]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge tag 'drm/panel/for-4.1-rc1' of git://anongit.freedesktop.org/tegra/linux into...
authorDave Airlie <airlied@redhat.com>
Wed, 8 Apr 2015 01:14:10 +0000 (11:14 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 8 Apr 2015 01:14:10 +0000 (11:14 +1000)
drm/panel: Changes for v4.1-rc1

This set of changes adds support for a whole bunch of new panels, mostly
simple ones. There's now also support for panels to provide display
timings rather than fixed modes, which should allow panels to work with
a larger number of display drivers. Eventually drivers should migrate to
this new interface and the fixed modes removed from panels.

There are also a couple of sparse fixes for the PS8622 and PS8625 bridge
drivers.

* tag 'drm/panel/for-4.1-rc1' of git://anongit.freedesktop.org/tegra/linux:
  drm/panel: Add support for Ampire AM-800480R3TMQW-A1H 800x480 7" panel
  of: Add vendor prefix for Ampire Co., Ltd.
  drm/panel: Add display timing for HannStar HSD070PWW1
  drm/panel: simple: Add display timing support
  drm/panel: Add display timing support
  drm/panel: Add support for OrtusTech COM43H4M85ULC panel
  of: Add vendor prefix for Ortus Technology Co., Ltd.
  drm/panel: Add bus format for Giantplus GPG482739QS5 panel
  drm/panel: simple: Add support for AUO b101ean01 panel
  drm/panel: simple: Add support for Innolux ZJ070NA-01P
  drm/panel: simple: Add support for Innolux AT043TN24
  drm/panel: simple: Add support for Shelly SCA07010-BFN-LNN
  drm/panel: simple: Add support for Samsung LTN140AT29 panel
  drm: Remove unused DRM_MODE_OBJECT_BRIDGE
  drm/bridge: ptn3460: Fix sparse warnings
  drm/bridge: ps8622: Fix sparse warnings
  drm/bridge: Add I2C based driver for ps8622/ps8625 bridge

1227 files changed:
Documentation/CodeOfConflict [new file with mode: 0644]
Documentation/DocBook/drm.tmpl
Documentation/cgroups/unified-hierarchy.txt
Documentation/devicetree/bindings/arm/exynos/power_domain.txt
Documentation/devicetree/bindings/arm/sti.txt
Documentation/devicetree/bindings/i2c/i2c-imx.txt
Documentation/devicetree/bindings/net/amd-xgbe-phy.txt
Documentation/devicetree/bindings/net/apm-xgene-enet.txt
Documentation/devicetree/bindings/power/power_domain.txt
Documentation/devicetree/bindings/serial/8250.txt [new file with mode: 0644]
Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt [new file with mode: 0644]
Documentation/devicetree/bindings/serial/of-serial.txt [deleted file]
Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
Documentation/devicetree/bindings/submitting-patches.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
Documentation/filesystems/dlmfs.txt
Documentation/filesystems/ocfs2.txt
Documentation/power/suspend-and-interrupts.txt
MAINTAINERS
Makefile
arch/arc/include/asm/processor.h
arch/arc/include/asm/stacktrace.h [new file with mode: 0644]
arch/arc/kernel/process.c
arch/arc/kernel/signal.c
arch/arc/kernel/stacktrace.c
arch/arc/kernel/unaligned.c
arch/arc/mm/fault.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/dts/am335x-bone-common.dtsi
arch/arm/boot/dts/am335x-bone.dts
arch/arm/boot/dts/am335x-lxm.dts
arch/arm/boot/dts/am33xx-clocks.dtsi
arch/arm/boot/dts/am437x-idk-evm.dts
arch/arm/boot/dts/am43xx-clocks.dtsi
arch/arm/boot/dts/am57xx-beagle-x15.dts
arch/arm/boot/dts/at91sam9260.dtsi
arch/arm/boot/dts/at91sam9261.dtsi
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9n12.dtsi
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/dm8168-evm.dts
arch/arm/boot/dts/dm816x.dtsi
arch/arm/boot/dts/dra7-evm.dts
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/dra72-evm.dts
arch/arm/boot/dts/dra7xx-clocks.dtsi
arch/arm/boot/dts/exynos3250.dtsi
arch/arm/boot/dts/exynos4-cpu-thermal.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos4.dtsi
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/exynos4212.dtsi
arch/arm/boot/dts/exynos4412-odroid-common.dtsi
arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos4412-trats2.dts
arch/arm/boot/dts/exynos4412.dtsi
arch/arm/boot/dts/exynos4x12.dtsi
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/exynos5420-trip-points.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos5420.dtsi
arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos5440-trip-points.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos5440.dtsi
arch/arm/boot/dts/imx6qdl-sabresd.dtsi
arch/arm/boot/dts/imx6sl-evk.dts
arch/arm/boot/dts/omap2.dtsi
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap5-core-thermal.dtsi
arch/arm/boot/dts/omap5-gpu-thermal.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/omap54xx-clocks.dtsi
arch/arm/boot/dts/rk3288.dtsi
arch/arm/boot/dts/sama5d3.dtsi
arch/arm/boot/dts/sama5d4.dtsi
arch/arm/boot/dts/socfpga.dtsi
arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
arch/arm/boot/dts/sun4i-a10.dtsi
arch/arm/boot/dts/sun5i-a13.dtsi
arch/arm/boot/dts/sun7i-a20.dtsi
arch/arm/configs/at91_dt_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/configs/sama5_defconfig
arch/arm/configs/sunxi_defconfig
arch/arm/configs/vexpress_defconfig
arch/arm/crypto/aesbs-core.S_shipped
arch/arm/crypto/bsaes-armv7.pl
arch/arm/include/asm/kvm_mmu.h
arch/arm/include/debug/at91.S
arch/arm/kernel/setup.c
arch/arm/kvm/arm.c
arch/arm/kvm/mmu.c
arch/arm/kvm/trace.h
arch/arm/mach-asm9260/Kconfig
arch/arm/mach-at91/pm.c
arch/arm/mach-at91/pm.h
arch/arm/mach-at91/pm_slowclock.S
arch/arm/mach-exynos/platsmp.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-exynos/suspend.c
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-msm/board-halibut.c
arch/arm/mach-msm/board-qsd8x50.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.h
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-pxa/idp.c
arch/arm/mach-pxa/irq.c
arch/arm/mach-pxa/lpd270.c
arch/arm/mach-pxa/zeus.c
arch/arm/mach-realview/core.c
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-sa1100/neponset.c
arch/arm/mach-sa1100/pleb.c
arch/arm/mach-socfpga/core.h
arch/arm/mach-socfpga/socfpga.c
arch/arm/mach-sti/board-dt.c
arch/arm/mach-sunxi/Kconfig
arch/arm/mm/cache-l2x0.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/fault.c
arch/arm/mm/pageattr.c
arch/arm/plat-omap/dmtimer.c
arch/arm64/boot/dts/apm/apm-storm.dtsi
arch/arm64/boot/dts/arm/foundation-v8.dts
arch/arm64/boot/dts/arm/juno-clocks.dtsi
arch/arm64/boot/dts/arm/juno.dts
arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts
arch/arm64/crypto/Makefile
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cmpxchg.h
arch/arm64/include/asm/cpuidle.h
arch/arm64/include/asm/insn.h
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/percpu.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/proc-fns.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/tlb.h
arch/arm64/include/asm/tlbflush.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/efi.c
arch/arm64/kernel/ftrace.c
arch/arm64/kernel/head.S
arch/arm64/kernel/insn.c
arch/arm64/kernel/process.c
arch/arm64/kernel/psci-call.S [new file with mode: 0644]
arch/arm64/kernel/psci.c
arch/arm64/kernel/signal32.c
arch/arm64/kernel/vdso/gettimeofday.S
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/init.c
arch/arm64/mm/pageattr.c
arch/c6x/include/asm/pgtable.h
arch/frv/include/asm/pgtable.h
arch/m32r/include/asm/pgtable-2level.h
arch/m68k/include/asm/pgtable_mm.h
arch/metag/include/asm/io.h
arch/metag/include/asm/pgtable-bits.h [new file with mode: 0644]
arch/metag/include/asm/pgtable.h
arch/metag/include/asm/processor.h
arch/microblaze/kernel/entry.S
arch/mips/kvm/tlb.c
arch/mips/kvm/trace.h
arch/mn10300/include/asm/pgtable.h
arch/nios2/include/asm/ptrace.h
arch/nios2/include/asm/ucontext.h [deleted file]
arch/nios2/include/uapi/asm/Kbuild
arch/nios2/include/uapi/asm/elf.h
arch/nios2/include/uapi/asm/ptrace.h
arch/nios2/include/uapi/asm/sigcontext.h
arch/nios2/kernel/signal.c
arch/nios2/mm/fault.c
arch/parisc/include/asm/pgalloc.h
arch/parisc/include/asm/pgtable.h
arch/parisc/kernel/syscall_table.S
arch/powerpc/include/asm/iommu.h
arch/powerpc/include/asm/irq_work.h [new file with mode: 0644]
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/reg.h
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dbell.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/smp.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/smp.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/mobility.c
arch/s390/include/asm/elf.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/page.h
arch/s390/include/asm/pgtable.h
arch/s390/kernel/ftrace.c
arch/s390/kernel/jump_label.c
arch/s390/kernel/module.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/processor.c
arch/s390/kernel/swsusp_asm64.S
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/priv.c
arch/s390/pci/pci.c
arch/s390/pci/pci_mmio.c
arch/sparc/Kconfig
arch/sparc/include/asm/hypervisor.h
arch/sparc/include/asm/io_64.h
arch/sparc/include/asm/starfire.h
arch/sparc/kernel/entry.h
arch/sparc/kernel/hvapi.c
arch/sparc/kernel/hvcalls.S
arch/sparc/kernel/pcr.c
arch/sparc/kernel/perf_event.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/starfire.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/traps_64.c
arch/sparc/lib/memmove.S
arch/sparc/mm/init_64.c
arch/x86/Kconfig
arch/x86/boot/compressed/aslr.c
arch/x86/boot/compressed/misc.c
arch/x86/boot/compressed/misc.h
arch/x86/crypto/aesni-intel_glue.c
arch/x86/include/asm/fpu-internal.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/xsave.h
arch/x86/include/uapi/asm/bootparam.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/apic_numachip.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/kprobes/opt.c
arch/x86/kernel/module.c
arch/x86/kernel/setup.c
arch/x86/kernel/traps.c
arch/x86/kernel/xsave.c
arch/x86/kvm/emulate.c
arch/x86/kvm/i8259.c
arch/x86/kvm/ioapic.c
arch/x86/kvm/lapic.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lguest/Kconfig
arch/x86/pci/acpi.c
arch/x86/pci/common.c
arch/x86/pci/intel_mid_pci.c
arch/x86/pci/irq.c
arch/x86/platform/intel-mid/intel-mid.c
arch/x86/vdso/vdso32/sigreturn.S
arch/x86/xen/enlighten.c
arch/x86/xen/p2m.c
block/blk-merge.c
block/blk-mq-tag.c
block/blk-mq.c
drivers/acpi/acpi_lpss.c
drivers/acpi/pci_irq.c
drivers/acpi/resource.c
drivers/acpi/video.c
drivers/android/binder.c
drivers/ata/libata-core.c
drivers/ata/sata_fsl.c
drivers/base/power/domain.c
drivers/base/power/wakeup.c
drivers/base/regmap/internal.h
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
drivers/block/nbd.c
drivers/block/nvme-core.c
drivers/block/zram/zram_drv.c
drivers/bluetooth/btusb.c
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm_ibmvtpm.c
drivers/char/tpm/tpm_ibmvtpm.h
drivers/char/virtio_console.c
drivers/clk/at91/pmc.c
drivers/clk/at91/pmc.h
drivers/clk/clk-divider.c
drivers/clk/clk.c
drivers/clk/qcom/gcc-msm8960.c
drivers/clk/qcom/lcc-ipq806x.c
drivers/clk/qcom/lcc-msm8960.c
drivers/clk/ti/fapll.c
drivers/clocksource/Kconfig
drivers/clocksource/mtk_timer.c
drivers/clocksource/pxa_timer.c
drivers/clocksource/time-efm32.c
drivers/clocksource/timer-sun5i.c
drivers/cpufreq/exynos-cpufreq.c
drivers/cpufreq/ppc-corenet-cpufreq.c
drivers/cpuidle/cpuidle-mvebu-v7.c
drivers/cpuidle/cpuidle.c
drivers/dma-buf/fence.c
drivers/dma-buf/reservation.c
drivers/dma/amba-pl08x.c
drivers/dma/at_hdmac.c
drivers/dma/at_hdmac_regs.h
drivers/dma/at_xdmac.c
drivers/dma/dw/core.c
drivers/dma/dw/platform.c
drivers/dma/imx-sdma.c
drivers/dma/ioat/dma_v3.c
drivers/dma/mmp_pdma.c
drivers/dma/mmp_tdma.c
drivers/dma/qcom_bam_dma.c
drivers/dma/sh/shdmac.c
drivers/firmware/dmi_scan.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/gpio/gpio-tps65912.c
drivers/gpio/gpiolib-of.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c
drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
drivers/gpu/drm/amd/amdkfd/kfd_module.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/amdkfd/kfd_process.c
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/include/kgd_kfd_interface.h
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
drivers/gpu/drm/bochs/bochs_hw.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_bridge.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_plane_helper.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos7_drm_decon.c
drivers/gpu/drm/exynos/exynos_drm_connector.c [deleted file]
drivers/gpu/drm/exynos/exynos_drm_connector.h [deleted file]
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/i2c/adv7511.c
drivers/gpu/drm/i2c/tda998x_drv.c
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_evict.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_gtt.h
drivers/gpu/drm/i915/i915_gem_shrinker.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/i915_trace.h
drivers/gpu/drm/i915/i915_ums.c [deleted file]
drivers/gpu/drm/i915/i915_vgpu.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_vgpu.h [new file with mode: 0644]
drivers/gpu/drm/i915/intel_atomic.c
drivers/gpu/drm/i915/intel_atomic_plane.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_bios.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dsi.c
drivers/gpu/drm/i915/intel_dsi_cmd.h [deleted file]
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_fifo_underrun.c
drivers/gpu/drm/i915/intel_frontbuffer.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_lrc.h
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_psr.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/imx/dw_hdmi-imx.c
drivers/gpu/drm/imx/imx-ldb.c
drivers/gpu/drm/imx/parallel-display.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.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_crtc.c
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_plane.c
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c
drivers/gpu/drm/omapdrm/omap_connector.c
drivers/gpu/drm/omapdrm/omap_crtc.c
drivers/gpu/drm/omapdrm/omap_dmm_priv.h
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
drivers/gpu/drm/omapdrm/omap_dmm_tiler.h
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/omapdrm/omap_drv.h
drivers/gpu/drm/omapdrm/omap_fb.c
drivers/gpu/drm/omapdrm/omap_fbdev.c
drivers/gpu/drm/omapdrm/omap_gem.c
drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
drivers/gpu/drm/omapdrm/omap_irq.c
drivers/gpu/drm/omapdrm/omap_plane.c
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/btc_dpm.c
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/dce6_afmt.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/ni_reg.h
drivers/gpu/drm/radeon/nid.h
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_dpm.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_audio.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_dp_auxch.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_dp_mst.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kfd.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs780_dpm.c
drivers/gpu/drm/radeon/rv6xx_dpm.c
drivers/gpu/drm/radeon/rv770_dpm.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/radeon/sumo_dpm.c
drivers/gpu/drm/radeon/trinity_dpm.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.h
drivers/gpu/drm/rcar-du/rcar_du_drv.c
drivers/gpu/drm/rcar-du/rcar_du_drv.h
drivers/gpu/drm/rcar-du/rcar_du_encoder.c
drivers/gpu/drm/rcar-du/rcar_du_group.h
drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
drivers/gpu/drm/rcar-du/rcar_du_plane.c
drivers/gpu/drm/rcar-du/rcar_du_plane.h
drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.h
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/sti/sti_drm_crtc.c
drivers/gpu/drm/sti/sti_drm_drv.c
drivers/gpu/drm/sti/sti_drm_drv.h
drivers/gpu/drm/sti/sti_drm_plane.c
drivers/gpu/drm/sti/sti_dvo.c
drivers/gpu/drm/sti/sti_hda.c
drivers/gpu/drm/sti/sti_hdmi.c
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/dc.h
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/hdmi.c
drivers/gpu/drm/tegra/hdmi.h
drivers/gpu/drm/tegra/sor.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/vgem/Makefile [new file with mode: 0644]
drivers/gpu/drm/vgem/vgem_dma_buf.c [new file with mode: 0644]
drivers/gpu/drm/vgem/vgem_drv.c [new file with mode: 0644]
drivers/gpu/drm/vgem/vgem_drv.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/host1x/syncpt.c
drivers/gpu/ipu-v3/ipu-di.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-microsoft.c
drivers/hid/hid-saitek.c
drivers/hid/hid-sensor-hub.c
drivers/hid/hid-sony.c
drivers/hid/hid-tivo.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_wac.c
drivers/hwmon/ads7828.c
drivers/i2c/busses/i2c-designware-baytrail.c
drivers/i2c/i2c-core.c
drivers/ide/ide-tape.c
drivers/iio/adc/mcp3422.c
drivers/iio/adc/qcom-spmi-iadc.c
drivers/iio/common/ssp_sensors/ssp_dev.c
drivers/iio/dac/ad5686.c
drivers/iio/humidity/dht11.c
drivers/iio/humidity/si7020.c
drivers/iio/imu/adis16400_core.c
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
drivers/iio/light/Kconfig
drivers/iio/magnetometer/Kconfig
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/input/keyboard/tc3589x-keypad.c
drivers/input/misc/mma8450.c
drivers/input/mouse/alps.c
drivers/input/mouse/cyapa_gen3.c
drivers/input/mouse/cyapa_gen5.c
drivers/input/mouse/focaltech.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse.h
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.h
drivers/input/touchscreen/Kconfig
drivers/iommu/Kconfig
drivers/iommu/exynos-iommu.c
drivers/iommu/io-pgtable-arm.c
drivers/iommu/omap-iommu.c
drivers/iommu/rockchip-iommu.c
drivers/irqchip/irq-armada-370-xp.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic.c
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/isdn/icn/icn.c
drivers/md/dm-io.c
drivers/md/dm-snap.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid5.c
drivers/mfd/kempld-core.c
drivers/mfd/rtsx_usb.c
drivers/misc/mei/init.c
drivers/mmc/core/pwrseq_simple.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/ubi/eba.c
drivers/net/Kconfig
drivers/net/appletalk/Kconfig
drivers/net/can/Kconfig
drivers/net/can/dev.c
drivers/net/can/usb/kvaser_usb.c
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
drivers/net/dsa/bcm_sf2.h
drivers/net/ethernet/8390/axnet_cs.c
drivers/net/ethernet/8390/pcnet_cs.c
drivers/net/ethernet/altera/altera_tse_main.c
drivers/net/ethernet/amd/pcnet32.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bcmsysport.h
drivers/net/ethernet/broadcom/bgmac.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/genet/bcmgenet.h
drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/dec/tulip/tulip_core.c
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_nvm.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.h
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_selftest.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/qp.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/pasemi/pasemi_mac.c
drivers/net/ethernet/qlogic/netxen/netxen_nic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/rocker/rocker.c
drivers/net/ethernet/smsc/smc91c92_cs.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/smsc/smc91x.h
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/davinci_mdio.c
drivers/net/ethernet/wiznet/w5100.c
drivers/net/ethernet/wiznet/w5300.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/macvtap.c
drivers/net/phy/amd-xgbe-phy.c
drivers/net/phy/phy.c
drivers/net/team/team.c
drivers/net/usb/Kconfig
drivers/net/usb/asix_devices.c
drivers/net/usb/cx82310_eth.c
drivers/net/usb/hso.c
drivers/net/usb/plusb.c
drivers/net/virtio_net.c
drivers/net/vxlan.c
drivers/net/wan/cosa.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/brcm80211/brcmfmac/vendor.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/of/Kconfig
drivers/of/base.c
drivers/of/irq.c
drivers/of/overlay.c
drivers/of/unittest.c
drivers/pci/host/pci-versatile.c
drivers/pci/host/pci-xgene.c
drivers/pci/pci-sysfs.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/rsrc_pci.c [deleted file]
drivers/phy/phy-armada375-usb2.c
drivers/phy/phy-core.c
drivers/phy/phy-exynos-dp-video.c
drivers/phy/phy-exynos-mipi-video.c
drivers/phy/phy-exynos4210-usb2.c
drivers/phy/phy-exynos4x12-usb2.c
drivers/phy/phy-exynos5-usbdrd.c
drivers/phy/phy-exynos5250-usb2.c
drivers/phy/phy-hix5hd2-sata.c
drivers/phy/phy-miphy28lp.c
drivers/phy/phy-miphy365x.c
drivers/phy/phy-omap-control.c
drivers/phy/phy-omap-usb2.c
drivers/phy/phy-rockchip-usb.c
drivers/phy/phy-ti-pipe3.c
drivers/phy/phy-twl4030-usb.c
drivers/phy/phy-xgene.c
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/pinctrl/sunxi/pinctrl-sunxi.h
drivers/powercap/intel_rapl.c
drivers/regulator/core.c
drivers/regulator/da9210-regulator.c
drivers/regulator/palmas-regulator.c
drivers/regulator/rk808-regulator.c
drivers/regulator/tps65910-regulator.c
drivers/rpmsg/virtio_rpmsg_bus.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-ds1685.c
drivers/rtc/rtc-mrst.c
drivers/rtc/rtc-s3c.c
drivers/s390/block/dcssblk.c
drivers/s390/block/scm_blk_cluster.c
drivers/scsi/ipr.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/libsas/sas_discover.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/sh/pm_runtime.c
drivers/spi/spi-atmel.c
drivers/spi/spi-dw-mid.c
drivers/spi/spi-dw-pci.c
drivers/spi/spi-dw.c
drivers/spi/spi-img-spfi.c
drivers/spi/spi-pl022.c
drivers/spi/spi-qup.c
drivers/spi/spi-ti-qspi.c
drivers/spi/spi.c
drivers/staging/comedi/drivers/adv_pci1710.c
drivers/staging/comedi/drivers/comedi_isadma.c
drivers/staging/comedi/drivers/vmk80xx.c
drivers/staging/iio/adc/mxs-lradc.c
drivers/staging/iio/resolver/ad2s1200.c
drivers/staging/vt6655/device_main.c
drivers/staging/vt6655/rf.c
drivers/staging/vt6656/rf.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_erl0.c
drivers/target/loopback/tcm_loop.c
drivers/target/target_core_device.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tfc_io.c
drivers/thermal/int340x_thermal/int3400_thermal.c
drivers/thermal/int340x_thermal/int340x_thermal_zone.c
drivers/thermal/intel_powerclamp.c
drivers/thermal/rcar_thermal.c
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/thermal_core.c
drivers/thermal/ti-soc-thermal/ti-bandgap.c
drivers/thermal/ti-soc-thermal/ti-thermal-common.c
drivers/tty/bfin_jtag_comm.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/of_serial.c
drivers/tty/serial/sprd_serial.c
drivers/tty/tty_io.c
drivers/tty/tty_ioctl.c
drivers/usb/chipidea/udc.c
drivers/usb/class/cdc-acm.c
drivers/usb/common/usb-otg-fsm.c
drivers/usb/core/devio.c
drivers/usb/dwc2/core_intr.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_hid.c
drivers/usb/gadget/function/f_loopback.c
drivers/usb/gadget/function/f_phonet.c
drivers/usb/gadget/function/f_sourcesink.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/g_zero.h
drivers/usb/gadget/function/uvc_v4l2.c
drivers/usb/gadget/function/uvc_video.c
drivers/usb/gadget/legacy/g_ffs.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/gadget/legacy/tcm_usb_gadget.c
drivers/usb/gadget/legacy/zero.c
drivers/usb/host/ehci-atmel.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h
drivers/usb/isp1760/isp1760-core.c
drivers/usb/isp1760/isp1760-hcd.c
drivers/usb/isp1760/isp1760-udc.c
drivers/usb/musb/Kconfig
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/omap2430.c
drivers/usb/phy/phy-am335x-control.c
drivers/usb/renesas_usbhs/Kconfig
drivers/usb/serial/bus.c
drivers/usb/serial/ch341.c
drivers/usb/serial/console.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/generic.c
drivers/usb/serial/mxuport.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/usb-serial.c
drivers/usb/storage/unusual_uas.h
drivers/usb/storage/usb.c
drivers/vfio/pci/vfio_pci_intrs.c
drivers/vhost/net.c
drivers/vhost/scsi.c
drivers/video/fbdev/amba-clcd.c
drivers/video/fbdev/core/fbmon.c
drivers/video/fbdev/omap2/dss/display-sysfs.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_mmio.c
drivers/watchdog/at91sam9_wdt.c
drivers/watchdog/imgpdc_wdt.c
drivers/watchdog/mtk_wdt.c
drivers/xen/Makefile
drivers/xen/events/events_base.c
drivers/xen/preempt.c [new file with mode: 0644]
drivers/xen/privcmd.c
drivers/xen/xen-pciback/conf_space.c
drivers/xen/xen-pciback/conf_space.h
drivers/xen/xen-pciback/conf_space_header.c
drivers/xen/xen-scsiback.c
fs/affs/file.c
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ordered-data.c
fs/btrfs/qgroup.c
fs/btrfs/send.c
fs/btrfs/tests/inode-tests.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/xattr.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/keystore.c
fs/ecryptfs/main.c
fs/fuse/dev.c
fs/hfsplus/brec.c
fs/kernfs/file.c
fs/locks.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4session.h
fs/nfs/nfs4state.c
fs/nfs/proc.c
fs/nfs/write.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4state.c
fs/nilfs2/btree.c
fs/nilfs2/segment.c
fs/notify/fanotify/fanotify.c
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_fs.h
fs/overlayfs/super.c
fs/proc/task_mmu.c
fs/xfs/xfs_file.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_iops.c
fs/xfs/xfs_pnfs.c
fs/xfs/xfs_qm.c
include/drm/drmP.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_dp_mst_helper.h
include/drm/drm_fb_helper.h
include/drm/drm_mm.h
include/drm/drm_modes.h
include/drm/drm_plane_helper.h
include/drm/i915_pciids.h
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/dt-bindings/pinctrl/am33xx.h
include/dt-bindings/pinctrl/am43xx.h
include/kvm/arm_vgic.h
include/linux/clk.h
include/linux/cpuidle.h
include/linux/device-mapper.h
include/linux/hid-sensor-hub.h
include/linux/host1x.h
include/linux/interrupt.h
include/linux/irqchip/arm-gic-v3.h
include/linux/irqdesc.h
include/linux/kasan.h
include/linux/libata.h
include/linux/mfd/palmas.h
include/linux/mlx4/qp.h
include/linux/module.h
include/linux/moduleloader.h
include/linux/netdevice.h
include/linux/nfs_fs.h
include/linux/of_platform.h
include/linux/pinctrl/consumer.h
include/linux/regulator/driver.h
include/linux/rhashtable.h
include/linux/sched.h
include/linux/serial_core.h
include/linux/skbuff.h
include/linux/spi/spi.h
include/linux/thermal.h
include/linux/uio.h
include/linux/usb/serial.h
include/linux/vmalloc.h
include/linux/workqueue.h
include/net/caif/cfpkt.h
include/net/dst.h
include/net/netfilter/nf_log.h
include/net/netfilter/nf_tables.h
include/net/vxlan.h
include/soc/at91/at91sam9_ddrsdr.h
include/target/target_core_backend.h
include/trace/events/regmap.h
include/uapi/drm/drm.h
include/uapi/drm/drm_fourcc.h
include/uapi/drm/drm_mode.h
include/uapi/drm/i915_drm.h
include/uapi/drm/radeon_drm.h
include/uapi/drm/tegra_drm.h
include/uapi/linux/serial.h
include/uapi/linux/tc_act/Kbuild
include/uapi/linux/virtio_blk.h
include/uapi/linux/virtio_scsi.h
include/video/omapdss.h
include/xen/xen-ops.h
include/xen/xenbus.h
kernel/cpuset.c
kernel/events/core.c
kernel/irq/manage.c
kernel/irq/pm.c
kernel/livepatch/core.c
kernel/locking/lockdep.c
kernel/locking/rtmutex.c
kernel/module.c
kernel/printk/console_cmdline.h
kernel/printk/printk.c
kernel/sched/core.c
kernel/sched/fair.c
kernel/sched/idle.c
kernel/sys.c
kernel/time/tick-broadcast-hrtimer.c
kernel/trace/ftrace.c
kernel/workqueue.c
lib/Makefile
lib/iov_iter.c [new file with mode: 0644]
lib/lz4/lz4_decompress.c
lib/rhashtable.c
lib/seq_buf.c
lib/test_rhashtable.c
mm/Makefile
mm/cma.c
mm/huge_memory.c
mm/hugetlb.c
mm/iov_iter.c [deleted file]
mm/kasan/kasan.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/mlock.c
mm/mmap.c
mm/mprotect.c
mm/nommu.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_isolation.c
mm/pagewalk.c
mm/rmap.c
mm/shmem.c
mm/slub.c
mm/vmalloc.c
net/9p/trans_virtio.c
net/bridge/br.c
net/bridge/br_if.c
net/caif/caif_socket.c
net/caif/cffrml.c
net/caif/cfpkt_skbuff.c
net/can/af_can.c
net/compat.c
net/core/dev.c
net/core/ethtool.c
net/core/gen_stats.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/decnet/dn_route.c
net/hsr/hsr_device.c
net/hsr/hsr_main.c
net/hsr/hsr_slave.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/ip_forward.c
net/ipv4/ip_fragment.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/ping.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_cubic.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv4/xfrm4_output.c
net/ipv6/addrconf.c
net/ipv6/datagram.c
net/ipv6/fib6_rules.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/ping.c
net/ipv6/udp_offload.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_policy.c
net/irda/ircomm/ircomm_tty.c
net/irda/irnet/irnet_ppp.c
net/mac80211/chan.c
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rx.c
net/mac80211/tx.c
net/mac80211/util.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/nf_log.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netfilter/nfnetlink_cthelper.c
net/netfilter/nft_compat.c
net/netfilter/nft_hash.c
net/netfilter/xt_TPROXY.c
net/netfilter/xt_recent.c
net/netfilter/xt_socket.c
net/netlink/af_netlink.c
net/openvswitch/datapath.c
net/openvswitch/flow_netlink.c
net/openvswitch/vport.h
net/packet/af_packet.c
net/rds/iw_rdma.c
net/rxrpc/ar-ack.c
net/rxrpc/ar-error.c
net/rxrpc/ar-recvmsg.c
net/sched/act_bpf.c
net/sched/cls_u32.c
net/sched/ematch.c
net/socket.c
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/xprt_rdma.h
net/tipc/link.c
net/tipc/socket.c
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/reg.c
net/xfrm/xfrm_policy.c
scripts/gdb/linux/__init__.py [new file with mode: 0644]
security/selinux/selinuxfs.c
sound/core/control.c
sound/core/pcm_native.c
sound/drivers/opl3/opl3_midi.c
sound/firewire/amdtp.c
sound/firewire/bebob/bebob.c
sound/firewire/bebob/bebob_stream.c
sound/firewire/dice/dice-stream.c
sound/firewire/dice/dice.c
sound/firewire/fireworks/fireworks.c
sound/firewire/fireworks/fireworks_stream.c
sound/firewire/iso-resources.c
sound/firewire/oxfw/oxfw-stream.c
sound/firewire/oxfw/oxfw.c
sound/isa/msnd/msnd_pinnacle_mixer.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/cirrus/Kconfig
sound/soc/codecs/Kconfig
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/da732x.c
sound/soc/codecs/es8328.c
sound/soc/codecs/max98357a.c
sound/soc/codecs/pcm1681.c
sound/soc/codecs/rt286.c
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5677.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sn95031.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/tas5086.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/generic/simple-card.c
sound/soc/intel/sst-atom-controls.h
sound/soc/intel/sst-haswell-dsp.c
sound/soc/intel/sst-haswell-ipc.c
sound/soc/intel/sst/sst.c
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/omap/omap-hdmi-audio.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-pcm.c
sound/soc/samsung/Kconfig
sound/soc/sh/rcar/core.c
sound/soc/soc-core.c
sound/usb/line6/playback.c
sound/usb/quirks-table.h
tools/perf/bench/mem-memcpy.c
tools/perf/config/Makefile.arch
tools/perf/config/feature-checks/Makefile
tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c
tools/perf/util/annotate.c
tools/perf/util/cloexec.c
tools/perf/util/evlist.h
tools/perf/util/symbol-elf.c
tools/power/cpupower/Makefile
tools/testing/selftests/Makefile
tools/testing/selftests/exec/execveat.c
tools/thermal/tmon/.gitignore [new file with mode: 0644]
tools/thermal/tmon/Makefile
tools/thermal/tmon/tmon.8
tools/thermal/tmon/tmon.c
tools/thermal/tmon/tui.c
virt/kvm/arm/vgic-v2.c
virt/kvm/arm/vgic-v3.c
virt/kvm/arm/vgic.c
virt/kvm/kvm_main.c

diff --git a/Documentation/CodeOfConflict b/Documentation/CodeOfConflict
new file mode 100644 (file)
index 0000000..1684d0b
--- /dev/null
@@ -0,0 +1,27 @@
+Code of Conflict
+----------------
+
+The Linux kernel development effort is a very personal process compared
+to "traditional" ways of developing software.  Your code and ideas
+behind it will be carefully reviewed, often resulting in critique and
+criticism.  The review will almost always require improvements to the
+code before it can be included in the kernel.  Know that this happens
+because everyone involved wants to see the best possible solution for
+the overall success of Linux.  This development process has been proven
+to create the most robust operating system kernel ever, and we do not
+want to do anything to cause the quality of submission and eventual
+result to ever decrease.
+
+If however, anyone feels personally abused, threatened, or otherwise
+uncomfortable due to this process, that is not acceptable.  If so,
+please contact the Linux Foundation's Technical Advisory Board at
+<tab@lists.linux-foundation.org>, or the individual members, and they
+will work to resolve the issue to the best of their ability.  For more
+information on who is on the Technical Advisory Board and what their
+role is, please see:
+       http://www.linuxfoundation.org/programs/advisory-councils/tab
+
+As a reviewer of code, please strive to keep things civil and focused on
+the technical issues involved.  We are all humans, and frustrations can
+be high on both sides of the process.  Try to keep in mind the immortal
+words of Bill and Ted, "Be excellent to each other."
index 03f1985a4bd1876d7b3e78d70b0c6939ef709eab..f4976cd7b32bac2c3b91983caa2872495812e8cf 100644 (file)
@@ -3979,6 +3979,11 @@ int num_ioctls;</synopsis>
 !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>
+      <sect2>
+        <title>Intel GVT-g Guest Support(vGPU)</title>
+!Pdrivers/gpu/drm/i915/i915_vgpu.c Intel GVT-g guest support
+!Idrivers/gpu/drm/i915/i915_vgpu.c
+      </sect2>
     </sect1>
     <sect1>
       <title>Display Hardware Handling</title>
@@ -4046,6 +4051,17 @@ int num_ioctls;</synopsis>
        <title>Frame Buffer Compression (FBC)</title>
 !Pdrivers/gpu/drm/i915/intel_fbc.c Frame Buffer Compression (FBC)
 !Idrivers/gpu/drm/i915/intel_fbc.c
+      </sect2>
+      <sect2>
+        <title>Display Refresh Rate Switching (DRRS)</title>
+!Pdrivers/gpu/drm/i915/intel_dp.c Display Refresh Rate Switching (DRRS)
+!Fdrivers/gpu/drm/i915/intel_dp.c intel_dp_set_drrs_state
+!Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_enable
+!Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_disable
+!Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_invalidate
+!Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_flush
+!Fdrivers/gpu/drm/i915/intel_dp.c intel_dp_drrs_init
+
       </sect2>
       <sect2>
         <title>DPIO</title>
@@ -4168,7 +4184,7 @@ int num_ioctls;</synopsis>
       <sect2>
         <title>Buffer Object Eviction</title>
        <para>
-         This section documents the interface function for evicting buffer
+         This section documents the interface functions for evicting buffer
          objects to make space available in the virtual gpu address spaces.
          Note that this is mostly orthogonal to shrinking buffer objects
          caches, which has the goal to make main memory (shared with the gpu
@@ -4176,6 +4192,17 @@ int num_ioctls;</synopsis>
        </para>
 !Idrivers/gpu/drm/i915/i915_gem_evict.c
       </sect2>
+      <sect2>
+        <title>Buffer Object Memory Shrinking</title>
+       <para>
+         This section documents the interface function for shrinking memory
+         usage of buffer object caches. Shrinking is used to make main memory
+         available.  Note that this is mostly orthogonal to evicting buffer
+         objects, which has the goal to make space in gpu virtual address
+         spaces.
+       </para>
+!Idrivers/gpu/drm/i915/i915_gem_shrinker.c
+      </sect2>
     </sect1>
 
     <sect1>
index 71daa35ec2d9201d2a4647e0a088af3ab36bbae3..eb102fb722134758a39d7d2e17c1dd00fdc0d799 100644 (file)
@@ -404,8 +404,8 @@ supported and the interface files "release_agent" and
   be understood as an underflow into the highest possible value, -2 or
   -10M etc. do not work, so it's not consistent.
 
-  memory.low, memory.high, and memory.max will use the string
-  "infinity" to indicate and set the highest possible value.
+  memory.low, memory.high, and memory.max will use the string "max" to
+  indicate and set the highest possible value.
 
 5. Planned Changes
 
index f4445e5a2bbb7db23a7c32075f2efb5dbb9dec8d..1e097037349c326a22e3f07abb3e3aca9d78d0ce 100644 (file)
@@ -22,6 +22,8 @@ Optional Properties:
        - pclkN, clkN: Pairs of parent of input clock and input clock to the
                devices in this power domain. Maximum of 4 pairs (N = 0 to 3)
                are supported currently.
+- power-domains: phandle pointing to the parent power domain, for more details
+                see Documentation/devicetree/bindings/power/power_domain.txt
 
 Node of a device using power domains must have a power-domains property
 defined with a phandle to respective power domain.
index d70ec358736c48f376020183869d5b582bf81bed..8d27f6b084c7bfd07fda2ffce59c18e9a76390f2 100644 (file)
@@ -13,6 +13,10 @@ Boards with the ST STiH407 SoC shall have the following properties:
 Required root node property:
 compatible = "st,stih407";
 
+Boards with the ST STiH410 SoC shall have the following properties:
+Required root node property:
+compatible = "st,stih410";
+
 Boards with the ST STiH418 SoC shall have the following properties:
 Required root node property:
 compatible = "st,stih418";
index 52d37fd8d3e5c151471a70fb45ff2d4a09317a18..ce4311d726ae5e4a414e6240cc8832e876a9c24e 100644 (file)
@@ -7,6 +7,7 @@ Required properties:
   - "fsl,vf610-i2c" for I2C compatible with the one integrated on Vybrid vf610 SoC
 - reg : Should contain I2C/HS-I2C registers location and length
 - interrupts : Should contain I2C/HS-I2C interrupt
+- clocks : Should contain the I2C/HS-I2C clock specifier
 
 Optional properties:
 - clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
index 33df3932168e1b8941a5de1565b1cf02f96fb551..8db32384a4866e56094aa96e86ac8765ccdf519c 100644 (file)
@@ -27,6 +27,8 @@ property is used.
 - amd,serdes-cdr-rate: CDR rate speed selection
 - amd,serdes-pq-skew: PQ (data sampling) skew
 - amd,serdes-tx-amp: TX amplitude boost
+- amd,serdes-dfe-tap-config: DFE taps available to run
+- amd,serdes-dfe-tap-enable: DFE taps to enable
 
 Example:
        xgbe_phy@e1240800 {
@@ -41,4 +43,6 @@ Example:
                amd,serdes-cdr-rate = <2>, <2>, <7>;
                amd,serdes-pq-skew = <10>, <10>, <30>;
                amd,serdes-tx-amp = <15>, <15>, <10>;
+               amd,serdes-dfe-tap-config = <3>, <3>, <1>;
+               amd,serdes-dfe-tap-enable = <0>, <0>, <127>;
        };
index cfcc52705ed8093ba11b4f549dd1b02a8949fb40..6151999c5dcae6e31f60dc155b433723550cf693 100644 (file)
@@ -4,7 +4,10 @@ Ethernet nodes are defined to describe on-chip ethernet interfaces in
 APM X-Gene SoC.
 
 Required properties for all the ethernet interfaces:
-- compatible: Should be "apm,xgene-enet"
+- compatible: Should state binding information from the following list,
+  - "apm,xgene-enet":    RGMII based 1G interface
+  - "apm,xgene1-sgenet": SGMII based 1G interface
+  - "apm,xgene1-xgenet": XFI based 10G interface
 - reg: Address and length of the register set for the device. It contains the
   information of registers in the same order as described by reg-names
 - reg-names: Should contain the register set names
index 98c16672ab5f49e06cd6dd516f3c1a302e65beec..0f8ed3710c66e9e24450a77ba1d86fd9d2a01ea3 100644 (file)
@@ -19,6 +19,16 @@ Required properties:
    providing multiple PM domains (e.g. power controllers), but can be any value
    as specified by device tree binding documentation of particular provider.
 
+Optional properties:
+ - power-domains : A phandle and PM domain specifier as defined by bindings of
+                   the power controller specified by phandle.
+   Some power domains might be powered from another power domain (or have
+   other hardware specific dependencies). For representing such dependency
+   a standard PM domain consumer binding is used. When provided, all domains
+   created by the given provider should be subdomains of the domain
+   specified by this binding. More details about power domain specifier are
+   available in the next section.
+
 Example:
 
        power: power-controller@12340000 {
@@ -30,6 +40,25 @@ Example:
 The node above defines a power controller that is a PM domain provider and
 expects one cell as its phandle argument.
 
+Example 2:
+
+       parent: power-controller@12340000 {
+               compatible = "foo,power-controller";
+               reg = <0x12340000 0x1000>;
+               #power-domain-cells = <1>;
+       };
+
+       child: power-controller@12340000 {
+               compatible = "foo,power-controller";
+               reg = <0x12341000 0x1000>;
+               power-domains = <&parent 0>;
+               #power-domain-cells = <1>;
+       };
+
+The nodes above define two power controllers: 'parent' and 'child'.
+Domains created by the 'child' power controller are subdomains of '0' power
+domain provided by the 'parent' power controller.
+
 ==PM domain consumers==
 
 Required properties:
diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt
new file mode 100644 (file)
index 0000000..91d5ab0
--- /dev/null
@@ -0,0 +1,66 @@
+* UART (Universal Asynchronous Receiver/Transmitter)
+
+Required properties:
+- compatible : one of:
+       - "ns8250"
+       - "ns16450"
+       - "ns16550a"
+       - "ns16550"
+       - "ns16750"
+       - "ns16850"
+       - For Tegra20, must contain "nvidia,tegra20-uart"
+       - For other Tegra, must contain '"nvidia,<chip>-uart",
+         "nvidia,tegra20-uart"' where <chip> is tegra30, tegra114, tegra124,
+         tegra132, or tegra210.
+       - "nxp,lpc3220-uart"
+       - "ralink,rt2880-uart"
+       - "ibm,qpace-nwp-serial"
+       - "altr,16550-FIFO32"
+       - "altr,16550-FIFO64"
+       - "altr,16550-FIFO128"
+       - "fsl,16550-FIFO64"
+       - "fsl,ns16550"
+       - "serial" if the port type is unknown.
+- reg : offset and length of the register set for the device.
+- interrupts : should contain uart interrupt.
+- clock-frequency : the input clock frequency for the UART
+        or
+  clocks phandle to refer to the clk used as per Documentation/devicetree
+  /bindings/clock/clock-bindings.txt
+
+Optional properties:
+- current-speed : the current active speed of the UART.
+- reg-offset : offset to apply to the mapbase from the start of the registers.
+- reg-shift : quantity to shift the register offsets by.
+- reg-io-width : the size (in bytes) of the IO accesses that should be
+  performed on the device.  There are some systems that require 32-bit
+  accesses to the UART (e.g. TI davinci).
+- used-by-rtas : set to indicate that the port is in use by the OpenFirmware
+  RTAS and should not be registered.
+- no-loopback-test: set to indicate that the port does not implements loopback
+  test mode
+- fifo-size: the fifo size of the UART.
+- auto-flow-control: one way to enable automatic flow control support. The
+  driver is allowed to detect support for the capability even without this
+  property.
+
+Note:
+* fsl,ns16550:
+  ------------
+  Freescale DUART is very similar to the PC16552D (and to a
+  pair of NS16550A), albeit with some nonstandard behavior such as
+  erratum A-004737 (relating to incorrect BRK handling).
+
+  Represents a single port that is compatible with the DUART found
+  on many Freescale chips (examples include mpc8349, mpc8548,
+  mpc8641d, p4080 and ls2085a).
+
+Example:
+
+       uart@80230000 {
+               compatible = "ns8250";
+               reg = <0x80230000 0x100>;
+               clock-frequency = <3686400>;
+               interrupts = <10>;
+               reg-shift = <2>;
+       };
diff --git a/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt b/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt
new file mode 100644 (file)
index 0000000..ebcbb62
--- /dev/null
@@ -0,0 +1,19 @@
+ETRAX FS UART
+
+Required properties:
+- compatible : "axis,etraxfs-uart"
+- reg: offset and length of the register set for the device.
+- interrupts: device interrupt
+
+Optional properties:
+- {dtr,dsr,ri,cd}-gpios: specify a GPIO for DTR/DSR/RI/CD
+  line respectively.
+
+Example:
+
+serial@b00260000 {
+       compatible = "axis,etraxfs-uart";
+       reg = <0xb0026000 0x1000>;
+       interrupts = <68>;
+       status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/serial/of-serial.txt b/Documentation/devicetree/bindings/serial/of-serial.txt
deleted file mode 100644 (file)
index 91d5ab0..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-* UART (Universal Asynchronous Receiver/Transmitter)
-
-Required properties:
-- compatible : one of:
-       - "ns8250"
-       - "ns16450"
-       - "ns16550a"
-       - "ns16550"
-       - "ns16750"
-       - "ns16850"
-       - For Tegra20, must contain "nvidia,tegra20-uart"
-       - For other Tegra, must contain '"nvidia,<chip>-uart",
-         "nvidia,tegra20-uart"' where <chip> is tegra30, tegra114, tegra124,
-         tegra132, or tegra210.
-       - "nxp,lpc3220-uart"
-       - "ralink,rt2880-uart"
-       - "ibm,qpace-nwp-serial"
-       - "altr,16550-FIFO32"
-       - "altr,16550-FIFO64"
-       - "altr,16550-FIFO128"
-       - "fsl,16550-FIFO64"
-       - "fsl,ns16550"
-       - "serial" if the port type is unknown.
-- reg : offset and length of the register set for the device.
-- interrupts : should contain uart interrupt.
-- clock-frequency : the input clock frequency for the UART
-        or
-  clocks phandle to refer to the clk used as per Documentation/devicetree
-  /bindings/clock/clock-bindings.txt
-
-Optional properties:
-- current-speed : the current active speed of the UART.
-- reg-offset : offset to apply to the mapbase from the start of the registers.
-- reg-shift : quantity to shift the register offsets by.
-- reg-io-width : the size (in bytes) of the IO accesses that should be
-  performed on the device.  There are some systems that require 32-bit
-  accesses to the UART (e.g. TI davinci).
-- used-by-rtas : set to indicate that the port is in use by the OpenFirmware
-  RTAS and should not be registered.
-- no-loopback-test: set to indicate that the port does not implements loopback
-  test mode
-- fifo-size: the fifo size of the UART.
-- auto-flow-control: one way to enable automatic flow control support. The
-  driver is allowed to detect support for the capability even without this
-  property.
-
-Note:
-* fsl,ns16550:
-  ------------
-  Freescale DUART is very similar to the PC16552D (and to a
-  pair of NS16550A), albeit with some nonstandard behavior such as
-  erratum A-004737 (relating to incorrect BRK handling).
-
-  Represents a single port that is compatible with the DUART found
-  on many Freescale chips (examples include mpc8349, mpc8548,
-  mpc8641d, p4080 and ls2085a).
-
-Example:
-
-       uart@80230000 {
-               compatible = "ns8250";
-               reg = <0x80230000 0x100>;
-               clock-frequency = <3686400>;
-               interrupts = <10>;
-               reg-shift = <2>;
-       };
index 7f76214f728aa6028f133a94d04f183ccb3b1c38..289c40ed747042a70b13f9912dc0b5c443f7827e 100644 (file)
@@ -21,6 +21,18 @@ Optional properties:
 - reg-io-width : the size (in bytes) of the IO accesses that should be
   performed on the device.  If this property is not present then single byte
   accesses are used.
+- dcd-override : Override the DCD modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- dsr-override : Override the DTS modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- cts-override : Override the CTS modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- ri-override : Override the RI modem status signal. This signal will always be
+  reported as inactive instead of being obtained from the modem status register.
+  Define this if your serial port does not use this pin.
 
 Example:
 
@@ -31,6 +43,10 @@ Example:
                interrupts = <10>;
                reg-shift = <2>;
                reg-io-width = <4>;
+               dcd-override;
+               dsr-override;
+               cts-override;
+               ri-override;
        };
 
 Example with one clock:
index 56742bc70218bfd5d4035732301f1df6c6f4927e..7d44eae7ab0b951d2ea77889cee1c6733978dd0b 100644 (file)
@@ -12,6 +12,9 @@ I. For patch submitters
 
        devicetree@vger.kernel.org
 
+     and Cc: the DT maintainers. Use scripts/get_maintainer.pl to identify
+     all of the DT maintainers.
+
   3) The Documentation/ portion of the patch should come in the series before
      the code implementing the binding.
 
index ef29e0c301b28e7c1a93e4d62311dc4f582806dd..772b24f8638814a7398abdcb374eb11a04c4a237 100644 (file)
@@ -21,6 +21,7 @@ ampire        Ampire Co., Ltd.
 ams    AMS AG
 amstaos        AMS-Taos Inc.
 apm    Applied Micro Circuits Corporation (APM)
+arasan Arasan Chip Systems
 arm    ARM Ltd.
 armadeus       ARMadeus Systems SARL
 asahi-kasei    Asahi Kasei Corp.
@@ -28,6 +29,7 @@ atmel Atmel Corporation
 auo    AU Optronics Corporation
 avago  Avago Technologies
 avic   Shanghai AVIC Optoelectronics Co., Ltd.
+axis   Axis Communications AB
 bosch  Bosch Sensortec GmbH
 brcm   Broadcom Corporation
 buffalo        Buffalo, Inc.
index f90e294d7631f9b538ba3e5e72c2ab1b096a5479..a4d869744f5958f7bd0311868ef3c7b1c3956386 100644 (file)
@@ -26,6 +26,11 @@ Optional properties:
 - atmel,disable : Should be present if you want to disable the watchdog.
 - atmel,idle-halt : Should be present if you want to stop the watchdog when
        entering idle state.
+       CAUTION: This property should be used with care, it actually makes the
+       watchdog not counting when the CPU is in idle state, therefore the
+       watchdog reset time depends on mean CPU usage and will not reset at all
+       if the CPU stop working while it is in idle state, which is probably
+       not what you want.
 - atmel,dbg-halt : Should be present if you want to stop the watchdog when
        entering debug state.
 
index 1b528b2ad809b8418cb352be8755de286b78882f..fcf4d509d1186f728b77e398c438af0850d9511c 100644 (file)
@@ -5,8 +5,8 @@ system.
 
 dlmfs is built with OCFS2 as it requires most of its infrastructure.
 
-Project web page:    http://oss.oracle.com/projects/ocfs2
-Tools web page:      http://oss.oracle.com/projects/ocfs2-tools
+Project web page:    http://ocfs2.wiki.kernel.org
+Tools web page:      https://github.com/markfasheh/ocfs2-tools
 OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
 
 All code copyright 2005 Oracle except when otherwise noted.
index 28f8c08201e29e0e90e2a489997f7a6b1d78dabb..4c49e5410595c0ee86447ed6312d58315e2e974c 100644 (file)
@@ -8,8 +8,8 @@ also make it attractive for non-clustered use.
 You'll want to install the ocfs2-tools package in order to at least
 get "mount.ocfs2" and "ocfs2_hb_ctl".
 
-Project web page:    http://oss.oracle.com/projects/ocfs2
-Tools web page:      http://oss.oracle.com/projects/ocfs2-tools
+Project web page:    http://ocfs2.wiki.kernel.org
+Tools git tree:      https://github.com/markfasheh/ocfs2-tools
 OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
 
 All code copyright 2005 Oracle except when otherwise noted.
index 2f9c5a5fcb25ff2d91aa196123952b01d0908e34..8afb29a8604a552c9dc1b1794466bf20933dca35 100644 (file)
@@ -40,8 +40,10 @@ but also to IPIs and to some other special-purpose interrupts.
 
 The IRQF_NO_SUSPEND flag is used to indicate that to the IRQ subsystem when
 requesting a special-purpose interrupt.  It causes suspend_device_irqs() to
-leave the corresponding IRQ enabled so as to allow the interrupt to work all
-the time as expected.
+leave the corresponding IRQ enabled so as to allow the interrupt to work as
+expected during the suspend-resume cycle, but does not guarantee that the
+interrupt will wake the system from a suspended state -- for such cases it is
+necessary to use enable_irq_wake().
 
 Note that the IRQF_NO_SUSPEND flag affects the entire IRQ and not just one
 user of it.  Thus, if the IRQ is shared, all of the interrupt handlers installed
@@ -110,8 +112,9 @@ any special interrupt handling logic for it to work.
 IRQF_NO_SUSPEND and enable_irq_wake()
 -------------------------------------
 
-There are no valid reasons to use both enable_irq_wake() and the IRQF_NO_SUSPEND
-flag on the same IRQ.
+There are very few valid reasons to use both enable_irq_wake() and the
+IRQF_NO_SUSPEND flag on the same IRQ, and it is never valid to use both for the
+same device.
 
 First of all, if the IRQ is not shared, the rules for handling IRQF_NO_SUSPEND
 interrupts (interrupt handlers are invoked after suspend_device_irqs()) are
@@ -120,4 +123,13 @@ handlers are not invoked after suspend_device_irqs()).
 
 Second, both enable_irq_wake() and IRQF_NO_SUSPEND apply to entire IRQs and not
 to individual interrupt handlers, so sharing an IRQ between a system wakeup
-interrupt source and an IRQF_NO_SUSPEND interrupt source does not make sense.
+interrupt source and an IRQF_NO_SUSPEND interrupt source does not generally
+make sense.
+
+In rare cases an IRQ can be shared between a wakeup device driver and an
+IRQF_NO_SUSPEND user. In order for this to be safe, the wakeup device driver
+must be able to discern spurious IRQs from genuine wakeup events (signalling
+the latter to the core with pm_system_wakeup()), must use enable_irq_wake() to
+ensure that the IRQ will function as a wakeup source, and must request the IRQ
+with IRQF_COND_SUSPEND to tell the core that it meets these requirements. If
+these requirements are not met, it is not valid to use IRQF_COND_SUSPEND.
index ddc5a8cf9a8ac0078f8ca1bc99d9c48f8197214a..36cf1007037c0464d73d83a7357d2c55638e0aff 100644 (file)
@@ -1030,6 +1030,16 @@ F:       arch/arm/mach-mxs/
 F:     arch/arm/boot/dts/imx*
 F:     arch/arm/configs/imx*_defconfig
 
+ARM/FREESCALE VYBRID ARM ARCHITECTURE
+M:     Shawn Guo <shawn.guo@linaro.org>
+M:     Sascha Hauer <kernel@pengutronix.de>
+R:     Stefan Agner <stefan@agner.ch>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
+F:     arch/arm/mach-imx/*vf610*
+F:     arch/arm/boot/dts/vf*
+
 ARM/GLOMATION GESBC9312SX MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1176,7 +1186,7 @@ M:        Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-mvebu/
-F:     drivers/rtc/armada38x-rtc
+F:     drivers/rtc/rtc-armada38x.c
 
 ARM/Marvell Berlin SoC support
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
@@ -1188,6 +1198,7 @@ ARM/Marvell Dove/MV78xx0/Orion SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
 M:     Andrew Lunn <andrew@lunn.ch>
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+M:     Gregory Clement <gregory.clement@free-electrons.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-dove/
@@ -1351,6 +1362,7 @@ F:        drivers/i2c/busses/i2c-rk3x.c
 F:     drivers/*/*rockchip*
 F:     drivers/*/*/*rockchip*
 F:     sound/soc/rockchip/
+N:     rockchip
 
 ARM/SAMSUNG EXYNOS ARM ARCHITECTURES
 M:     Kukjin Kim <kgene@kernel.org>
@@ -1664,8 +1676,8 @@ F:        drivers/misc/eeprom/at24.c
 F:     include/linux/platform_data/at24.h
 
 ATA OVER ETHERNET (AOE) DRIVER
-M:     "Ed L. Cashin" <ecashin@coraid.com>
-W:     http://support.coraid.com/support/linux
+M:     "Ed L. Cashin" <ed.cashin@acm.org>
+W:     http://www.openaoe.org/
 S:     Supported
 F:     Documentation/aoe/
 F:     drivers/block/aoe/
@@ -1730,7 +1742,7 @@ S:        Maintained
 F:     drivers/net/ethernet/atheros/
 
 ATM
-M:     Chas Williams <chas@cmf.nrl.navy.mil>
+M:     Chas Williams <3chas3@gmail.com>
 L:     linux-atm-general@lists.sourceforge.net (moderated for non-subscribers)
 L:     netdev@vger.kernel.org
 W:     http://linux-atm.sourceforge.net
@@ -2065,7 +2077,7 @@ F:        include/net/bluetooth/
 BONDING DRIVER
 M:     Jay Vosburgh <j.vosburgh@gmail.com>
 M:     Veaceslav Falico <vfalico@gmail.com>
-M:     Andy Gospodarek <andy@greyhouse.net>
+M:     Andy Gospodarek <gospo@cumulusnetworks.com>
 L:     netdev@vger.kernel.org
 W:     http://sourceforge.net/projects/bonding/
 S:     Supported
@@ -2107,7 +2119,6 @@ F:        drivers/net/ethernet/broadcom/bnx2x/
 
 BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE
 M:     Christian Daudt <bcm@fixthebug.org>
-M:     Matt Porter <mporter@linaro.org>
 M:     Florian Fainelli <f.fainelli@gmail.com>
 L:     bcm-kernel-feedback-list@broadcom.com
 T:     git git://github.com/broadcom/mach-bcm
@@ -2369,8 +2380,9 @@ F:        arch/x86/include/asm/tce.h
 
 CAN NETWORK LAYER
 M:     Oliver Hartkopp <socketcan@hartkopp.net>
+M:     Marc Kleine-Budde <mkl@pengutronix.de>
 L:     linux-can@vger.kernel.org
-W:     http://gitorious.org/linux-can
+W:     https://github.com/linux-can
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
 S:     Maintained
@@ -2386,7 +2398,7 @@ CAN NETWORK DRIVERS
 M:     Wolfgang Grandegger <wg@grandegger.com>
 M:     Marc Kleine-Budde <mkl@pengutronix.de>
 L:     linux-can@vger.kernel.org
-W:     http://gitorious.org/linux-can
+W:     https://github.com/linux-can
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
 S:     Maintained
@@ -3241,6 +3253,13 @@ S:       Maintained
 F:     Documentation/hwmon/dme1737
 F:     drivers/hwmon/dme1737.c
 
+DMI/SMBIOS SUPPORT
+M:     Jean Delvare <jdelvare@suse.de>
+S:     Maintained
+F:     drivers/firmware/dmi-id.c
+F:     drivers/firmware/dmi_scan.c
+F:     include/linux/dmi.h
+
 DOCKING STATION DRIVER
 M:     Shaohua Li <shaohua.li@intel.com>
 L:     linux-acpi@vger.kernel.org
@@ -3378,7 +3397,6 @@ T:        git git://people.freedesktop.org/~airlied/linux
 S:     Supported
 F:     drivers/gpu/drm/rcar-du/
 F:     drivers/gpu/drm/shmobile/
-F:     include/linux/platform_data/rcar-du.h
 F:     include/linux/platform_data/shmob_drm.h
 
 DSBR100 USB FM RADIO DRIVER
@@ -7213,8 +7231,7 @@ ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
 M:     Mark Fasheh <mfasheh@suse.com>
 M:     Joel Becker <jlbec@evilplan.org>
 L:     ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
-W:     http://oss.oracle.com/projects/ocfs2/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2.git
+W:     http://ocfs2.wiki.kernel.org
 S:     Supported
 F:     Documentation/filesystems/ocfs2.txt
 F:     Documentation/filesystems/dlmfs.txt
@@ -8481,6 +8498,14 @@ S:       Supported
 L:     netdev@vger.kernel.org
 F:     drivers/net/ethernet/samsung/sxgbe/
 
+SAMSUNG THERMAL DRIVER
+M:     Lukasz Majewski <l.majewski@samsung.com>
+L:     linux-pm@vger.kernel.org
+L:     linux-samsung-soc@vger.kernel.org
+S:     Supported
+T:     https://github.com/lmajewski/linux-samsung-thermal.git
+F:     drivers/thermal/samsung/
+
 SAMSUNG USB2 PHY DRIVER
 M:     Kamil Debski <k.debski@samsung.com>
 L:     linux-kernel@vger.kernel.org
@@ -10189,6 +10214,13 @@ S:     Maintained
 F:     Documentation/usb/ohci.txt
 F:     drivers/usb/host/ohci*
 
+USB OTG FSM (Finite State Machine)
+M:     Peter Chen <Peter.Chen@freescale.com>
+T:     git git://github.com/hzpeterchen/linux-usb.git
+L:     linux-usb@vger.kernel.org
+S:     Maintained
+F:     drivers/usb/common/usb-otg-fsm.c
+
 USB OVER IP DRIVER
 M:     Valentina Manea <valentina.manea.m@gmail.com>
 M:     Shuah Khan <shuah.kh@samsung.com>
index 9fab639727c78e5370538afcd6980f167af6fdf6..da36a3be7969049870d969ae4a623fd7a0c15ee1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 0
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc6
 NAME = Hurr durr I'ma sheep
 
 # *DOCUMENTATION*
index 4e547296831d62ea673239dcb224c69ee02cd782..52312cb5dbe21490b48e21343ab8f82b7eecfc0e 100644 (file)
@@ -47,9 +47,6 @@ struct thread_struct {
 /* Forward declaration, a strange C thing */
 struct task_struct;
 
-/* Return saved PC of a blocked thread  */
-unsigned long thread_saved_pc(struct task_struct *t);
-
 #define task_pt_regs(p) \
        ((struct pt_regs *)(THREAD_SIZE + (void *)task_stack_page(p)) - 1)
 
@@ -72,18 +69,21 @@ unsigned long thread_saved_pc(struct task_struct *t);
 #define release_segments(mm)        do { } while (0)
 
 #define KSTK_EIP(tsk)   (task_pt_regs(tsk)->ret)
+#define KSTK_ESP(tsk)   (task_pt_regs(tsk)->sp)
 
 /*
  * Where abouts of Task's sp, fp, blink when it was last seen in kernel mode.
  * Look in process.c for details of kernel stack layout
  */
-#define KSTK_ESP(tsk)   (tsk->thread.ksp)
+#define TSK_K_ESP(tsk)         (tsk->thread.ksp)
 
-#define KSTK_REG(tsk, off)     (*((unsigned int *)(KSTK_ESP(tsk) + \
+#define TSK_K_REG(tsk, off)    (*((unsigned int *)(TSK_K_ESP(tsk) + \
                                        sizeof(struct callee_regs) + off)))
 
-#define KSTK_BLINK(tsk) KSTK_REG(tsk, 4)
-#define KSTK_FP(tsk)    KSTK_REG(tsk, 0)
+#define TSK_K_BLINK(tsk)       TSK_K_REG(tsk, 4)
+#define TSK_K_FP(tsk)          TSK_K_REG(tsk, 0)
+
+#define thread_saved_pc(tsk)   TSK_K_BLINK(tsk)
 
 extern void start_thread(struct pt_regs * regs, unsigned long pc,
                         unsigned long usp);
diff --git a/arch/arc/include/asm/stacktrace.h b/arch/arc/include/asm/stacktrace.h
new file mode 100644 (file)
index 0000000..b29b606
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
+ * Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_STACKTRACE_H
+#define __ASM_STACKTRACE_H
+
+#include <linux/sched.h>
+
+/**
+ * arc_unwind_core - Unwind the kernel mode stack for an execution context
+ * @tsk:               NULL for current task, specific task otherwise
+ * @regs:              pt_regs used to seed the unwinder {SP, FP, BLINK, PC}
+ *                     If NULL, use pt_regs of @tsk (if !NULL) otherwise
+ *                     use the current values of {SP, FP, BLINK, PC}
+ * @consumer_fn:       Callback invoked for each frame unwound
+ *                     Returns 0 to continue unwinding, -1 to stop
+ * @arg:               Arg to callback
+ *
+ * Returns the address of first function in stack
+ *
+ * Semantics:
+ *  - synchronous unwinding (e.g. dump_stack): @tsk  NULL, @regs  NULL
+ *  - Asynchronous unwinding of sleeping task: @tsk !NULL, @regs  NULL
+ *  - Asynchronous unwinding of intr/excp etc: @tsk !NULL, @regs !NULL
+ */
+notrace noinline unsigned int arc_unwind_core(
+       struct task_struct *tsk, struct pt_regs *regs,
+       int (*consumer_fn) (unsigned int, void *),
+       void *arg);
+
+#endif /* __ASM_STACKTRACE_H */
index fdd89715d2d3783f8a1302513c10a15d138ded91..98c00a2d4dd9a57f1c503ac2ebb6d63a3f1a76b4 100644 (file)
@@ -192,29 +192,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
        return 0;
 }
 
-/*
- * API: expected by schedular Code: If thread is sleeping where is that.
- * What is this good for? it will be always the scheduler or ret_from_fork.
- * So we hard code that anyways.
- */
-unsigned long thread_saved_pc(struct task_struct *t)
-{
-       struct pt_regs *regs = task_pt_regs(t);
-       unsigned long blink = 0;
-
-       /*
-        * If the thread being queried for in not itself calling this, then it
-        * implies it is not executing, which in turn implies it is sleeping,
-        * which in turn implies it got switched OUT by the schedular.
-        * In that case, it's kernel mode blink can reliably retrieved as per
-        * the picture above (right above pt_regs).
-        */
-       if (t != current && t->state != TASK_RUNNING)
-               blink = *((unsigned int *)regs - 1);
-
-       return blink;
-}
-
 int elf_check_arch(const struct elf32_hdr *x)
 {
        unsigned int eflags;
index 114234e83caa25968e08302b5e61f14e152e2d16..edda76fae83f25219bd74c5487a458e29c765373 100644 (file)
@@ -67,7 +67,7 @@ stash_usr_regs(struct rt_sigframe __user *sf, struct pt_regs *regs,
               sigset_t *set)
 {
        int err;
-       err = __copy_to_user(&(sf->uc.uc_mcontext.regs), regs,
+       err = __copy_to_user(&(sf->uc.uc_mcontext.regs.scratch), regs,
                             sizeof(sf->uc.uc_mcontext.regs.scratch));
        err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(sigset_t));
 
@@ -83,7 +83,7 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf)
        if (!err)
                set_current_blocked(&set);
 
-       err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs),
+       err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs.scratch),
                                sizeof(sf->uc.uc_mcontext.regs.scratch));
 
        return err;
@@ -131,6 +131,15 @@ SYSCALL_DEFINE0(rt_sigreturn)
        /* Don't restart from sigreturn */
        syscall_wont_restart(regs);
 
+       /*
+        * Ensure that sigreturn always returns to user mode (in case the
+        * regs saved on user stack got fudged between save and sigreturn)
+        * Otherwise it is easy to panic the kernel with a custom
+        * signal handler and/or restorer which clobberes the status32/ret
+        * to return to a bogus location in kernel mode.
+        */
+       regs->status32 |= STATUS_U_MASK;
+
        return regs->r0;
 
 badframe:
@@ -229,8 +238,11 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
 
        /*
         * handler returns using sigreturn stub provided already by userpsace
+        * If not, nuke the process right away
         */
-       BUG_ON(!(ksig->ka.sa.sa_flags & SA_RESTORER));
+       if(!(ksig->ka.sa.sa_flags & SA_RESTORER))
+               return 1;
+
        regs->blink = (unsigned long)ksig->ka.sa.sa_restorer;
 
        /* User Stack for signal handler will be above the frame just carved */
@@ -296,12 +308,12 @@ static void
 handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 {
        sigset_t *oldset = sigmask_to_save();
-       int ret;
+       int failed;
 
        /* Set up the stack frame */
-       ret = setup_rt_frame(ksig, oldset, regs);
+       failed = setup_rt_frame(ksig, oldset, regs);
 
-       signal_setup_done(ret, ksig, 0);
+       signal_setup_done(failed, ksig, 0);
 }
 
 void do_signal(struct pt_regs *regs)
index 9ce47cfe23037fa12f463a350819731422aadd9b..92320d6f737cf5149d0968f5da3cd73a47af9848 100644 (file)
@@ -43,6 +43,10 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
                                   struct pt_regs *regs,
                                   struct unwind_frame_info *frame_info)
 {
+       /*
+        * synchronous unwinding (e.g. dump_stack)
+        *  - uses current values of SP and friends
+        */
        if (tsk == NULL && regs == NULL) {
                unsigned long fp, sp, blink, ret;
                frame_info->task = current;
@@ -61,12 +65,17 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
                frame_info->regs.r63 = ret;
                frame_info->call_frame = 0;
        } else if (regs == NULL) {
+               /*
+                * Asynchronous unwinding of sleeping task
+                *  - Gets SP etc from task's pt_regs (saved bottom of kernel
+                *    mode stack of task)
+                */
 
                frame_info->task = tsk;
 
-               frame_info->regs.r27 = KSTK_FP(tsk);
-               frame_info->regs.r28 = KSTK_ESP(tsk);
-               frame_info->regs.r31 = KSTK_BLINK(tsk);
+               frame_info->regs.r27 = TSK_K_FP(tsk);
+               frame_info->regs.r28 = TSK_K_ESP(tsk);
+               frame_info->regs.r31 = TSK_K_BLINK(tsk);
                frame_info->regs.r63 = (unsigned int)__switch_to;
 
                /* In the prologue of __switch_to, first FP is saved on stack
@@ -83,6 +92,10 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
                frame_info->call_frame = 0;
 
        } else {
+               /*
+                * Asynchronous unwinding of intr/exception
+                *  - Just uses the pt_regs passed
+                */
                frame_info->task = tsk;
 
                frame_info->regs.r27 = regs->fp;
@@ -95,7 +108,7 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
 
 #endif
 
-static noinline unsigned int
+notrace noinline unsigned int
 arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs,
                int (*consumer_fn) (unsigned int, void *), void *arg)
 {
index 7ff5b5c183bb026716295c13f7b123de1d67a96f..74db59b6f39269f072ce606700375ae14ab9ec8c 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/perf_event.h>
 #include <linux/ptrace.h>
 #include <linux/uaccess.h>
 #include <asm/disasm.h>
@@ -253,6 +254,7 @@ int misaligned_fixup(unsigned long address, struct pt_regs *regs,
                }
        }
 
+       perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, address);
        return 0;
 
 fault:
index 563cb27e37f55f3f99badc9b99e64aca6ee397b7..6a2e006cbcce1f1cd69866e0f0f9f94463d73dcb 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/ptrace.h>
 #include <linux/uaccess.h>
 #include <linux/kdebug.h>
+#include <linux/perf_event.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu.h>
 
@@ -139,13 +140,20 @@ good_area:
                        return;
        }
 
+       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
+
        if (likely(!(fault & VM_FAULT_ERROR))) {
                if (flags & FAULT_FLAG_ALLOW_RETRY) {
                        /* To avoid updating stats twice for retry case */
-                       if (fault & VM_FAULT_MAJOR)
+                       if (fault & VM_FAULT_MAJOR) {
                                tsk->maj_flt++;
-                       else
+                               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+                                             regs, address);
+                       } else {
                                tsk->min_flt++;
+                               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+                                             regs, address);
+                       }
 
                        if (fault & VM_FAULT_RETRY) {
                                flags &= ~FAULT_FLAG_ALLOW_RETRY;
index 9f1f09a2bc9bf28894777c08d6968d7faeba55a6..cf4c0c99aa253f3f69ecc08a07f0c5a695e63640 100644 (file)
@@ -619,6 +619,7 @@ config ARCH_PXA
        select GENERIC_CLOCKEVENTS
        select GPIO_PXA
        select HAVE_IDE
+       select IRQ_DOMAIN
        select MULTI_IRQ_HANDLER
        select PLAT_PXA
        select SPARSE_IRQ
index 7f99cd652203ce5705b22f5f0fc24f0574a82840..eb7bb511f853d975d67c0ee26c1167b2d5054279 100644 (file)
@@ -150,6 +150,7 @@ machine-$(CONFIG_ARCH_BERLIN)               += berlin
 machine-$(CONFIG_ARCH_CLPS711X)                += clps711x
 machine-$(CONFIG_ARCH_CNS3XXX)         += cns3xxx
 machine-$(CONFIG_ARCH_DAVINCI)         += davinci
+machine-$(CONFIG_ARCH_DIGICOLOR)       += digicolor
 machine-$(CONFIG_ARCH_DOVE)            += dove
 machine-$(CONFIG_ARCH_EBSA110)         += ebsa110
 machine-$(CONFIG_ARCH_EFM32)           += efm32
index 6cc25ed912eeff57fc9bd06cc390c6ece3e56b14..c3255e0c90aa829fc792f02d1265d413f3c6e624 100644 (file)
 
 &usb0 {
        status = "okay";
+       dr_mode = "peripheral";
 };
 
 &usb1 {
        cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
        cd-inverted;
 };
+
+&aes {
+       status = "okay";
+};
+
+&sham {
+       status = "okay";
+};
index 83d40f7655e52503d76537a4ceca1c76e3023e97..6b849372042419e21ca67f142c53f62618e5191d 100644 (file)
 &mmc1 {
        vmmc-supply = <&ldo3_reg>;
 };
-
-&sham {
-       status = "okay";
-};
-
-&aes {
-       status = "okay";
-};
index 7266a00aab2ea515397a9046942749cb291eb6d4..5c5667a3624dee614047e6b63efde568c063f431 100644 (file)
        dual_emac_res_vlan = <3>;
 };
 
+&phy_sel {
+       rmii-clock-ext;
+};
+
 &mac {
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&cpsw_default>;
index 712edce7d6fb12904f7063d38e57e36ab051346a..071b56aa0c7e05fd18201b25ba75836edb9aed5e 100644 (file)
@@ -99,7 +99,7 @@
        ehrpwm0_tbclk: ehrpwm0_tbclk@44e10664 {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <0>;
                reg = <0x0664>;
        };
        ehrpwm1_tbclk: ehrpwm1_tbclk@44e10664 {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <1>;
                reg = <0x0664>;
        };
        ehrpwm2_tbclk: ehrpwm2_tbclk@44e10664 {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <2>;
                reg = <0x0664>;
        };
index f9a17e2ca8cb068dfa63034d43a1077fb0a606bb..0198f5a62b96cd8b8569d4ae5d6dfd2938fcd580 100644 (file)
                >;
        };
 
-       i2c1_pins_default: i2c1_pins_default {
-               pinctrl-single,pins = <
-                       0x15c (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_cs0.i2c1_scl */
-                       0x158 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_d1.i2c1_sda */
-               >;
-       };
-
-       i2c1_pins_sleep: i2c1_pins_sleep {
-               pinctrl-single,pins = <
-                       0x15c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_cs0.i2c1_scl */
-                       0x158 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_d1.i2c1_sda */
-               >;
-       };
-
        mmc1_pins_default: pinmux_mmc1_pins_default {
                pinctrl-single,pins = <
                        0x100 (PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
        status = "okay";
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&i2c0_pins_default>;
-       pinctrl-1 = <&i2c0_pins_default>;
+       pinctrl-1 = <&i2c0_pins_sleep>;
        clock-frequency = <400000>;
 
        at24@50 {
                pagesize = <64>;
                reg = <0x50>;
        };
-};
-
-&i2c1 {
-       status = "okay";
-       pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&i2c1_pins_default>;
-       pinctrl-1 = <&i2c1_pins_default>;
-       clock-frequency = <400000>;
 
        tps: tps62362@60 {
                compatible = "ti,tps62362";
+               reg = <0x60>;
                regulator-name = "VDD_MPU";
                regulator-min-microvolt = <950000>;
                regulator-max-microvolt = <1330000>;
index c7dc9dab93a45eaf779497071cb9968027f5e163..cfb49686ab6af02ba7086e344869ee9ad457a2aa 100644 (file)
        ehrpwm0_tbclk: ehrpwm0_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <0>;
                reg = <0x0664>;
        };
        ehrpwm1_tbclk: ehrpwm1_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <1>;
                reg = <0x0664>;
        };
        ehrpwm2_tbclk: ehrpwm2_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <2>;
                reg = <0x0664>;
        };
        ehrpwm3_tbclk: ehrpwm3_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <4>;
                reg = <0x0664>;
        };
        ehrpwm4_tbclk: ehrpwm4_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <5>;
                reg = <0x0664>;
        };
        ehrpwm5_tbclk: ehrpwm5_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <6>;
                reg = <0x0664>;
        };
index 03750af3b49a41493035217c34c16984343b226c..6463f9ef2b548208bda288a78a07ab3353aa2220 100644 (file)
        pinctrl-0 = <&usb1_pins>;
 };
 
-&omap_dwc3_1 {
-       extcon = <&extcon_usb1>;
-};
-
-&omap_dwc3_2 {
-       extcon = <&extcon_usb2>;
-};
-
 &usb2 {
        dr_mode = "peripheral";
 };
index fff0ee69aab495361898b503268fd300a02832c1..e7f0a4ae271c6a53244c3a3b0f6204cae45d6b0b 100644 (file)
 
                                        pinctrl_usart3_rts: usart3_rts-0 {
                                                atmel,pins =
-                                                       <AT91_PIOB 8 AT91_PERIPH_B AT91_PINCTRL_NONE>;  /* PC8 periph B */
+                                                       <AT91_PIOC 8 AT91_PERIPH_B AT91_PINCTRL_NONE>;
                                        };
 
                                        pinctrl_usart3_cts: usart3_cts-0 {
                                                atmel,pins =
-                                                       <AT91_PIOB 10 AT91_PERIPH_B AT91_PINCTRL_NONE>; /* PC10 periph B */
+                                                       <AT91_PIOC 10 AT91_PERIPH_B AT91_PINCTRL_NONE>;
                                        };
                                };
 
                        };
 
                        usb1: gadget@fffa4000 {
-                               compatible = "atmel,at91rm9200-udc";
+                               compatible = "atmel,at91sam9260-udc";
                                reg = <0xfffa4000 0x4000>;
                                interrupts = <10 IRQ_TYPE_LEVEL_HIGH 2>;
                                clocks = <&udc_clk>, <&udpck>;
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index e247b0b5fdab2fe1cb41e57fd51450ae723256dd..d55fdf2487ef53f7a3c68cded4e78fe42039f538 100644 (file)
                        };
 
                        usb1: gadget@fffa4000 {
-                               compatible = "atmel,at91rm9200-udc";
+                               compatible = "atmel,at91sam9261-udc";
                                reg = <0xfffa4000 0x4000>;
                                interrupts = <10 IRQ_TYPE_LEVEL_HIGH 2>;
-                               clocks = <&usb>, <&udc_clk>, <&udpck>;
-                               clock-names = "usb_clk", "udc_clk", "udpck";
+                               clocks = <&udc_clk>, <&udpck>;
+                               clock-names = "pclk", "hclk";
+                               atmel,matrix = <&matrix>;
                                status = "disabled";
                        };
 
                        };
 
                        matrix: matrix@ffffee00 {
-                               compatible = "atmel,at91sam9260-bus-matrix";
+                               compatible = "atmel,at91sam9260-bus-matrix", "syscon";
                                reg = <0xffffee00 0x200>;
                        };
 
index 1f67bb4c144eef2489891b63b64edda96402f100..fce301c4e9d6e22aeb37d3a2a4fe83bf6634ad78 100644 (file)
@@ -69,7 +69,7 @@
 
        sram1: sram@00500000 {
                compatible = "mmio-sram";
-               reg = <0x00300000 0x4000>;
+               reg = <0x00500000 0x4000>;
        };
 
        ahb {
                        };
 
                        usb1: gadget@fff78000 {
-                               compatible = "atmel,at91rm9200-udc";
+                               compatible = "atmel,at91sam9263-udc";
                                reg = <0xfff78000 0x4000>;
                                interrupts = <24 IRQ_TYPE_LEVEL_HIGH 2>;
                                clocks = <&udc_clk>, <&udpck>;
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index ee80aa9c0759c17f178965181fb28f2a562f6b13..488af63d5174c7e9dc0eb29319ccb35eebd8fc7c 100644 (file)
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00800000 0x100000>;
                        interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "hclk", "uhpck";
                        status = "disabled";
                };
index c2666a7cb5b19b547d31f11d58d5af1c13d36acb..0c53a375ba99d214c1c0b5eabd85e77ec0cc72e6 100644 (file)
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index 818dabdd8c0e08e3089092f27117c1927bc6122f..d221179d0f1aad8aaccde552f74962a3009c6274 100644 (file)
                                reg = <0x00500000 0x80000
                                       0xf803c000 0x400>;
                                interrupts = <23 IRQ_TYPE_LEVEL_HIGH 0>;
-                               clocks = <&usb>, <&udphs_clk>;
+                               clocks = <&utmi>, <&udphs_clk>;
                                clock-names = "hclk", "pclk";
                                status = "disabled";
 
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00700000 0x100000>;
                        interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "uhpck";
                        status = "disabled";
                };
index 857d0289ad4d7c9ed81268a2d2a20c923b2177a0..afe678f6d2e950308b74e403d26a3cc326c2b760 100644 (file)
                        DM816X_IOPAD(0x0aac, PIN_INPUT | MUX_MODE0)     /* SPI_D1 */
                >;
        };
+
+       mmc_pins: pinmux_mmc_pins {
+               pinctrl-single,pins = <
+                       DM816X_IOPAD(0x0a70, MUX_MODE0)                 /* SD_POW */
+                       DM816X_IOPAD(0x0a74, MUX_MODE0)                 /* SD_CLK */
+                       DM816X_IOPAD(0x0a78, MUX_MODE0)                 /* SD_CMD */
+                       DM816X_IOPAD(0x0a7C, MUX_MODE0)                 /* SD_DAT0 */
+                       DM816X_IOPAD(0x0a80, MUX_MODE0)                 /* SD_DAT1 */
+                       DM816X_IOPAD(0x0a84, MUX_MODE0)                 /* SD_DAT2 */
+                       DM816X_IOPAD(0x0a88, MUX_MODE0)                 /* SD_DAT2 */
+                       DM816X_IOPAD(0x0a8c, MUX_MODE2)                 /* GP1[7] */
+                       DM816X_IOPAD(0x0a90, MUX_MODE2)                 /* GP1[8] */
+               >;
+       };
+
+       usb0_pins: pinmux_usb0_pins {
+               pinctrl-single,pins = <
+                       DM816X_IOPAD(0x0d00, MUX_MODE0)                 /* USB0_DRVVBUS */
+               >;
+       };
+
+       usb1_pins: pinmux_usb0_pins {
+               pinctrl-single,pins = <
+                       DM816X_IOPAD(0x0d04, MUX_MODE0)                 /* USB1_DRVVBUS */
+               >;
+       };
 };
 
 &i2c1 {
 };
 
 &mmc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc_pins>;
        vmmc-supply = <&vmmcsd_fixed>;
+       bus-width = <4>;
+       cd-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
+};
+
+/* At least dm8168-evm rev c won't support multipoint, later may */
+&usb0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb0_pins>;
+       mentor,multipoint = <0>;
+};
+
+&usb1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb1_pins>;
+       mentor,multipoint = <0>;
 };
index d98d0f7de380d95d956aa6826dd626c53d500be7..f35715bc69922591577299730ecf1a105c6642de 100644 (file)
 
                        /* Device Configuration Registers */
                        scm_conf: syscon@600 {
-                               compatible = "syscon";
+                               compatible = "syscon", "simple-bus";
                                reg = <0x600 0x110>;
                                #address-cells = <1>;
                                #size-cells = <1>;
+                               ranges = <0 0x600 0x110>;
+
+                               usb_phy0: usb-phy@20 {
+                                       compatible = "ti,dm8168-usb-phy";
+                                       reg = <0x20 0x8>;
+                                       reg-names = "phy";
+                                       clocks = <&main_fapll 6>;
+                                       clock-names = "refclk";
+                                       #phy-cells = <0>;
+                                       syscon = <&scm_conf>;
+                               };
+
+                               usb_phy1: usb-phy@28 {
+                                       compatible = "ti,dm8168-usb-phy";
+                                       reg = <0x28 0x8>;
+                                       reg-names = "phy";
+                                       clocks = <&main_fapll 6>;
+                                       clock-names = "refclk";
+                                       #phy-cells = <0>;
+                                       syscon = <&scm_conf>;
+                               };
                        };
 
                        scrm_clocks: clocks {
                };
 
                gpio1: gpio@48032000 {
-                       compatible = "ti,omap3-gpio";
+                       compatible = "ti,omap4-gpio";
                        ti,hwmods = "gpio1";
+                       ti,gpio-always-on;
                        reg = <0x48032000 0x1000>;
-                       interrupts = <97>;
+                       interrupts = <96>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
 
                gpio2: gpio@4804c000 {
-                       compatible = "ti,omap3-gpio";
+                       compatible = "ti,omap4-gpio";
                        ti,hwmods = "gpio2";
+                       ti,gpio-always-on;
                        reg = <0x4804c000 0x1000>;
-                       interrupts = <99>;
+                       interrupts = <98>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
 
                gpmc: gpmc@50000000 {
                                reg-names = "mc", "control";
                                interrupts = <18>;
                                interrupt-names = "mc";
-                               dr_mode = "otg";
+                               dr_mode = "host";
+                               interface-type = <0>;
+                               phys = <&usb_phy0>;
+                               phy-names = "usb2-phy";
                                mentor,multipoint = <1>;
                                mentor,num-eps = <16>;
                                mentor,ram-bits = <12>;
 
                        usb1: usb@47401800 {
                                compatible = "ti,musb-am33xx";
-                               status = "disabled";
                                reg = <0x47401c00 0x400
                                       0x47401800 0x200>;
                                reg-names = "mc", "control";
                                interrupts = <19>;
                                interrupt-names = "mc";
-                               dr_mode = "otg";
+                               dr_mode = "host";
+                               interface-type = <0>;
+                               phys = <&usb_phy1>;
+                               phy-names = "usb2-phy";
                                mentor,multipoint = <1>;
                                mentor,num-eps = <16>;
                                mentor,ram-bits = <12>;
index 746cddb1b8f538e1d1fed717b077998f4a46adc8..7563d7ce01bbc74ed71fab8cd07a578060325500 100644 (file)
 
        dcan1_pins_default: dcan1_pins_default {
                pinctrl-single,pins = <
-                       0x3d0   (PIN_OUTPUT | MUX_MODE0) /* dcan1_tx */
-                       0x3d4   (MUX_MODE15)            /* dcan1_rx.off */
-                       0x418   (PULL_DIS | MUX_MODE1) /* wakeup0.dcan1_rx */
+                       0x3d0   (PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */
+                       0x418   (PULL_UP | MUX_MODE1) /* wakeup0.dcan1_rx */
                >;
        };
 
        dcan1_pins_sleep: dcan1_pins_sleep {
                pinctrl-single,pins = <
-                       0x3d0   (MUX_MODE15)    /* dcan1_tx.off */
-                       0x3d4   (MUX_MODE15)    /* dcan1_rx.off */
-                       0x418   (MUX_MODE15)    /* wakeup0.off */
+                       0x3d0   (MUX_MODE15 | PULL_UP)  /* dcan1_tx.off */
+                       0x418   (MUX_MODE15 | PULL_UP)  /* wakeup0.off */
                >;
        };
 };
        };
 };
 
-&omap_dwc3_1 {
-       extcon = <&extcon_usb1>;
-};
-
-&omap_dwc3_2 {
-       extcon = <&extcon_usb2>;
-};
-
 &usb1 {
        dr_mode = "peripheral";
        pinctrl-names = "default";
index 5827fedafd43d58a00169a4186cbb595d6f11234..c4659a979c41387558f8ea660d119568645acbcb 100644 (file)
                                     <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <127>;
+                       dma-channels = <32>;
+                       dma-requests = <127>;
                };
 
                gpio1: gpio@4ae10000 {
                                      <0x4A096800 0x40>; /* pll_ctrl */
                                reg-names = "phy_rx", "phy_tx", "pll_ctrl";
                                ctrl-module = <&omap_control_sata>;
-                               clocks = <&sys_clkin1>;
-                               clock-names = "sysclk";
+                               clocks = <&sys_clkin1>, <&sata_ref_clk>;
+                               clock-names = "sysclk", "refclk";
                                #phy-cells = <0>;
                        };
 
                                              "wkupclk", "refclk",
                                              "div-clk", "phy-div";
                                #phy-cells = <0>;
-                               ti,hwmods = "pcie1-phy";
                        };
 
                        pcie2_phy: pciephy@4a095000 {
                                              "wkupclk", "refclk",
                                              "div-clk", "phy-div";
                                #phy-cells = <0>;
-                               ti,hwmods = "pcie2-phy";
                                status = "disabled";
                        };
                };
index 4d87117136108873d2410ffaa68010652fd2e356..40ed539ce4743a0f3eccc319e4a4c6be09472363 100644 (file)
 
        dcan1_pins_default: dcan1_pins_default {
                pinctrl-single,pins = <
-                       0x3d0   (PIN_OUTPUT | MUX_MODE0) /* dcan1_tx */
-                       0x3d4   (MUX_MODE15)            /* dcan1_rx.off */
-                       0x418   (PULL_DIS | MUX_MODE1) /* wakeup0.dcan1_rx */
+                       0x3d0   (PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */
+                       0x418   (PULL_UP | MUX_MODE1)   /* wakeup0.dcan1_rx */
                >;
        };
 
        dcan1_pins_sleep: dcan1_pins_sleep {
                pinctrl-single,pins = <
-                       0x3d0   (MUX_MODE15)    /* dcan1_tx.off */
-                       0x3d4   (MUX_MODE15)    /* dcan1_rx.off */
-                       0x418   (MUX_MODE15)    /* wakeup0.off */
+                       0x3d0   (MUX_MODE15 | PULL_UP)  /* dcan1_tx.off */
+                       0x418   (MUX_MODE15 | PULL_UP)  /* wakeup0.off */
                >;
        };
 
        phy-supply = <&ldo4_reg>;
 };
 
-&omap_dwc3_1 {
-       extcon = <&extcon_usb1>;
-};
-
-&omap_dwc3_2 {
-       extcon = <&extcon_usb2>;
-};
-
 &usb1 {
        dr_mode = "peripheral";
        pinctrl-names = "default";
index 4bdcbd61ce47eac73d287448b2163426d67c7305..99b09a44e2694129ece5426f8df2227719255a37 100644 (file)
                ti,invert-autoidle-bit;
        };
 
+       dpll_core_byp_mux: dpll_core_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x012c>;
+       };
+
        dpll_core_ck: dpll_core_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-core-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_core_byp_mux>;
                reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_dsp_byp_mux: dpll_dsp_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dsp_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x0240>;
+       };
+
        dpll_dsp_ck: dpll_dsp_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dsp_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_dsp_byp_mux>;
                reg = <0x0234>, <0x0238>, <0x0240>, <0x023c>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_iva_byp_mux: dpll_iva_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&iva_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x01ac>;
+       };
+
        dpll_iva_ck: dpll_iva_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&iva_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_iva_byp_mux>;
                reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_gpu_byp_mux: dpll_gpu_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x02e4>;
+       };
+
        dpll_gpu_ck: dpll_gpu_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_gpu_byp_mux>;
                reg = <0x02d8>, <0x02dc>, <0x02e4>, <0x02e0>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_ddr_byp_mux: dpll_ddr_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x021c>;
+       };
+
        dpll_ddr_ck: dpll_ddr_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_ddr_byp_mux>;
                reg = <0x0210>, <0x0214>, <0x021c>, <0x0218>;
        };
 
                ti,invert-autoidle-bit;
        };
 
+       dpll_gmac_byp_mux: dpll_gmac_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x02b4>;
+       };
+
        dpll_gmac_ck: dpll_gmac_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_gmac_byp_mux>;
                reg = <0x02a8>, <0x02ac>, <0x02b4>, <0x02b0>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_eve_byp_mux: dpll_eve_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&eve_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x0290>;
+       };
+
        dpll_eve_ck: dpll_eve_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&eve_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_eve_byp_mux>;
                reg = <0x0284>, <0x0288>, <0x0290>, <0x028c>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_per_byp_mux: dpll_per_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&per_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x014c>;
+       };
+
        dpll_per_ck: dpll_per_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&per_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_per_byp_mux>;
                reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_usb_byp_mux: dpll_usb_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&usb_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x018c>;
+       };
+
        dpll_usb_ck: dpll_usb_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-j-type-clock";
-               clocks = <&sys_clkin1>, <&usb_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_usb_byp_mux>;
                reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>;
        };
 
index 277b48b0b6f9cd155737550d0586e9d720cf75f4..ac6b0ae42caff5f9ad7d14307f2421ddbf35c689 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include "skeleton.dtsi"
+#include "exynos4-cpu-thermal.dtsi"
 #include <dt-bindings/clock/exynos3250.h>
 
 / {
                        interrupts = <0 216 0>;
                        clocks = <&cmu CLK_TMU_APBIF>;
                        clock-names = "tmu_apbif";
+                       #include "exynos4412-tmu-sensor-conf.dtsi"
                        status = "disabled";
                };
 
diff --git a/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi b/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi
new file mode 100644 (file)
index 0000000..735cb2f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Device tree sources for Exynos4 thermal zone
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@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 <dt-bindings/thermal/thermal.h>
+
+/ {
+thermal-zones {
+       cpu_thermal: cpu-thermal {
+               thermal-sensors = <&tmu 0>;
+               polling-delay-passive = <0>;
+               polling-delay = <0>;
+               trips {
+                       cpu_alert0: cpu-alert-0 {
+                               temperature = <70000>; /* millicelsius */
+                               hysteresis = <10000>; /* millicelsius */
+                               type = "active";
+                       };
+                       cpu_alert1: cpu-alert-1 {
+                               temperature = <95000>; /* millicelsius */
+                               hysteresis = <10000>; /* millicelsius */
+                               type = "active";
+                       };
+                       cpu_alert2: cpu-alert-2 {
+                               temperature = <110000>; /* millicelsius */
+                               hysteresis = <10000>; /* millicelsius */
+                               type = "active";
+                       };
+                       cpu_crit0: cpu-crit-0 {
+                               temperature = <120000>; /* millicelsius */
+                               hysteresis = <0>; /* millicelsius */
+                               type = "critical";
+                       };
+               };
+               cooling-maps {
+                       map0 {
+                               trip = <&cpu_alert0>;
+                       };
+                       map1 {
+                               trip = <&cpu_alert1>;
+                       };
+               };
+       };
+};
+};
index 76173cacd4501fdd5af0ff061cf6f93e3bd922df..77ea547768f4fa24965ce945b6a7ea2adc12ba60 100644 (file)
@@ -38,6 +38,7 @@
                i2c5 = &i2c_5;
                i2c6 = &i2c_6;
                i2c7 = &i2c_7;
+               i2c8 = &i2c_8;
                csis0 = &csis_0;
                csis1 = &csis_1;
                fimc0 = &fimc_0;
                compatible = "samsung,exynos4210-pd";
                reg = <0x10023C20 0x20>;
                #power-domain-cells = <0>;
+               power-domains = <&pd_lcd0>;
        };
 
        pd_cam: cam-power-domain@10023C00 {
                status = "disabled";
        };
 
+       i2c_8: i2c@138E0000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "samsung,s3c2440-hdmiphy-i2c";
+               reg = <0x138E0000 0x100>;
+               interrupts = <0 93 0>;
+               clocks = <&clock CLK_I2C_HDMI>;
+               clock-names = "i2c";
+               status = "disabled";
+
+               hdmi_i2c_phy: hdmiphy@38 {
+                       compatible = "exynos4210-hdmiphy";
+                       reg = <0x38>;
+               };
+       };
+
        spi_0: spi@13920000 {
                compatible = "samsung,exynos4210-spi";
                reg = <0x13920000 0x100>;
                status = "disabled";
        };
 
+       tmu: tmu@100C0000 {
+               #include "exynos4412-tmu-sensor-conf.dtsi"
+       };
+
+       hdmi: hdmi@12D00000 {
+               compatible = "samsung,exynos4210-hdmi";
+               reg = <0x12D00000 0x70000>;
+               interrupts = <0 92 0>;
+               clock-names = "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy",
+                       "mout_hdmi";
+               clocks = <&clock CLK_HDMI>, <&clock CLK_SCLK_HDMI>,
+                       <&clock CLK_SCLK_PIXEL>, <&clock CLK_SCLK_HDMIPHY>,
+                       <&clock CLK_MOUT_HDMI>;
+               phy = <&hdmi_i2c_phy>;
+               power-domains = <&pd_tv>;
+               samsung,syscon-phandle = <&pmu_system_controller>;
+               status = "disabled";
+       };
+
+       mixer: mixer@12C10000 {
+               compatible = "samsung,exynos4210-mixer";
+               interrupts = <0 91 0>;
+               reg = <0x12C10000 0x2100>, <0x12c00000 0x300>;
+               power-domains = <&pd_tv>;
+               status = "disabled";
+       };
+
        ppmu_dmc0: ppmu_dmc0@106a0000 {
                compatible = "samsung,exynos-ppmu";
                reg = <0x106a0000 0x2000>;
index 3d6652a4b6cbafad4a935ee82430c0b998e8590e..32c5fd8f6269d9c5932de0d715e7763f99541057 100644 (file)
                status = "okay";
        };
 
+       tmu@100C0000 {
+               status = "okay";
+       };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 2 2>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 4 4>;
+                              };
+                      };
+               };
+       };
+
        camera {
                pinctrl-names = "default";
                pinctrl-0 = <>;
index b57e6b82ea203b521399fc13f56f3e3a99c10c17..d4f2b11319dd10d4d7b79fa295d55e63baccff9c 100644 (file)
                        assigned-clock-rates = <0>, <160000000>;
                };
        };
+
+       hdmi_en: voltage-regulator-hdmi-5v {
+               compatible = "regulator-fixed";
+               regulator-name = "HDMI_5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpe0 1 0>;
+               enable-active-high;
+       };
+
+       hdmi_ddc: i2c-ddc {
+               compatible = "i2c-gpio";
+               gpios = <&gpe4 2 0 &gpe4 3 0>;
+               i2c-gpio,delay-us = <100>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pinctrl-0 = <&i2c_ddc_bus>;
+               pinctrl-names = "default";
+               status = "okay";
+       };
+
+       mixer@12C10000 {
+               status = "okay";
+       };
+
+       hdmi@12D00000 {
+               hpd-gpio = <&gpx3 7 0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&hdmi_hpd>;
+               hdmi-en-supply = <&hdmi_en>;
+               vdd-supply = <&ldo3_reg>;
+               vdd_osc-supply = <&ldo4_reg>;
+               vdd_pll-supply = <&ldo3_reg>;
+               ddc = <&hdmi_ddc>;
+               status = "okay";
+       };
+
+       i2c@138E0000 {
+               status = "okay";
+       };
+};
+
+&pinctrl_1 {
+       hdmi_hpd: hdmi-hpd {
+               samsung,pins = "gpx3-7";
+               samsung,pin-pud = <0>;
+       };
+};
+
+&pinctrl_0 {
+       i2c_ddc_bus: i2c-ddc-bus {
+               samsung,pins = "gpe4-2", "gpe4-3";
+               samsung,pin-function = <2>;
+               samsung,pin-pud = <3>;
+               samsung,pin-drv = <0>;
+       };
 };
 
 &mdma1 {
index 67c832c9dcf140d6203d742810a374aff867ef69..be89f83f70e7750577441c7400567a57c89ec9cb 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "exynos4.dtsi"
 #include "exynos4210-pinctrl.dtsi"
+#include "exynos4-cpu-thermal.dtsi"
 
 / {
        compatible = "samsung,exynos4210", "samsung,exynos4";
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@900 {
+               cpu0: cpu@900 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0x900>;
+                       cooling-min-level = <4>;
+                       cooling-max-level = <2>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
 
                cpu@901 {
                reg = <0x03860000 0x1000>;
        };
 
-       tmu@100C0000 {
+       tmu: tmu@100C0000 {
                compatible = "samsung,exynos4210-tmu";
                interrupt-parent = <&combiner>;
                reg = <0x100C0000 0x100>;
                interrupts = <2 4>;
                clocks = <&clock CLK_TMU_APBIF>;
                clock-names = "tmu_apbif";
+               samsung,tmu_gain = <15>;
+               samsung,tmu_reference_voltage = <7>;
                status = "disabled";
        };
 
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&tmu 0>;
+
+                       trips {
+                             cpu_alert0: cpu-alert-0 {
+                                     temperature = <85000>; /* millicelsius */
+                             };
+                             cpu_alert1: cpu-alert-1 {
+                                     temperature = <100000>; /* millicelsius */
+                             };
+                             cpu_alert2: cpu-alert-2 {
+                                     temperature = <110000>; /* millicelsius */
+                             };
+                       };
+               };
+       };
+
        g2d@12800000 {
                compatible = "samsung,s5pv210-g2d";
                reg = <0x12800000 0x1000>;
                };
        };
 
+       mixer: mixer@12C10000 {
+               clock-names = "mixer", "hdmi", "sclk_hdmi", "vp", "mout_mixer",
+                       "sclk_mixer";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                       <&clock CLK_SCLK_HDMI>, <&clock CLK_VP>,
+                       <&clock CLK_MOUT_MIXER>, <&clock CLK_SCLK_MIXER>;
+       };
+
        ppmu_lcd1: ppmu_lcd1@12240000 {
                compatible = "samsung,exynos-ppmu";
                reg = <0x12240000 0x2000>;
index dd0a43ec56da905d64fc02f596b70d0ce92e67f3..5be03288f1ee6157cf35849c256743c9ff86b70d 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@A00 {
+               cpu0: cpu@A00 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0xA00>;
+                       cooling-min-level = <13>;
+                       cooling-max-level = <7>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
 
                cpu@A01 {
index de80b5bba20454b3e504fd26228d581bcb725190..adb4f6a97a1d5b19d67d486e7d36dd386884d1fd 100644 (file)
                                        regulator-always-on;
                                };
 
+                               ldo8_reg: ldo@8 {
+                                       regulator-compatible = "LDO8";
+                                       regulator-name = "VDD10_HDMI_1.0V";
+                                       regulator-min-microvolt = <1000000>;
+                                       regulator-max-microvolt = <1000000>;
+                               };
+
+                               ldo10_reg: ldo@10 {
+                                       regulator-compatible = "LDO10";
+                                       regulator-name = "VDDQ_MIPIHSI_1.8V";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
+                               };
+
                                ldo11_reg: LDO11 {
                                        regulator-name = "VDD18_ABB1_1.8V";
                                        regulator-min-microvolt = <1800000>;
        ehci: ehci@12580000 {
                status = "okay";
        };
+
+       tmu@100C0000 {
+               vtmu-supply = <&ldo10_reg>;
+               status = "okay";
+       };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 7 7>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 13 13>;
+                              };
+                      };
+               };
+       };
+
+       mixer: mixer@12C10000 {
+               status = "okay";
+       };
+
+       hdmi@12D00000 {
+               hpd-gpio = <&gpx3 7 0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&hdmi_hpd>;
+               vdd-supply = <&ldo8_reg>;
+               vdd_osc-supply = <&ldo10_reg>;
+               vdd_pll-supply = <&ldo8_reg>;
+               ddc = <&hdmi_ddc>;
+               status = "okay";
+       };
+
+       hdmi_ddc: i2c@13880000 {
+               status = "okay";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c2_bus>;
+       };
+
+       i2c@138E0000 {
+               status = "okay";
+       };
 };
 
 &pinctrl_1 {
                samsung,pin-pud = <0>;
                samsung,pin-drv = <0>;
        };
+
+       hdmi_hpd: hdmi-hpd {
+               samsung,pins = "gpx3-7";
+               samsung,pin-pud = <1>;
+       };
 };
diff --git a/arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi b/arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi
new file mode 100644 (file)
index 0000000..e3f7934
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Device tree sources for Exynos4412 TMU sensor configuration
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@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 <dt-bindings/thermal/thermal_exynos.h>
+
+#thermal-sensor-cells = <0>;
+samsung,tmu_gain = <8>;
+samsung,tmu_reference_voltage = <16>;
+samsung,tmu_noise_cancel_mode = <4>;
+samsung,tmu_efuse_value = <55>;
+samsung,tmu_min_efuse_value = <40>;
+samsung,tmu_max_efuse_value = <100>;
+samsung,tmu_first_point_trim = <25>;
+samsung,tmu_second_point_trim = <85>;
+samsung,tmu_default_temp_offset = <50>;
+samsung,tmu_cal_type = <TYPE_ONE_POINT_TRIMMING>;
index 21f7480835868396061bc8216833eae37398398a..173ffa479ad3cb03eb6e6742663fafaccacf9d53 100644 (file)
                pulldown-ohm = <100000>; /* 100K */
                io-channels = <&adc 2>;  /* Battery temperature */
        };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 7 7>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 13 13>;
+                              };
+                      };
+               };
+       };
 };
 
 &pmu_system_controller {
index 0f6ec93bb1d8a243d511dac4e2e42f6a794e9015..68ad43b391ae6122c3783b443cf23b5ccb7a2d04 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@A00 {
+               cpu0: cpu@A00 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0xA00>;
+                       cooling-min-level = <13>;
+                       cooling-max-level = <7>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
 
                cpu@A01 {
index f5e0ae780d6ce8dd25622abed741b03416570f03..6a6abe14fd9b59eed66e033ef43b970c6d4ce256 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "exynos4.dtsi"
 #include "exynos4x12-pinctrl.dtsi"
+#include "exynos4-cpu-thermal.dtsi"
 
 / {
        aliases {
                clock-names = "tmu_apbif";
                status = "disabled";
        };
+
+       hdmi: hdmi@12D00000 {
+               compatible = "samsung,exynos4212-hdmi";
+       };
+
+       mixer: mixer@12C10000 {
+               compatible = "samsung,exynos4212-mixer";
+               clock-names = "mixer", "hdmi", "sclk_hdmi", "vp";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                        <&clock CLK_SCLK_HDMI>, <&clock CLK_VP>;
+       };
 };
index 9bb1b0b738f53d2e544baa582faeec5841b16783..adbde1adad95ddf0bde124e25b2b16ac41dba83b 100644 (file)
@@ -20,7 +20,7 @@
 #include <dt-bindings/clock/exynos5250.h>
 #include "exynos5.dtsi"
 #include "exynos5250-pinctrl.dtsi"
-
+#include "exynos4-cpu-thermal.dtsi"
 #include <dt-bindings/clock/exynos-audss-clk.h>
 
 / {
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@0 {
+               cpu0: cpu@0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0>;
                        clock-frequency = <1700000000>;
+                       cooling-min-level = <15>;
+                       cooling-max-level = <9>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
                cpu@1 {
                        device_type = "cpu";
                #power-domain-cells = <0>;
        };
 
+       pd_disp1: disp1-power-domain@100440A0 {
+               compatible = "samsung,exynos4210-pd";
+               reg = <0x100440A0 0x20>;
+               #power-domain-cells = <0>;
+       };
+
        clock: clock-controller@10010000 {
                compatible = "samsung,exynos5250-clock";
                reg = <0x10010000 0x30000>;
                status = "disabled";
        };
 
-       tmu@10060000 {
+       tmu: tmu@10060000 {
                compatible = "samsung,exynos5250-tmu";
                reg = <0x10060000 0x100>;
                interrupts = <0 65 0>;
                clocks = <&clock CLK_TMU>;
                clock-names = "tmu_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
+       };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&tmu 0>;
+
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 9 9>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 15 15>;
+                              };
+                      };
+               };
        };
 
        serial@12C00000 {
        hdmi: hdmi {
                compatible = "samsung,exynos4212-hdmi";
                reg = <0x14530000 0x70000>;
+               power-domains = <&pd_disp1>;
                interrupts = <0 95 0>;
                clocks = <&clock CLK_HDMI>, <&clock CLK_SCLK_HDMI>,
                         <&clock CLK_SCLK_PIXEL>, <&clock CLK_SCLK_HDMIPHY>,
        mixer {
                compatible = "samsung,exynos5250-mixer";
                reg = <0x14450000 0x10000>;
+               power-domains = <&pd_disp1>;
                interrupts = <0 94 0>;
-               clocks = <&clock CLK_MIXER>, <&clock CLK_SCLK_HDMI>;
-               clock-names = "mixer", "sclk_hdmi";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                        <&clock CLK_SCLK_HDMI>;
+               clock-names = "mixer", "hdmi", "sclk_hdmi";
        };
 
        dp_phy: video-phy@10040720 {
        };
 
        dp: dp-controller@145B0000 {
+               power-domains = <&pd_disp1>;
                clocks = <&clock CLK_DP>;
                clock-names = "dp";
                phys = <&dp_phy>;
        };
 
        fimd: fimd@14400000 {
+               power-domains = <&pd_disp1>;
                clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>;
                clock-names = "sclk_fimd", "fimd";
        };
diff --git a/arch/arm/boot/dts/exynos5420-trip-points.dtsi b/arch/arm/boot/dts/exynos5420-trip-points.dtsi
new file mode 100644 (file)
index 0000000..5d31fc1
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Device tree sources for default Exynos5420 thermal zone definition
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@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.
+ *
+ */
+
+polling-delay-passive = <0>;
+polling-delay = <0>;
+trips {
+       cpu-alert-0 {
+               temperature = <85000>; /* millicelsius */
+               hysteresis = <10000>; /* millicelsius */
+               type = "active";
+       };
+       cpu-alert-1 {
+               temperature = <103000>; /* millicelsius */
+               hysteresis = <10000>; /* millicelsius */
+               type = "active";
+       };
+       cpu-alert-2 {
+               temperature = <110000>; /* millicelsius */
+               hysteresis = <10000>; /* millicelsius */
+               type = "active";
+       };
+       cpu-crit-0 {
+               temperature = <1200000>; /* millicelsius */
+               hysteresis = <0>; /* millicelsius */
+               type = "critical";
+       };
+};
index 9dc2e9773b30c5f5aaa22e5b3d1c1968bc1dd226..c0e98cf3514fa1fec0031984f735b02ca054af3c 100644 (file)
                compatible = "samsung,exynos5420-mixer";
                reg = <0x14450000 0x10000>;
                interrupts = <0 94 0>;
-               clocks = <&clock CLK_MIXER>, <&clock CLK_SCLK_HDMI>;
-               clock-names = "mixer", "sclk_hdmi";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                        <&clock CLK_SCLK_HDMI>;
+               clock-names = "mixer", "hdmi", "sclk_hdmi";
                power-domains = <&disp_pd>;
        };
 
                interrupts = <0 65 0>;
                clocks = <&clock CLK_TMU>;
                clock-names = "tmu_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_cpu1: tmu@10064000 {
                interrupts = <0 183 0>;
                clocks = <&clock CLK_TMU>;
                clock-names = "tmu_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_cpu2: tmu@10068000 {
                interrupts = <0 184 0>;
                clocks = <&clock CLK_TMU>, <&clock CLK_TMU>;
                clock-names = "tmu_apbif", "tmu_triminfo_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_cpu3: tmu@1006c000 {
                interrupts = <0 185 0>;
                clocks = <&clock CLK_TMU>, <&clock CLK_TMU_GPU>;
                clock-names = "tmu_apbif", "tmu_triminfo_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_gpu: tmu@100a0000 {
                interrupts = <0 215 0>;
                clocks = <&clock CLK_TMU_GPU>, <&clock CLK_TMU>;
                clock-names = "tmu_apbif", "tmu_triminfo_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
+       };
+
+       thermal-zones {
+               cpu0_thermal: cpu0-thermal {
+                       thermal-sensors = <&tmu_cpu0>;
+                       #include "exynos5420-trip-points.dtsi"
+               };
+               cpu1_thermal: cpu1-thermal {
+                      thermal-sensors = <&tmu_cpu1>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
+               cpu2_thermal: cpu2-thermal {
+                      thermal-sensors = <&tmu_cpu2>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
+               cpu3_thermal: cpu3-thermal {
+                      thermal-sensors = <&tmu_cpu3>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
+               gpu_thermal: gpu-thermal {
+                      thermal-sensors = <&tmu_gpu>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
        };
 
         watchdog: watchdog@101D0000 {
diff --git a/arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi b/arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi
new file mode 100644 (file)
index 0000000..7b2fba0
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Device tree sources for Exynos5440 TMU sensor configuration
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@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 <dt-bindings/thermal/thermal_exynos.h>
+
+#thermal-sensor-cells = <0>;
+samsung,tmu_gain = <5>;
+samsung,tmu_reference_voltage = <16>;
+samsung,tmu_noise_cancel_mode = <4>;
+samsung,tmu_efuse_value = <0x5d2d>;
+samsung,tmu_min_efuse_value = <16>;
+samsung,tmu_max_efuse_value = <76>;
+samsung,tmu_first_point_trim = <25>;
+samsung,tmu_second_point_trim = <70>;
+samsung,tmu_default_temp_offset = <25>;
+samsung,tmu_cal_type = <TYPE_ONE_POINT_TRIMMING>;
diff --git a/arch/arm/boot/dts/exynos5440-trip-points.dtsi b/arch/arm/boot/dts/exynos5440-trip-points.dtsi
new file mode 100644 (file)
index 0000000..48adfa8
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Device tree sources for default Exynos5440 thermal zone definition
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@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.
+ *
+ */
+
+polling-delay-passive = <0>;
+polling-delay = <0>;
+trips {
+       cpu-alert-0 {
+               temperature = <100000>; /* millicelsius */
+               hysteresis = <0>; /* millicelsius */
+               type = "active";
+       };
+       cpu-crit-0 {
+               temperature = <1050000>; /* millicelsius */
+               hysteresis = <0>; /* millicelsius */
+               type = "critical";
+       };
+};
index 8f3373cd7b878b79f2e499518a7ec774ffd06db8..59d9416b3b03f042cd05c412736c1fd432440747 100644 (file)
                interrupts = <0 58 0>;
                clocks = <&clock CLK_B_125>;
                clock-names = "tmu_apbif";
+               #include "exynos5440-tmu-sensor-conf.dtsi"
        };
 
        tmuctrl_1: tmuctrl@16011C {
                interrupts = <0 58 0>;
                clocks = <&clock CLK_B_125>;
                clock-names = "tmu_apbif";
+               #include "exynos5440-tmu-sensor-conf.dtsi"
        };
 
        tmuctrl_2: tmuctrl@160120 {
                interrupts = <0 58 0>;
                clocks = <&clock CLK_B_125>;
                clock-names = "tmu_apbif";
+               #include "exynos5440-tmu-sensor-conf.dtsi"
+       };
+
+       thermal-zones {
+               cpu0_thermal: cpu0-thermal {
+                       thermal-sensors = <&tmuctrl_0>;
+                       #include "exynos5440-trip-points.dtsi"
+               };
+               cpu1_thermal: cpu1-thermal {
+                      thermal-sensors = <&tmuctrl_1>;
+                      #include "exynos5440-trip-points.dtsi"
+               };
+               cpu2_thermal: cpu2-thermal {
+                      thermal-sensors = <&tmuctrl_2>;
+                      #include "exynos5440-trip-points.dtsi"
+               };
        };
 
        sata@210000 {
index f1cd2147421d2e0f82e2a921cc5c449d8ff6d1b4..a626e6dd8022c04defdbc56171147c04027aa48b 100644 (file)
@@ -35,6 +35,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio3 22 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_usb_h1_vbus: regulator@1 {
@@ -45,6 +46,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio1 29 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_audio: regulator@2 {
index fda4932faefda2f0b847547f15954a94347d5c40..945887d3fdb35a6588155590474479901a45671f 100644 (file)
@@ -52,6 +52,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio4 0 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_usb_otg2_vbus: regulator@1 {
@@ -62,6 +63,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio4 2 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_aud3v: regulator@2 {
index 59d1c297bb30f17aaab458f94e6ba52363c635cb..578fa2a54dce35482ba2d7b7fd1d42ce67a762ac 100644 (file)
@@ -87,8 +87,8 @@
                                     <14>,
                                     <15>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <64>;
+                       dma-channels = <32>;
+                       dma-requests = <64>;
                };
 
                i2c1: i2c@48070000 {
index 60403273f83e6918483641884707c8f5bd546d1e..db80f9d376fadf569655fc9660526b16b0c10739 100644 (file)
        model = "Nokia N900";
        compatible = "nokia,omap3-n900", "ti,omap3430", "ti,omap3";
 
+       aliases {
+               i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+       };
+
        cpus {
                cpu@0 {
                        cpu0-supply = <&vcc>;
                compatible = "smsc,lan91c94";
                interrupt-parent = <&gpio2>;
                interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;  /* gpio54 */
-               reg = <1 0x300 0xf>;            /* 16 byte IO range at offset 0x300 */
+               reg = <1 0 0xf>;                /* 16 byte IO range */
                bank-width = <2>;
                pinctrl-names = "default";
                pinctrl-0 = <&ethernet_pins>;
index 01b71111bd558738595fde6deaa71b05c4c08e9a..3fdc84fddb70d06a2ae26db02fc2c9c9f6d8ee63 100644 (file)
@@ -92,6 +92,8 @@
                        ti,hwmods = "aes";
                        reg = <0x480c5000 0x50>;
                        interrupts = <0>;
+                       dmas = <&sdma 65 &sdma 66>;
+                       dma-names = "tx", "rx";
                };
 
                prm: prm@48306000 {
                                     <14>,
                                     <15>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <96>;
+                       dma-channels = <32>;
+                       dma-requests = <96>;
                };
 
                omap3_pmx_core: pinmux@48002030 {
                        ti,hwmods = "sham";
                        reg = <0x480c3000 0x64>;
                        interrupts = <49>;
+                       dmas = <&sdma 69>;
+                       dma-names = "rx";
                };
 
                smartreflex_core: smartreflex@480cb000 {
index 074147cebae49f965b254915240b667bffcf9d21..87401d9f4d8b02314323e5a46ee38e5b0c6e4523 100644 (file)
                                     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <127>;
+                       dma-channels = <32>;
+                       dma-requests = <127>;
                };
 
                gpio1: gpio@4a310000 {
index 19212ac6eef054e62e52454c8548a196ca08cafa..de8a3d456cf7de0e3252074e9fb4e3fcb2eca80a 100644 (file)
@@ -13,7 +13,7 @@
 
 core_thermal: core_thermal {
        polling-delay-passive = <250>; /* milliseconds */
-       polling-delay = <1000>; /* milliseconds */
+       polling-delay = <500>; /* milliseconds */
 
                        /* sensor       ID */
        thermal-sensors = <&bandgap     2>;
index 1b87aca88b77130991bb4155331983792116ddeb..bc3090f2e84b3bea10779becd939d5e9555fbffe 100644 (file)
@@ -13,7 +13,7 @@
 
 gpu_thermal: gpu_thermal {
        polling-delay-passive = <250>; /* milliseconds */
-       polling-delay = <1000>; /* milliseconds */
+       polling-delay = <500>; /* milliseconds */
 
                        /* sensor       ID */
        thermal-sensors = <&bandgap     1>;
index b321fdf42c9f3c51e3a59d4b51b27a08f4fcaba4..4a485b63a1413bf8cfda0f027ed5e7a903c68066 100644 (file)
                                     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <127>;
+                       dma-channels = <32>;
+                       dma-requests = <127>;
                };
 
                gpio1: gpio@4ae10000 {
                                      <0x4A096800 0x40>; /* pll_ctrl */
                                reg-names = "phy_rx", "phy_tx", "pll_ctrl";
                                ctrl-module = <&omap_control_sata>;
-                               clocks = <&sys_clkin>;
-                               clock-names = "sysclk";
+                               clocks = <&sys_clkin>, <&sata_ref_clk>;
+                               clock-names = "sysclk", "refclk";
                                #phy-cells = <0>;
                        };
                };
        };
 };
 
+&cpu_thermal {
+       polling-delay = <500>; /* milliseconds */
+};
+
 /include/ "omap54xx-clocks.dtsi"
index 58c27466f01262a6f9ecee2058fb11dff9b5df3f..83b425fb3ac20eb1421cede5283b6a3befcdd391 100644 (file)
                ti,index-starts-at-one;
        };
 
+       dpll_core_byp_mux: dpll_core_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x012c>;
+       };
+
        dpll_core_ck: dpll_core_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-core-clock";
-               clocks = <&sys_clkin>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin>, <&dpll_core_byp_mux>;
                reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_iva_byp_mux: dpll_iva_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&iva_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x01ac>;
+       };
+
        dpll_iva_ck: dpll_iva_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin>, <&iva_dpll_hs_clk_div>;
+               clocks = <&sys_clkin>, <&dpll_iva_byp_mux>;
                reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>;
        };
 
        };
 };
 &cm_core_clocks {
+
+       dpll_per_byp_mux: dpll_per_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&per_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x014c>;
+       };
+
        dpll_per_ck: dpll_per_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin>, <&per_dpll_hs_clk_div>;
+               clocks = <&sys_clkin>, <&dpll_per_byp_mux>;
                reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>;
        };
 
                ti,index-starts-at-one;
        };
 
+       dpll_usb_byp_mux: dpll_usb_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&usb_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x018c>;
+       };
+
        dpll_usb_ck: dpll_usb_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-j-type-clock";
-               clocks = <&sys_clkin>, <&usb_dpll_hs_clk_div>;
+               clocks = <&sys_clkin>, <&dpll_usb_byp_mux>;
                reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>;
        };
 
index d771f687a13b50abad6f87ad6fb476e1d4377da9..eccc78d3220ba2e59e2994dfb4f5f20d3d3f7a91 100644 (file)
                        "mac_clk_rx", "mac_clk_tx",
                        "clk_mac_ref", "clk_mac_refout",
                        "aclk_mac", "pclk_mac";
+               status = "disabled";
        };
 
        usb_host0_ehci: usb@ff500000 {
index 261311bdf65bcb601ee5824b57ea3dcf68920db2..367af53c1b8437d30059b32abff7dd3ed7a0c992 100644 (file)
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00700000 0x100000>;
                        interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "uhpck";
                        status = "disabled";
                };
index d986b41b965495bce29dc0d610a715ff4ffc0208..4303874889c69954fa894ff458bb9bfb492f33d4 100644 (file)
@@ -66,6 +66,7 @@
                gpio4 = &pioE;
                tcb0 = &tcb0;
                tcb1 = &tcb1;
+               i2c0 = &i2c0;
                i2c2 = &i2c2;
        };
        cpus {
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00600000 0x100000>;
                        interrupts = <46 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "uhpck";
                        status = "disabled";
                };
 
                                        lcdck: lcdck {
                                                #clock-cells = <0>;
-                                               reg = <4>;
-                                               clocks = <&smd>;
+                                               reg = <3>;
+                                               clocks = <&mck>;
                                        };
 
                                        smdck: smdck {
                                                reg = <50>;
                                        };
 
-                                       lcd_clk: lcd_clk {
+                                       lcdc_clk: lcdc_clk {
                                                #clock-cells = <0>;
                                                reg = <51>;
                                        };
index 252c3d1bda501f0814b73f6fa5e267c177cbff75..d9176e6061731b7c42ee792338fab3509482c603 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0xfff01000 0x1000>;
-                       interrupts = <0 156 4>;
+                       interrupts = <0 155 4>;
                        num-cs = <4>;
                        clocks = <&spi_m_clk>;
                        status = "disabled";
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&l4_sp_clk>;
+                       dmas = <&pdma 28>,
+                              <&pdma 29>;
+                       dma-names = "tx", "rx";
                };
 
                uart1: serial1@ffc03000 {
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&l4_sp_clk>;
+                       dmas = <&pdma 30>,
+                              <&pdma 31>;
+                       dma-names = "tx", "rx";
                };
 
                rst: rstmgr@ffd05000 {
index ab7891c43231de889f40efb79f7a064577c2d6ec..75742f8f96f3d1800d803a7fc2b2d3bd352413f5 100644 (file)
        model = "Olimex A10-OLinuXino-LIME";
        compatible = "olimex,a10-olinuxino-lime", "allwinner,sun4i-a10";
 
+       cpus {
+               cpu0: cpu@0 {
+                       /*
+                        * The A10-Lime is known to be unstable
+                        * when running at 1008 MHz
+                        */
+                       operating-points = <
+                               /* kHz    uV */
+                               912000  1350000
+                               864000  1300000
+                               624000  1250000
+                               >;
+                       cooling-max-level = <2>;
+               };
+       };
+
        soc@01c00000 {
                emac: ethernet@01c0b000 {
                        pinctrl-names = "default";
index 5c2925831f2038318258003ae6cd3736da71c0de..eebb7853e00bbad39916e804453929a2935cc831 100644 (file)
@@ -75,7 +75,6 @@
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1056000 1500000
                                1008000 1400000
                                912000  1350000
                                864000  1300000
@@ -83,7 +82,7 @@
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <4>;
+                       cooling-max-level = <3>;
                };
        };
 
index f8818f1edbbef27f16adadc139b8e46ae49823ad..883cb4873688f2f80ce3036ca2a60f338aa4bb67 100644 (file)
@@ -47,7 +47,6 @@
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1104000 1500000
                                1008000 1400000
                                912000  1350000
                                864000  1300000
@@ -57,7 +56,7 @@
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <6>;
+                       cooling-max-level = <5>;
                };
        };
 
index 3a8530b79f1c46200d2b7ee8bbe343198c7106d8..fdd181792b4beeb553ab55e275361d6bd6ecab07 100644 (file)
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1008000 1450000
                                960000  1400000
                                912000  1400000
                                864000  1300000
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <7>;
+                       cooling-max-level = <6>;
                };
 
                cpu@1 {
index f2670f638e97564ac8e3a01ea5bc9a1cbc24be6f..811e72bbe6429b6e6a18ac5c31c267c178d17714 100644 (file)
@@ -70,6 +70,7 @@ CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
+CONFIG_ARM_AT91_ETHER=y
 CONFIG_MACB=y
 # CONFIG_NET_VENDOR_BROADCOM is not set
 CONFIG_DM9000=y
index e8a4c955241b88e38dfda2cc91d17b701ca6935a..06075b6d246364db1c57b1e8860e6f675d1857c5 100644 (file)
@@ -62,6 +62,17 @@ CONFIG_MACH_SPEAR1340=y
 CONFIG_ARCH_STI=y
 CONFIG_ARCH_EXYNOS=y
 CONFIG_EXYNOS5420_MCPM=y
+CONFIG_ARCH_SHMOBILE_MULTI=y
+CONFIG_ARCH_EMEV2=y
+CONFIG_ARCH_R7S72100=y
+CONFIG_ARCH_R8A73A4=y
+CONFIG_ARCH_R8A7740=y
+CONFIG_ARCH_R8A7779=y
+CONFIG_ARCH_R8A7790=y
+CONFIG_ARCH_R8A7791=y
+CONFIG_ARCH_R8A7794=y
+CONFIG_ARCH_SH73A0=y
+CONFIG_MACH_MARZEN=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_SIRF=y
 CONFIG_ARCH_TEGRA=y
@@ -84,9 +95,11 @@ CONFIG_PCI_KEYSTONE=y
 CONFIG_PCI_MSI=y
 CONFIG_PCI_MVEBU=y
 CONFIG_PCI_TEGRA=y
+CONFIG_PCI_RCAR_GEN2=y
+CONFIG_PCI_RCAR_GEN2_PCIE=y
 CONFIG_PCIEPORTBUS=y
 CONFIG_SMP=y
-CONFIG_NR_CPUS=8
+CONFIG_NR_CPUS=16
 CONFIG_HIGHPTE=y
 CONFIG_CMA=y
 CONFIG_ARM_APPENDED_DTB=y
@@ -130,6 +143,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_OMAP_OCP2SCP=y
+CONFIG_SIMPLE_PM_BUS=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -157,6 +171,7 @@ CONFIG_AHCI_SUNXI=y
 CONFIG_AHCI_TEGRA=y
 CONFIG_SATA_HIGHBANK=y
 CONFIG_SATA_MV=y
+CONFIG_SATA_RCAR=y
 CONFIG_NETDEVICES=y
 CONFIG_HIX5HD2_GMAC=y
 CONFIG_SUN4I_EMAC=y
@@ -167,14 +182,17 @@ CONFIG_MV643XX_ETH=y
 CONFIG_MVNETA=y
 CONFIG_KS8851=y
 CONFIG_R8169=y
+CONFIG_SH_ETH=y
 CONFIG_SMSC911X=y
 CONFIG_STMMAC_ETH=y
 CONFIG_TI_CPSW=y
 CONFIG_XILINX_EMACLITE=y
 CONFIG_AT803X_PHY=y
 CONFIG_MARVELL_PHY=y
+CONFIG_SMSC_PHY=y
 CONFIG_BROADCOM_PHY=y
 CONFIG_ICPLUS_PHY=y
+CONFIG_MICREL_PHY=y
 CONFIG_USB_PEGASUS=y
 CONFIG_USB_USBNET=y
 CONFIG_USB_NET_SMSC75XX=y
@@ -192,15 +210,18 @@ CONFIG_KEYBOARD_CROS_EC=y
 CONFIG_MOUSE_PS2_ELANTECH=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_ST1232=m
 CONFIG_TOUCHSCREEN_STMPE=y
 CONFIG_TOUCHSCREEN_SUN4I=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_MPU3050=y
 CONFIG_INPUT_AXP20X_PEK=y
+CONFIG_INPUT_ADXL34X=m
 CONFIG_SERIO_AMBAKMI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_EM=y
 CONFIG_SERIAL_8250_MT6577=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
@@ -213,6 +234,9 @@ CONFIG_SERIAL_SIRFSOC_CONSOLE=y
 CONFIG_SERIAL_TEGRA=y
 CONFIG_SERIAL_IMX=y
 CONFIG_SERIAL_IMX_CONSOLE=y
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=20
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_VT8500=y
@@ -233,19 +257,26 @@ CONFIG_I2C_MUX_PCA954x=y
 CONFIG_I2C_MUX_PINCTRL=y
 CONFIG_I2C_CADENCE=y
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_I2C_GPIO=m
 CONFIG_I2C_EXYNOS5=y
 CONFIG_I2C_MV64XXX=y
+CONFIG_I2C_RIIC=y
 CONFIG_I2C_S3C2410=y
+CONFIG_I2C_SH_MOBILE=y
 CONFIG_I2C_SIRF=y
-CONFIG_I2C_TEGRA=y
 CONFIG_I2C_ST=y
-CONFIG_SPI=y
+CONFIG_I2C_TEGRA=y
 CONFIG_I2C_XILINX=y
-CONFIG_SPI_DAVINCI=y
+CONFIG_I2C_RCAR=y
+CONFIG_SPI=y
 CONFIG_SPI_CADENCE=y
+CONFIG_SPI_DAVINCI=y
 CONFIG_SPI_OMAP24XX=y
 CONFIG_SPI_ORION=y
 CONFIG_SPI_PL022=y
+CONFIG_SPI_RSPI=y
+CONFIG_SPI_SH_MSIOF=m
+CONFIG_SPI_SH_HSPI=y
 CONFIG_SPI_SIRF=y
 CONFIG_SPI_SUN4I=y
 CONFIG_SPI_SUN6I=y
@@ -259,12 +290,15 @@ CONFIG_PINCTRL_PALMAS=y
 CONFIG_PINCTRL_APQ8084=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_GENERIC_PLATFORM=y
-CONFIG_GPIO_DWAPB=y
 CONFIG_GPIO_DAVINCI=y
+CONFIG_GPIO_DWAPB=y
+CONFIG_GPIO_EM=y
+CONFIG_GPIO_RCAR=y
 CONFIG_GPIO_XILINX=y
 CONFIG_GPIO_ZYNQ=y
 CONFIG_GPIO_PCA953X=y
 CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_PCF857X=y
 CONFIG_GPIO_TWL4030=y
 CONFIG_GPIO_PALMAS=y
 CONFIG_GPIO_SYSCON=y
@@ -276,10 +310,12 @@ CONFIG_POWER_RESET_AS3722=y
 CONFIG_POWER_RESET_GPIO=y
 CONFIG_POWER_RESET_KEYSTONE=y
 CONFIG_POWER_RESET_SUN6I=y
+CONFIG_POWER_RESET_RMOBILE=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM95245=y
 CONFIG_THERMAL=y
 CONFIG_CPU_THERMAL=y
+CONFIG_RCAR_THERMAL=y
 CONFIG_ARMADA_THERMAL=y
 CONFIG_DAVINCI_WATCHDOG
 CONFIG_ST_THERMAL_SYSCFG=y
@@ -290,6 +326,7 @@ CONFIG_ARM_SP805_WATCHDOG=y
 CONFIG_ORION_WATCHDOG=y
 CONFIG_SUNXI_WATCHDOG=y
 CONFIG_MESON_WATCHDOG=y
+CONFIG_MFD_AS3711=y
 CONFIG_MFD_AS3722=y
 CONFIG_MFD_BCM590XX=y
 CONFIG_MFD_AXP20X=y
@@ -304,13 +341,16 @@ CONFIG_MFD_TPS65090=y
 CONFIG_MFD_TPS6586X=y
 CONFIG_MFD_TPS65910=y
 CONFIG_REGULATOR_AB8500=y
+CONFIG_REGULATOR_AS3711=y
 CONFIG_REGULATOR_AS3722=y
 CONFIG_REGULATOR_AXP20X=y
 CONFIG_REGULATOR_BCM590XX=y
+CONFIG_REGULATOR_DA9210=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MFD_SYSCON=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_REGULATOR_MAX8907=y
+CONFIG_REGULATOR_MAX8973=y
 CONFIG_REGULATOR_MAX77686=y
 CONFIG_REGULATOR_PALMAS=y
 CONFIG_REGULATOR_S2MPS11=y
@@ -324,18 +364,32 @@ CONFIG_REGULATOR_TWL4030=y
 CONFIG_REGULATOR_VEXPRESS=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=y
 CONFIG_USB_GSPCA=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=m
+CONFIG_SOC_CAMERA_PLATFORM=m
+CONFIG_VIDEO_RCAR_VIN=m
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_RENESAS_VSP1=m
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+CONFIG_VIDEO_ADV7180=m
 CONFIG_DRM=y
+CONFIG_DRM_RCAR_DU=m
 CONFIG_DRM_TEGRA=y
 CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_FB_ARMCLCD=y
 CONFIG_FB_WM8505=y
+CONFIG_FB_SH_MOBILE_LCDC=y
 CONFIG_FB_SIMPLE=y
+CONFIG_FB_SH_MOBILE_MERAM=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_AS3711=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_SOUND=y
@@ -343,6 +397,8 @@ CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
+CONFIG_SND_SOC_SH4_FSI=m
+CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SOC_TEGRA=y
 CONFIG_SND_SOC_TEGRA_RT5640=y
 CONFIG_SND_SOC_TEGRA_WM8753=y
@@ -350,6 +406,8 @@ CONFIG_SND_SOC_TEGRA_WM8903=y
 CONFIG_SND_SOC_TEGRA_TRIMSLICE=y
 CONFIG_SND_SOC_TEGRA_ALC5632=y
 CONFIG_SND_SOC_TEGRA_MAX98090=y
+CONFIG_SND_SOC_AK4642=m
+CONFIG_SND_SOC_WM8978=m
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_MVEBU=y
@@ -362,6 +420,8 @@ CONFIG_USB_ISP1760_HCD=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_STI=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_R8A66597_HCD=m
+CONFIG_USB_RENESAS_USBHS=m
 CONFIG_USB_STORAGE=y
 CONFIG_USB_DWC3=y
 CONFIG_USB_CHIPIDEA=y
@@ -374,6 +434,10 @@ CONFIG_SAMSUNG_USB3PHY=y
 CONFIG_USB_GPIO_VBUS=y
 CONFIG_USB_ISP1301=y
 CONFIG_USB_MXS_PHY=y
+CONFIG_USB_RCAR_PHY=m
+CONFIG_USB_RCAR_GEN2_PHY=m
+CONFIG_USB_GADGET=y
+CONFIG_USB_RENESAS_USBHS_UDC=m
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=16
 CONFIG_MMC_ARMMMCI=y
@@ -392,12 +456,14 @@ CONFIG_MMC_SDHCI_ST=y
 CONFIG_MMC_OMAP=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_MMC_MVSDIO=y
-CONFIG_MMC_SUNXI=y
+CONFIG_MMC_SDHI=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_IDMAC=y
 CONFIG_MMC_DW_PLTFM=y
 CONFIG_MMC_DW_EXYNOS=y
 CONFIG_MMC_DW_ROCKCHIP=y
+CONFIG_MMC_SH_MMCIF=y
+CONFIG_MMC_SUNXI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
@@ -421,10 +487,12 @@ CONFIG_RTC_DRV_AS3722=y
 CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_MAX8907=y
 CONFIG_RTC_DRV_MAX77686=y
+CONFIG_RTC_DRV_RS5C372=m
 CONFIG_RTC_DRV_PALMAS=y
 CONFIG_RTC_DRV_TWL4030=y
 CONFIG_RTC_DRV_TPS6586X=y
 CONFIG_RTC_DRV_TPS65910=y
+CONFIG_RTC_DRV_S35390A=m
 CONFIG_RTC_DRV_EM3027=y
 CONFIG_RTC_DRV_PL031=y
 CONFIG_RTC_DRV_VT8500=y
@@ -436,6 +504,9 @@ CONFIG_DMADEVICES=y
 CONFIG_DW_DMAC=y
 CONFIG_MV_XOR=y
 CONFIG_TEGRA20_APB_DMA=y
+CONFIG_SH_DMAE=y
+CONFIG_RCAR_AUDMAC_PP=m
+CONFIG_RCAR_DMAC=y
 CONFIG_STE_DMA40=y
 CONFIG_SIRF_DMA=y
 CONFIG_TI_EDMA=y
@@ -468,6 +539,7 @@ CONFIG_IIO=y
 CONFIG_XILINX_XADC=y
 CONFIG_AK8975=y
 CONFIG_PWM=y
+CONFIG_PWM_RENESAS_TPU=y
 CONFIG_PWM_TEGRA=y
 CONFIG_PWM_VT8500=y
 CONFIG_PHY_HIX5HD2_SATA=y
index b7386524c356619ceb9889553144e1292d2e1904..8e108599e1af401451aeeb01a9e6b7a1752c7c0d 100644 (file)
@@ -114,6 +114,7 @@ CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ECC_BCH=y
 CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_OMAP_BCH=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_VERIFY_WRITE=y
 CONFIG_MTD_ONENAND_OMAP2=y
@@ -248,6 +249,7 @@ CONFIG_TWL6040_CORE=y
 CONFIG_REGULATOR_PALMAS=y
 CONFIG_REGULATOR_PBIAS=y
 CONFIG_REGULATOR_TI_ABB=y
+CONFIG_REGULATOR_TPS62360=m
 CONFIG_REGULATOR_TPS65023=y
 CONFIG_REGULATOR_TPS6507X=y
 CONFIG_REGULATOR_TPS65217=y
@@ -374,7 +376,8 @@ CONFIG_PWM_TIEHRPWM=m
 CONFIG_PWM_TWL=m
 CONFIG_PWM_TWL_LED=m
 CONFIG_OMAP_USB2=m
-CONFIG_TI_PIPE3=m
+CONFIG_TI_PIPE3=y
+CONFIG_TWL4030_USB=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
index 41d856effe6cadcf928ddd6f6fd8efa6edbc951d..510c747c65b446b173fb241d15da8c16983a989e 100644 (file)
@@ -3,8 +3,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
index 38840a8129240f7e89af853521b9aa2bb398c40f..8f6a5702b69619eb6d332db0dbf45853b527faa4 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_PERF_EVENTS=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_SMP=y
+CONFIG_NR_CPUS=8
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_HIGHPTE=y
index f489fdaa19b8ff127944d6bde8a7e0fa806848c4..37fe607a4ede57755a112da4f17fdd8d4ae44f8a 100644 (file)
@@ -118,8 +118,8 @@ CONFIG_HID_ZEROPLUS=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_MON=y
-CONFIG_USB_ISP1760_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_ISP1760=y
 CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
 CONFIG_NEW_LEDS=y
index 71e5fc7cfb18f489f3adadb20c6f8049421fb079..1d1800f71c5b3d372d33ec1e43acdaa35e17d3be 100644 (file)
 # define VFP_ABI_FRAME 0
 # define BSAES_ASM_EXTENDED_KEY
 # define XTS_CHAIN_TWEAK
-# define __ARM_ARCH__  7
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_MAX_ARCH__ 7
 #endif
 
 #ifdef __thumb__
 # define adrl adr
 #endif
 
-#if __ARM_ARCH__>=7
+#if __ARM_MAX_ARCH__>=7
+.arch  armv7-a
+.fpu   neon
+
 .text
 .syntax        unified         @ ARMv7-capable assembler is expected to handle this
 #ifdef __thumb2__
@@ -74,8 +78,6 @@
 .code   32
 #endif
 
-.fpu   neon
-
 .type  _bsaes_decrypt8,%function
 .align 4
 _bsaes_decrypt8:
@@ -2095,9 +2097,11 @@ bsaes_xts_decrypt:
        vld1.8  {q8}, [r0]                      @ initial tweak
        adr     r2, .Lxts_magic
 
+#ifndef        XTS_CHAIN_TWEAK
        tst     r9, #0xf                        @ if not multiple of 16
        it      ne                              @ Thumb2 thing, sanity check in ARM
        subne   r9, #0x10                       @ subtract another 16 bytes
+#endif
        subs    r9, #0x80
 
        blo     .Lxts_dec_short
index be068db960ee0006ac1aa25a4e69b95265404844..a4d3856e7d2477ec6379f1f10a9121e32f36a974 100644 (file)
@@ -701,14 +701,18 @@ $code.=<<___;
 # define VFP_ABI_FRAME 0
 # define BSAES_ASM_EXTENDED_KEY
 # define XTS_CHAIN_TWEAK
-# define __ARM_ARCH__  7
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_MAX_ARCH__ 7
 #endif
 
 #ifdef __thumb__
 # define adrl adr
 #endif
 
-#if __ARM_ARCH__>=7
+#if __ARM_MAX_ARCH__>=7
+.arch  armv7-a
+.fpu   neon
+
 .text
 .syntax        unified         @ ARMv7-capable assembler is expected to handle this
 #ifdef __thumb2__
@@ -717,8 +721,6 @@ $code.=<<___;
 .code   32
 #endif
 
-.fpu   neon
-
 .type  _bsaes_decrypt8,%function
 .align 4
 _bsaes_decrypt8:
@@ -2076,9 +2078,11 @@ bsaes_xts_decrypt:
        vld1.8  {@XMM[8]}, [r0]                 @ initial tweak
        adr     $magic, .Lxts_magic
 
+#ifndef        XTS_CHAIN_TWEAK
        tst     $len, #0xf                      @ if not multiple of 16
        it      ne                              @ Thumb2 thing, sanity check in ARM
        subne   $len, #0x10                     @ subtract another 16 bytes
+#endif
        subs    $len, #0x80
 
        blo     .Lxts_dec_short
index 37ca2a4c6f0944598cacb0fbdab33c716258ea4e..4cf48c3aca13e9afe7b852660afa4d5945994a93 100644 (file)
@@ -149,29 +149,28 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
        (__boundary - 1 < (end) - 1)? __boundary: (end);                \
 })
 
+#define kvm_pgd_index(addr)                    pgd_index(addr)
+
 static inline bool kvm_page_empty(void *ptr)
 {
        struct page *ptr_page = virt_to_page(ptr);
        return page_count(ptr_page) == 1;
 }
 
-
 #define kvm_pte_table_empty(kvm, ptep) kvm_page_empty(ptep)
 #define kvm_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp)
 #define kvm_pud_table_empty(kvm, pudp) (0)
 
 #define KVM_PREALLOC_LEVEL     0
 
-static inline int kvm_prealloc_hwpgd(struct kvm *kvm, pgd_t *pgd)
+static inline void *kvm_get_hwpgd(struct kvm *kvm)
 {
-       return 0;
+       return kvm->arch.pgd;
 }
 
-static inline void kvm_free_hwpgd(struct kvm *kvm) { }
-
-static inline void *kvm_get_hwpgd(struct kvm *kvm)
+static inline unsigned int kvm_get_hwpgd_size(void)
 {
-       return kvm->arch.pgd;
+       return PTRS_PER_S2_PGD * sizeof(pgd_t);
 }
 
 struct kvm;
@@ -207,7 +206,7 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
 
        bool need_flush = !vcpu_has_cache_enabled(vcpu) || ipa_uncached;
 
-       VM_BUG_ON(size & PAGE_MASK);
+       VM_BUG_ON(size & ~PAGE_MASK);
 
        if (!need_flush && !icache_is_pipt())
                goto vipt_cache;
index 80a6501b4d5068ceed534f43ba3b1d59083d0b2a..c3c45e628e33bb9bf80a96014f1b510ede78580c 100644 (file)
 #define AT91_DBGU 0xfc00c000 /* SAMA5D4_BASE_USART3 */
 #endif
 
-/* Keep in sync with mach-at91/include/mach/hardware.h */
+#ifdef CONFIG_MMU
 #define AT91_IO_P2V(x) ((x) - 0x01000000)
+#else
+#define AT91_IO_P2V(x) (x)
+#endif
 
 #define AT91_DBGU_SR           (0x14)  /* Status Register */
 #define AT91_DBGU_THR          (0x1c)  /* Transmitter Holding Register */
index e55408e965596964ff8c8708dcfec529a559b1bc..1d60bebea4b8b7923748cd6eb2d25fc4299bfc32 100644 (file)
@@ -246,12 +246,9 @@ static int __get_cpu_architecture(void)
                if (cpu_arch)
                        cpu_arch += CPU_ARCH_ARMv3;
        } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
-               unsigned int mmfr0;
-
                /* Revised CPUID format. Read the Memory Model Feature
                 * Register 0 and check for VMSAv7 or PMSAv7 */
-               asm("mrc        p15, 0, %0, c0, c1, 4"
-                   : "=r" (mmfr0));
+               unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0);
                if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
                    (mmfr0 & 0x000000f0) >= 0x00000030)
                        cpu_arch = CPU_ARCH_ARMv7;
index 07e7eb1d7ab63b0417f8a54203620988b72228c4..5560f74f9eeef1e3e4d2c9c39fc672e539eee93f 100644 (file)
@@ -540,7 +540,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
                kvm_guest_exit();
-               trace_kvm_exit(*vcpu_pc(vcpu));
+               trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
                /*
                 * We may have taken a host interrupt in HYP mode (ie
                 * while executing the guest). This interrupt is still
index 3e6859bc3e1170fc83489be9ba51a15c97b148a5..5656d79c5a44f4d2ca816e15b647abf29a114e0b 100644 (file)
@@ -290,7 +290,7 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
        phys_addr_t addr = start, end = start + size;
        phys_addr_t next;
 
-       pgd = pgdp + pgd_index(addr);
+       pgd = pgdp + kvm_pgd_index(addr);
        do {
                next = kvm_pgd_addr_end(addr, end);
                if (!pgd_none(*pgd))
@@ -355,7 +355,7 @@ static void stage2_flush_memslot(struct kvm *kvm,
        phys_addr_t next;
        pgd_t *pgd;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        do {
                next = kvm_pgd_addr_end(addr, end);
                stage2_flush_puds(kvm, pgd, addr, next);
@@ -632,6 +632,20 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
                                     __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE);
 }
 
+/* Free the HW pgd, one page at a time */
+static void kvm_free_hwpgd(void *hwpgd)
+{
+       free_pages_exact(hwpgd, kvm_get_hwpgd_size());
+}
+
+/* Allocate the HW PGD, making sure that each page gets its own refcount */
+static void *kvm_alloc_hwpgd(void)
+{
+       unsigned int size = kvm_get_hwpgd_size();
+
+       return alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
+}
+
 /**
  * kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
  * @kvm:       The KVM struct pointer for the VM.
@@ -645,15 +659,31 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
  */
 int kvm_alloc_stage2_pgd(struct kvm *kvm)
 {
-       int ret;
        pgd_t *pgd;
+       void *hwpgd;
 
        if (kvm->arch.pgd != NULL) {
                kvm_err("kvm_arch already initialized?\n");
                return -EINVAL;
        }
 
+       hwpgd = kvm_alloc_hwpgd();
+       if (!hwpgd)
+               return -ENOMEM;
+
+       /* When the kernel uses more levels of page tables than the
+        * guest, we allocate a fake PGD and pre-populate it to point
+        * to the next-level page table, which will be the real
+        * initial page table pointed to by the VTTBR.
+        *
+        * When KVM_PREALLOC_LEVEL==2, we allocate a single page for
+        * the PMD and the kernel will use folded pud.
+        * When KVM_PREALLOC_LEVEL==1, we allocate 2 consecutive PUD
+        * pages.
+        */
        if (KVM_PREALLOC_LEVEL > 0) {
+               int i;
+
                /*
                 * Allocate fake pgd for the page table manipulation macros to
                 * work.  This is not used by the hardware and we have no
@@ -661,30 +691,32 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
                 */
                pgd = (pgd_t *)kmalloc(PTRS_PER_S2_PGD * sizeof(pgd_t),
                                       GFP_KERNEL | __GFP_ZERO);
+
+               if (!pgd) {
+                       kvm_free_hwpgd(hwpgd);
+                       return -ENOMEM;
+               }
+
+               /* Plug the HW PGD into the fake one. */
+               for (i = 0; i < PTRS_PER_S2_PGD; i++) {
+                       if (KVM_PREALLOC_LEVEL == 1)
+                               pgd_populate(NULL, pgd + i,
+                                            (pud_t *)hwpgd + i * PTRS_PER_PUD);
+                       else if (KVM_PREALLOC_LEVEL == 2)
+                               pud_populate(NULL, pud_offset(pgd, 0) + i,
+                                            (pmd_t *)hwpgd + i * PTRS_PER_PMD);
+               }
        } else {
                /*
                 * Allocate actual first-level Stage-2 page table used by the
                 * hardware for Stage-2 page table walks.
                 */
-               pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, S2_PGD_ORDER);
+               pgd = (pgd_t *)hwpgd;
        }
 
-       if (!pgd)
-               return -ENOMEM;
-
-       ret = kvm_prealloc_hwpgd(kvm, pgd);
-       if (ret)
-               goto out_err;
-
        kvm_clean_pgd(pgd);
        kvm->arch.pgd = pgd;
        return 0;
-out_err:
-       if (KVM_PREALLOC_LEVEL > 0)
-               kfree(pgd);
-       else
-               free_pages((unsigned long)pgd, S2_PGD_ORDER);
-       return ret;
 }
 
 /**
@@ -785,11 +817,10 @@ void kvm_free_stage2_pgd(struct kvm *kvm)
                return;
 
        unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
-       kvm_free_hwpgd(kvm);
+       kvm_free_hwpgd(kvm_get_hwpgd(kvm));
        if (KVM_PREALLOC_LEVEL > 0)
                kfree(kvm->arch.pgd);
-       else
-               free_pages((unsigned long)kvm->arch.pgd, S2_PGD_ORDER);
+
        kvm->arch.pgd = NULL;
 }
 
@@ -799,7 +830,7 @@ static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache
        pgd_t *pgd;
        pud_t *pud;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        if (WARN_ON(pgd_none(*pgd))) {
                if (!cache)
                        return NULL;
@@ -1089,7 +1120,7 @@ static void stage2_wp_range(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)
        pgd_t *pgd;
        phys_addr_t next;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        do {
                /*
                 * Release kvm_mmu_lock periodically if the memory region is
index 881874b1a036ce117e01c2c6e124b28fb2506b89..6817664b46b80419047066686a47a8bc7953ebeb 100644 (file)
@@ -25,18 +25,22 @@ TRACE_EVENT(kvm_entry,
 );
 
 TRACE_EVENT(kvm_exit,
-       TP_PROTO(unsigned long vcpu_pc),
-       TP_ARGS(vcpu_pc),
+       TP_PROTO(unsigned int exit_reason, unsigned long vcpu_pc),
+       TP_ARGS(exit_reason, vcpu_pc),
 
        TP_STRUCT__entry(
+               __field(        unsigned int,   exit_reason     )
                __field(        unsigned long,  vcpu_pc         )
        ),
 
        TP_fast_assign(
+               __entry->exit_reason            = exit_reason;
                __entry->vcpu_pc                = vcpu_pc;
        ),
 
-       TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
+       TP_printk("HSR_EC: 0x%04x, PC: 0x%08lx",
+                 __entry->exit_reason,
+                 __entry->vcpu_pc)
 );
 
 TRACE_EVENT(kvm_guest_fault,
index 8423be76080eaa293e8f1d36f740548ddbad6973..52241207a82a3d3a802a90c1fe47e78150e8d5ba 100644 (file)
@@ -2,5 +2,7 @@ config MACH_ASM9260
        bool "Alphascale ASM9260"
        depends on ARCH_MULTI_V5
        select CPU_ARM926T
+       select ASM9260_TIMER
+       select GENERIC_CLOCKEVENTS
        help
          Support for Alphascale ASM9260 based platform.
index 5e34fb1433098aee3916f2b4c3019a14d2aa5ba8..aa4116e9452f725e0f63241cfc083576c665be19 100644 (file)
@@ -270,37 +270,35 @@ static void __init at91_pm_sram_init(void)
        phys_addr_t sram_pbase;
        unsigned long sram_base;
        struct device_node *node;
-       struct platform_device *pdev;
+       struct platform_device *pdev = NULL;
 
-       node = of_find_compatible_node(NULL, NULL, "mmio-sram");
-       if (!node) {
-               pr_warn("%s: failed to find sram node!\n", __func__);
-               return;
+       for_each_compatible_node(node, NULL, "mmio-sram") {
+               pdev = of_find_device_by_node(node);
+               if (pdev) {
+                       of_node_put(node);
+                       break;
+               }
        }
 
-       pdev = of_find_device_by_node(node);
        if (!pdev) {
                pr_warn("%s: failed to find sram device!\n", __func__);
-               goto put_node;
+               return;
        }
 
        sram_pool = dev_get_gen_pool(&pdev->dev);
        if (!sram_pool) {
                pr_warn("%s: sram pool unavailable!\n", __func__);
-               goto put_node;
+               return;
        }
 
        sram_base = gen_pool_alloc(sram_pool, at91_slow_clock_sz);
        if (!sram_base) {
                pr_warn("%s: unable to alloc ocram!\n", __func__);
-               goto put_node;
+               return;
        }
 
        sram_pbase = gen_pool_virt_to_phys(sram_pool, sram_base);
        slow_clock = __arm_ioremap_exec(sram_pbase, at91_slow_clock_sz, false);
-
-put_node:
-       of_node_put(node);
 }
 #endif
 
index d2c89963af2d168179e01e72d51f6684decc8d5e..86c0aa819d2590aae5af7146e5e3a4ebeb086e35 100644 (file)
@@ -44,7 +44,7 @@ static inline void at91rm9200_standby(void)
                "    mcr    p15, 0, %0, c7, c0, 4\n\t"
                "    str    %5, [%1, %2]"
                :
-               : "r" (0), "r" (AT91_BASE_SYS), "r" (AT91RM9200_SDRAMC_LPR),
+               : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91RM9200_SDRAMC_LPR),
                  "r" (1), "r" (AT91RM9200_SDRAMC_SRR),
                  "r" (lpr));
 }
index 556151e85ec4c71712373098ce731c68674a757b..931f0e302c035ecc33a138ec0bd61dc910321c66 100644 (file)
  */
 #undef SLOWDOWN_MASTER_CLOCK
 
-#define MCKRDY_TIMEOUT         1000
-#define MOSCRDY_TIMEOUT        1000
-#define PLLALOCK_TIMEOUT       1000
-#define PLLBLOCK_TIMEOUT       1000
-
 pmc    .req    r0
 sdramc .req    r1
 ramc1  .req    r2
@@ -41,60 +36,42 @@ tmp2        .req    r5
  * Wait until master clock is ready (after switching master clock source)
  */
        .macro wait_mckrdy
-       mov     tmp2, #MCKRDY_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_MCKRDY
        beq     1b
-2:
        .endm
 
 /*
  * Wait until master oscillator has stabilized.
  */
        .macro wait_moscrdy
-       mov     tmp2, #MOSCRDY_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_MOSCS
        beq     1b
-2:
        .endm
 
 /*
  * Wait until PLLA has locked.
  */
        .macro wait_pllalock
-       mov     tmp2, #PLLALOCK_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_LOCKA
        beq     1b
-2:
        .endm
 
 /*
  * Wait until PLLB has locked.
  */
        .macro wait_pllblock
-       mov     tmp2, #PLLBLOCK_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_LOCKB
        beq     1b
-2:
        .endm
 
        .text
 
+       .arm
+
 /* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc,
  *                     void __iomem *ramc1, int memctrl)
  */
@@ -134,6 +111,16 @@ ddr_sr_enable:
        cmp     memctrl, #AT91_MEMCTRL_DDRSDR
        bne     sdr_sr_enable
 
+       /* LPDDR1 --> force DDR2 mode during self-refresh */
+       ldr     tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+       str     tmp1, .saved_sam9_mdr
+       bic     tmp1, tmp1, #~AT91_DDRSDRC_MD
+       cmp     tmp1, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+       ldreq   tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+       biceq   tmp1, tmp1, #AT91_DDRSDRC_MD
+       orreq   tmp1, tmp1, #AT91_DDRSDRC_MD_DDR2
+       streq   tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+
        /* prepare for DDRAM self-refresh mode */
        ldr     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
        str     tmp1, .saved_sam9_lpr
@@ -142,14 +129,26 @@ ddr_sr_enable:
 
        /* figure out if we use the second ram controller */
        cmp     ramc1, #0
-       ldrne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
-       strne   tmp2, .saved_sam9_lpr1
-       bicne   tmp2, #AT91_DDRSDRC_LPCB
-       orrne   tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+       beq     ddr_no_2nd_ctrl
+
+       ldr     tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+       str     tmp2, .saved_sam9_mdr1
+       bic     tmp2, tmp2, #~AT91_DDRSDRC_MD
+       cmp     tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+       ldreq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+       biceq   tmp2, tmp2, #AT91_DDRSDRC_MD
+       orreq   tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
+       streq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+
+       ldr     tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+       str     tmp2, .saved_sam9_lpr1
+       bic     tmp2, #AT91_DDRSDRC_LPCB
+       orr     tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
        /* Enable DDRAM self-refresh mode */
+       str     tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+ddr_no_2nd_ctrl:
        str     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
-       strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
        b       sdr_sr_done
 
@@ -208,6 +207,7 @@ sdr_sr_done:
        /* Turn off the main oscillator */
        ldr     tmp1, [pmc, #AT91_CKGR_MOR]
        bic     tmp1, tmp1, #AT91_PMC_MOSCEN
+       orr     tmp1, tmp1, #AT91_PMC_KEY
        str     tmp1, [pmc, #AT91_CKGR_MOR]
 
        /* Wait for interrupt */
@@ -216,6 +216,7 @@ sdr_sr_done:
        /* Turn on the main oscillator */
        ldr     tmp1, [pmc, #AT91_CKGR_MOR]
        orr     tmp1, tmp1, #AT91_PMC_MOSCEN
+       orr     tmp1, tmp1, #AT91_PMC_KEY
        str     tmp1, [pmc, #AT91_CKGR_MOR]
 
        wait_moscrdy
@@ -280,12 +281,17 @@ sdr_sr_done:
         */
        cmp     memctrl, #AT91_MEMCTRL_DDRSDR
        bne     sdr_en_restore
+       /* Restore MDR in case of LPDDR1 */
+       ldr     tmp1, .saved_sam9_mdr
+       str     tmp1, [sdramc, #AT91_DDRSDRC_MDR]
        /* Restore LPR on AT91 with DDRAM */
        ldr     tmp1, .saved_sam9_lpr
        str     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
 
        /* if we use the second ram controller */
        cmp     ramc1, #0
+       ldrne   tmp2, .saved_sam9_mdr1
+       strne   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
        ldrne   tmp2, .saved_sam9_lpr1
        strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
@@ -319,5 +325,11 @@ ram_restored:
 .saved_sam9_lpr1:
        .word 0
 
+.saved_sam9_mdr:
+       .word 0
+
+.saved_sam9_mdr1:
+       .word 0
+
 ENTRY(at91_slow_clock_sz)
        .word .-at91_slow_clock
index 3f32c47a6d74e780f429e5a9331c0737c2cb64d7..d2e9f12d12f187e1e2c40f11748f75bbe0a283f2 100644 (file)
@@ -126,8 +126,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
  */
 void exynos_cpu_power_down(int cpu)
 {
-       if (cpu == 0 && (of_machine_is_compatible("samsung,exynos5420") ||
-               of_machine_is_compatible("samsung,exynos5800"))) {
+       if (cpu == 0 && (soc_is_exynos5420() || soc_is_exynos5800())) {
                /*
                 * Bypass power down for CPU0 during suspend. Check for
                 * the SYS_PWR_REG value to decide if we are suspending
index 20f267121b3e7876e4ab806ab6c2f655e9467499..37266a8264372a9d8ab898aec6389476f707869f 100644 (file)
@@ -161,6 +161,34 @@ no_clk:
                of_genpd_add_provider_simple(np, &pd->pd);
        }
 
+       /* Assign the child power domains to their parents */
+       for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") {
+               struct generic_pm_domain *child_domain, *parent_domain;
+               struct of_phandle_args args;
+
+               args.np = np;
+               args.args_count = 0;
+               child_domain = of_genpd_get_from_provider(&args);
+               if (!child_domain)
+                       continue;
+
+               if (of_parse_phandle_with_args(np, "power-domains",
+                                        "#power-domain-cells", 0, &args) != 0)
+                       continue;
+
+               parent_domain = of_genpd_get_from_provider(&args);
+               if (!parent_domain)
+                       continue;
+
+               if (pm_genpd_add_subdomain(parent_domain, child_domain))
+                       pr_warn("%s failed to add subdomain: %s\n",
+                               parent_domain->name, child_domain->name);
+               else
+                       pr_info("%s has as child subdomain: %s.\n",
+                               parent_domain->name, child_domain->name);
+               of_node_put(np);
+       }
+
        return 0;
 }
 arch_initcall(exynos4_pm_init_power_domain);
index 52e2b1a2fddbfcf7485d1c504c4e66cec3609388..318d127df147c2515f5ecb6674bec31423d790b1 100644 (file)
@@ -87,8 +87,8 @@ static unsigned int exynos_pmu_spare3;
 static u32 exynos_irqwake_intmask = 0xffffffff;
 
 static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
-       { 73, BIT(1) }, /* RTC alarm */
-       { 74, BIT(2) }, /* RTC tick */
+       { 105, BIT(1) }, /* RTC alarm */
+       { 106, BIT(2) }, /* RTC tick */
        { /* sentinel */ },
 };
 
index 4ad6e473cf83ab82e3a769ddcae8956762f47be9..9de3412af4063ccd4ae7b8f2a176e9300020947a 100644 (file)
@@ -211,8 +211,9 @@ static void __init imx6q_1588_init(void)
         * set bit IOMUXC_GPR1[21].  Or the PTP clock must be from pad
         * (external OSC), and we need to clear the bit.
         */
-       clksel = ptp_clk == enet_ref ? IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
-                                      IMX6Q_GPR1_ENET_CLK_SEL_PAD;
+       clksel = clk_is_match(ptp_clk, enet_ref) ?
+                               IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
+                               IMX6Q_GPR1_ENET_CLK_SEL_PAD;
        gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
        if (!IS_ERR(gpr))
                regmap_update_bits(gpr, IOMUXC_GPR1,
index 61bfe584a9d7fad4a7204d3ddb2a0a42afe3a23b..fc832040c6e979f139e272c73a47d167a65d8df5 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/smc91x.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -46,15 +47,20 @@ static struct resource smc91x_resources[] = {
        [1] = {
                .start  = MSM_GPIO_TO_INT(49),
                .end    = MSM_GPIO_TO_INT(49),
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
        },
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static struct platform_device *devices[] __initdata = {
index 4c748616ef47eb9de63d751072e8d779fc3ffe44..10016a3bc69826351830ea53f822c7a8e3c4f033 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/usb/msm_hsusb.h>
 #include <linux/err.h>
 #include <linux/clkdev.h>
+#include <linux/smc91x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -49,15 +50,20 @@ static struct resource smc91x_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        [1] = {
-               .flags = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
        },
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static int __init msm_init_smc91x(void)
index 2a2f4d56e4c85ea599b295a10d09c2bf922bdc79..25f1beea453e0252234b3c62d7f53de75e6ed3f3 100644 (file)
@@ -720,6 +720,8 @@ static const char * __init omap_get_family(void)
                return kasprintf(GFP_KERNEL, "OMAP4");
        else if (soc_is_omap54xx())
                return kasprintf(GFP_KERNEL, "OMAP5");
+       else if (soc_is_am33xx() || soc_is_am335x())
+               return kasprintf(GFP_KERNEL, "AM33xx");
        else if (soc_is_am43xx())
                return kasprintf(GFP_KERNEL, "AM43xx");
        else if (soc_is_dra7xx())
index 92afb723dcfc2364aca9e711a3fb4bf9c5245e12..355b089368715427627dd39f1014ed7024ae8459 100644 (file)
@@ -1692,16 +1692,15 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
        if (ret == -EBUSY)
                pr_warn("omap_hwmod: %s: failed to hardreset\n", oh->name);
 
-       if (!ret) {
+       if (oh->clkdm) {
                /*
                 * Set the clockdomain to HW_AUTO, assuming that the
                 * previous state was HW_AUTO.
                 */
-               if (oh->clkdm && hwsup)
+               if (hwsup)
                        clkdm_allow_idle(oh->clkdm);
-       } else {
-               if (oh->clkdm)
-                       clkdm_hwmod_disable(oh->clkdm, oh);
+
+               clkdm_hwmod_disable(oh->clkdm, oh);
        }
 
        return ret;
@@ -2698,6 +2697,7 @@ static int __init _register(struct omap_hwmod *oh)
        INIT_LIST_HEAD(&oh->master_ports);
        INIT_LIST_HEAD(&oh->slave_ports);
        spin_lock_init(&oh->_lock);
+       lockdep_set_class(&oh->_lock, &oh->hwmod_key);
 
        oh->_state = _HWMOD_STATE_REGISTERED;
 
index 9d4bec6ee7424c2643600ded08e0a0d9bef093fa..9611c91d9b82154e6d5d7f46c75c1b1ab6ffd588 100644 (file)
@@ -674,6 +674,7 @@ struct omap_hwmod {
        u32                             _sysc_cache;
        void __iomem                    *_mpu_rt_va;
        spinlock_t                      _lock;
+       struct lock_class_key           hwmod_key; /* unique lock class */
        struct list_head                node;
        struct omap_hwmod_ocp_if        *_mpu_port;
        unsigned int                    (*xlate_irq)(unsigned int);
index e8692e7675b865833e31b0b07c130d8512c3b221..16fe7a1b7a3578069746371dc789e51308cc2134 100644 (file)
@@ -1466,53 +1466,16 @@ static struct omap_hwmod dra7xx_ocp2scp3_hwmod = {
  *
  */
 
-static struct omap_hwmod_class dra7xx_pcie_hwmod_class = {
+static struct omap_hwmod_class dra7xx_pciess_hwmod_class = {
        .name   = "pcie",
 };
 
 /* pcie1 */
-static struct omap_hwmod dra7xx_pcie1_hwmod = {
+static struct omap_hwmod dra7xx_pciess1_hwmod = {
        .name           = "pcie1",
-       .class          = &dra7xx_pcie_hwmod_class,
+       .class          = &dra7xx_pciess_hwmod_class,
        .clkdm_name     = "pcie_clkdm",
        .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs   = DRA7XX_CM_PCIE_CLKSTCTRL_OFFSET,
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* pcie2 */
-static struct omap_hwmod dra7xx_pcie2_hwmod = {
-       .name           = "pcie2",
-       .class          = &dra7xx_pcie_hwmod_class,
-       .clkdm_name     = "pcie_clkdm",
-       .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_PCIE_CLKSTCTRL_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/*
- * 'PCIE PHY' class
- *
- */
-
-static struct omap_hwmod_class dra7xx_pcie_phy_hwmod_class = {
-       .name   = "pcie-phy",
-};
-
-/* pcie1 phy */
-static struct omap_hwmod dra7xx_pcie1_phy_hwmod = {
-       .name           = "pcie1-phy",
-       .class          = &dra7xx_pcie_phy_hwmod_class,
-       .clkdm_name     = "l3init_clkdm",
-       .main_clk       = "l4_root_clk_div",
        .prcm = {
                .omap4 = {
                        .clkctrl_offs = DRA7XX_CM_L3INIT_PCIESS1_CLKCTRL_OFFSET,
@@ -1522,11 +1485,11 @@ static struct omap_hwmod dra7xx_pcie1_phy_hwmod = {
        },
 };
 
-/* pcie2 phy */
-static struct omap_hwmod dra7xx_pcie2_phy_hwmod = {
-       .name           = "pcie2-phy",
-       .class          = &dra7xx_pcie_phy_hwmod_class,
-       .clkdm_name     = "l3init_clkdm",
+/* pcie2 */
+static struct omap_hwmod dra7xx_pciess2_hwmod = {
+       .name           = "pcie2",
+       .class          = &dra7xx_pciess_hwmod_class,
+       .clkdm_name     = "pcie_clkdm",
        .main_clk       = "l4_root_clk_div",
        .prcm = {
                .omap4 = {
@@ -2877,50 +2840,34 @@ static struct omap_hwmod_ocp_if dra7xx_l4_cfg__ocp2scp3 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l3_main_1 -> pcie1 */
-static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pcie1 = {
+/* l3_main_1 -> pciess1 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pciess1 = {
        .master         = &dra7xx_l3_main_1_hwmod,
-       .slave          = &dra7xx_pcie1_hwmod,
+       .slave          = &dra7xx_pciess1_hwmod,
        .clk            = "l3_iclk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_cfg -> pcie1 */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie1 = {
+/* l4_cfg -> pciess1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pciess1 = {
        .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie1_hwmod,
+       .slave          = &dra7xx_pciess1_hwmod,
        .clk            = "l4_root_clk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l3_main_1 -> pcie2 */
-static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pcie2 = {
+/* l3_main_1 -> pciess2 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pciess2 = {
        .master         = &dra7xx_l3_main_1_hwmod,
-       .slave          = &dra7xx_pcie2_hwmod,
+       .slave          = &dra7xx_pciess2_hwmod,
        .clk            = "l3_iclk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_cfg -> pcie2 */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie2 = {
-       .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie2_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_cfg -> pcie1 phy */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie1_phy = {
-       .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie1_phy_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_cfg -> pcie2 phy */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie2_phy = {
+/* l4_cfg -> pciess2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pciess2 = {
        .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie2_phy_hwmod,
+       .slave          = &dra7xx_pciess2_hwmod,
        .clk            = "l4_root_clk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
@@ -3327,12 +3274,10 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l4_cfg__mpu,
        &dra7xx_l4_cfg__ocp2scp1,
        &dra7xx_l4_cfg__ocp2scp3,
-       &dra7xx_l3_main_1__pcie1,
-       &dra7xx_l4_cfg__pcie1,
-       &dra7xx_l3_main_1__pcie2,
-       &dra7xx_l4_cfg__pcie2,
-       &dra7xx_l4_cfg__pcie1_phy,
-       &dra7xx_l4_cfg__pcie2_phy,
+       &dra7xx_l3_main_1__pciess1,
+       &dra7xx_l4_cfg__pciess1,
+       &dra7xx_l3_main_1__pciess2,
+       &dra7xx_l4_cfg__pciess2,
        &dra7xx_l3_main_1__qspi,
        &dra7xx_l4_per3__rtcss,
        &dra7xx_l4_cfg__sata,
index 190fa43e74796809e47b73a9a84e8b6aa589aead..e642b079e9f313ac97876e8f74a8b10612a80b83 100644 (file)
@@ -173,6 +173,7 @@ static void __init omap3_igep0030_rev_g_legacy_init(void)
 
 static void __init omap3_evm_legacy_init(void)
 {
+       hsmmc2_internal_input_clk();
        legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 149);
 }
 
index a08a617a6c110365cf20ce9c5df54edef19c20c5..d6d6bc39e05c962d80b3b777b50c1d802764af0b 100644 (file)
@@ -252,10 +252,10 @@ static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
 {
        saved_mask[0] =
                omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
-                                       OMAP4_PRM_IRQSTATUS_MPU_OFFSET);
+                                       OMAP4_PRM_IRQENABLE_MPU_OFFSET);
        saved_mask[1] =
                omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
-                                       OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET);
+                                       OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
 
        omap4_prm_write_inst_reg(0, OMAP4430_PRM_OCP_SOCKET_INST,
                                 OMAP4_PRM_IRQENABLE_MPU_OFFSET);
index 343c4e3a7c5d1aceb136a196dcae946a7c8f5a69..f6d02e4cbcda4e06954c1c960a54b945e28fe58b 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/platform_data/video-pxafb.h>
 #include <mach/bitfield.h>
 #include <linux/platform_data/mmc-pxamci.h>
+#include <linux/smc91x.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -81,11 +82,16 @@ static struct resource smc91x_resources[] = {
        }
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_32BIT | SMC91X_USE_DMA | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static void idp_backlight_power(int on)
index 0eecd83c624e3d98573d542efb834e7371cffc00..89a7c06570d3adf248a00bf07c3c3aff631d23cf 100644 (file)
@@ -11,6 +11,7 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
+#include <linux/bitops.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
@@ -40,7 +41,6 @@
 #define ICHP_VAL_IRQ           (1 << 31)
 #define ICHP_IRQ(i)            (((i) >> 16) & 0x7fff)
 #define IPR_VALID              (1 << 31)
-#define IRQ_BIT(n)             (((n) - PXA_IRQ(0)) & 0x1f)
 
 #define MAX_INTERNAL_IRQS      128
 
@@ -51,6 +51,7 @@
 static void __iomem *pxa_irq_base;
 static int pxa_internal_irq_nr;
 static bool cpu_has_ipr;
+static struct irq_domain *pxa_irq_domain;
 
 static inline void __iomem *irq_base(int i)
 {
@@ -66,18 +67,20 @@ static inline void __iomem *irq_base(int i)
 void pxa_mask_irq(struct irq_data *d)
 {
        void __iomem *base = irq_data_get_irq_chip_data(d);
+       irq_hw_number_t irq = irqd_to_hwirq(d);
        uint32_t icmr = __raw_readl(base + ICMR);
 
-       icmr &= ~(1 << IRQ_BIT(d->irq));
+       icmr &= ~BIT(irq & 0x1f);
        __raw_writel(icmr, base + ICMR);
 }
 
 void pxa_unmask_irq(struct irq_data *d)
 {
        void __iomem *base = irq_data_get_irq_chip_data(d);
+       irq_hw_number_t irq = irqd_to_hwirq(d);
        uint32_t icmr = __raw_readl(base + ICMR);
 
-       icmr |= 1 << IRQ_BIT(d->irq);
+       icmr |= BIT(irq & 0x1f);
        __raw_writel(icmr, base + ICMR);
 }
 
@@ -118,40 +121,63 @@ asmlinkage void __exception_irq_entry ichp_handle_irq(struct pt_regs *regs)
        } while (1);
 }
 
-void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
+static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
+                      irq_hw_number_t hw)
 {
-       int irq, i, n;
+       void __iomem *base = irq_base(hw / 32);
 
-       BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
+       /* initialize interrupt priority */
+       if (cpu_has_ipr)
+               __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
+
+       irq_set_chip_and_handler(virq, &pxa_internal_irq_chip,
+                                handle_level_irq);
+       irq_set_chip_data(virq, base);
+       set_irq_flags(virq, IRQF_VALID);
+
+       return 0;
+}
+
+static struct irq_domain_ops pxa_irq_ops = {
+       .map    = pxa_irq_map,
+       .xlate  = irq_domain_xlate_onecell,
+};
+
+static __init void
+pxa_init_irq_common(struct device_node *node, int irq_nr,
+                   int (*fn)(struct irq_data *, unsigned int))
+{
+       int n;
 
        pxa_internal_irq_nr = irq_nr;
-       cpu_has_ipr = !cpu_is_pxa25x();
-       pxa_irq_base = io_p2v(0x40d00000);
+       pxa_irq_domain = irq_domain_add_legacy(node, irq_nr,
+                                              PXA_IRQ(0), 0,
+                                              &pxa_irq_ops, NULL);
+       if (!pxa_irq_domain)
+               panic("Unable to add PXA IRQ domain\n");
+       irq_set_default_host(pxa_irq_domain);
 
        for (n = 0; n < irq_nr; n += 32) {
                void __iomem *base = irq_base(n >> 5);
 
                __raw_writel(0, base + ICMR);   /* disable all IRQs */
                __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
-               for (i = n; (i < (n + 32)) && (i < irq_nr); i++) {
-                       /* initialize interrupt priority */
-                       if (cpu_has_ipr)
-                               __raw_writel(i | IPR_VALID, pxa_irq_base + IPR(i));
-
-                       irq = PXA_IRQ(i);
-                       irq_set_chip_and_handler(irq, &pxa_internal_irq_chip,
-                                                handle_level_irq);
-                       irq_set_chip_data(irq, base);
-                       set_irq_flags(irq, IRQF_VALID);
-               }
        }
-
        /* only unmasked interrupts kick us out of idle */
        __raw_writel(1, irq_base(0) + ICCR);
 
        pxa_internal_irq_chip.irq_set_wake = fn;
 }
 
+void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
+{
+       BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
+
+       pxa_irq_base = io_p2v(0x40d00000);
+       cpu_has_ipr = !cpu_is_pxa25x();
+       pxa_init_irq_common(NULL, irq_nr, fn);
+}
+
 #ifdef CONFIG_PM
 static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
 static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
@@ -203,30 +229,6 @@ struct syscore_ops pxa_irq_syscore_ops = {
 };
 
 #ifdef CONFIG_OF
-static struct irq_domain *pxa_irq_domain;
-
-static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
-                      irq_hw_number_t hw)
-{
-       void __iomem *base = irq_base(hw / 32);
-
-       /* initialize interrupt priority */
-       if (cpu_has_ipr)
-               __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
-
-       irq_set_chip_and_handler(hw, &pxa_internal_irq_chip,
-                                handle_level_irq);
-       irq_set_chip_data(hw, base);
-       set_irq_flags(hw, IRQF_VALID);
-
-       return 0;
-}
-
-static struct irq_domain_ops pxa_irq_ops = {
-       .map    = pxa_irq_map,
-       .xlate  = irq_domain_xlate_onecell,
-};
-
 static const struct of_device_id intc_ids[] __initconst = {
        { .compatible = "marvell,pxa-intc", },
        {}
@@ -236,7 +238,7 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
 {
        struct device_node *node;
        struct resource res;
-       int n, ret;
+       int ret;
 
        node = of_find_matching_node(NULL, intc_ids);
        if (!node) {
@@ -267,23 +269,6 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
                return;
        }
 
-       pxa_irq_domain = irq_domain_add_legacy(node, pxa_internal_irq_nr, 0, 0,
-                                              &pxa_irq_ops, NULL);
-       if (!pxa_irq_domain)
-               panic("Unable to add PXA IRQ domain\n");
-
-       irq_set_default_host(pxa_irq_domain);
-
-       for (n = 0; n < pxa_internal_irq_nr; n += 32) {
-               void __iomem *base = irq_base(n >> 5);
-
-               __raw_writel(0, base + ICMR);   /* disable all IRQs */
-               __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
-       }
-
-       /* only unmasked interrupts kick us out of idle */
-       __raw_writel(1, irq_base(0) + ICCR);
-
-       pxa_internal_irq_chip.irq_set_wake = fn;
+       pxa_init_irq_common(node, pxa_internal_irq_nr, fn);
 }
 #endif /* CONFIG_OF */
index ad777b353bd5234797d93031ab6815747b65e363..eaee2c20b18956863557e0aba66e24f09e3f5070 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/pwm_backlight.h>
+#include <linux/smc91x.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -189,15 +190,20 @@ static struct resource smc91x_resources[] = {
        [1] = {
                .start  = LPD270_ETHERNET_IRQ,
                .end    = LPD270_ETHERNET_IRQ,
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
        },
 };
 
+struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static struct resource lpd270_flash_resources[] = {
index 205f9bf3821e30236d579021f09d1157a6c3fee5..ac2ae5c71ab45b7428440ee8925b121533ba9509 100644 (file)
@@ -412,7 +412,7 @@ static struct fixed_voltage_config can_regulator_pdata = {
 };
 
 static struct platform_device can_regulator_device = {
-       .name   = "reg-fixed-volage",
+       .name   = "reg-fixed-voltage",
        .id     = 0,
        .dev    = {
                .platform_data  = &can_regulator_pdata,
index 850e506926dfb8adbc137f652353d8d84cc40197..c309593abdb223e9c9499c0469f080344ea40fd7 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/platform_data/video-clcd-versatile.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
+#include <linux/smc91x.h>
 #include <linux/ata_platform.h>
 #include <linux/amba/mmci.h>
 #include <linux/gfp.h>
@@ -94,6 +95,10 @@ static struct smsc911x_platform_config smsc911x_config = {
        .phy_interface  = PHY_INTERFACE_MODE_MII,
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_32BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device realview_eth_device = {
        .name           = "smsc911x",
        .id             = 0,
@@ -107,6 +112,8 @@ int realview_eth_register(const char *name, struct resource *res)
        realview_eth_device.resource = res;
        if (strcmp(realview_eth_device.name, "smsc911x") == 0)
                realview_eth_device.dev.platform_data = &smsc911x_config;
+       else
+               realview_eth_device.dev.platform_data = &smc91x_platdata;
 
        return platform_device_register(&realview_eth_device);
 }
index 64c88d657f9efc6360600380910248a51fd3c73b..b3869cbbcc6858c5ddb6b8ab9808773cde4dfae6 100644 (file)
@@ -234,7 +234,7 @@ static struct resource realview_eb_eth_resources[] = {
        [1] = {
                .start          = IRQ_EB_ETH,
                .end            = IRQ_EB_ETH,
-               .flags          = IORESOURCE_IRQ,
+               .flags          = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
        },
 };
 
index 169262e3040dd77b25ae268bc39880929805f63c..af868d258e664b5a50a4c678506bf7da7ac6dfd0 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pm.h>
 #include <linux/serial_core.h>
 #include <linux/slab.h>
+#include <linux/smc91x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
@@ -258,12 +259,17 @@ static int neponset_probe(struct platform_device *dev)
                        0x02000000, "smc91x-attrib"),
                { .flags = IORESOURCE_IRQ },
        };
+       struct smc91x_platdata smc91x_platdata = {
+               .flags = SMC91X_USE_8BIT | SMC91X_IO_SHIFT_2 | SMC91X_NOWAIT,
+       };
        struct platform_device_info smc91x_devinfo = {
                .parent = &dev->dev,
                .name = "smc91x",
                .id = 0,
                .res = smc91x_resources,
                .num_res = ARRAY_SIZE(smc91x_resources),
+               .data = &smc91x_platdata,
+               .size_data = sizeof(smc91x_platdata),
        };
        int ret, irq;
 
index 091261878effde2e56d1b4f81a157f7d696de765..1525d7b5f1b74b6d06ac1276a56a45c23781e060 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/mtd/partitions.h>
+#include <linux/smc91x.h>
 
 #include <mach/hardware.h>
 #include <asm/setup.h>
@@ -43,12 +44,18 @@ static struct resource smc91x_resources[] = {
 #endif
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
 
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev = {
+               .platform_data  = &smc91x_platdata,
+       },
 };
 
 static struct platform_device *devices[] __initdata = {
index 483cb467bf65a13d1f414a88c0233b5e46e184d1..a0f3b1cd497cc70656637c6dd2215a07942c0b1e 100644 (file)
@@ -45,6 +45,6 @@ extern char secondary_trampoline, secondary_trampoline_end;
 
 extern unsigned long socfpga_cpu1start_addr;
 
-#define SOCFPGA_SCU_VIRT_BASE   0xfffec000
+#define SOCFPGA_SCU_VIRT_BASE   0xfee00000
 
 #endif
index 383d61e138af1e9dfeee1ccac39b6adb42f74236..f5e597c207b9e47d26c0a7d021563cc6bdc8bf35 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/cacheflush.h>
 
 #include "core.h"
 
@@ -73,6 +74,10 @@ void __init socfpga_sysmgr_init(void)
                        (u32 *) &socfpga_cpu1start_addr))
                pr_err("SMP: Need cpu1-start-addr in device tree.\n");
 
+       /* Ensure that socfpga_cpu1start_addr is visible to other CPUs */
+       smp_wmb();
+       sync_cache_w(&socfpga_cpu1start_addr);
+
        sys_manager_base_addr = of_iomap(np, 0);
 
        np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr");
index b067390cef4ed5c8432c77ab5ed4e7e78682bdcc..b373acade338ad7c64780da2f94bd3817b976f3e 100644 (file)
@@ -18,6 +18,7 @@ static const char *stih41x_dt_match[] __initdata = {
        "st,stih415",
        "st,stih416",
        "st,stih407",
+       "st,stih410",
        "st,stih418",
        NULL
 };
index a77604fbaf257acef8e2c546dd267a5e2ef501af..81502b90dd9130240bd716d4bfb866b9d5ac5efe 100644 (file)
@@ -1,10 +1,12 @@
 menuconfig ARCH_SUNXI
        bool "Allwinner SoCs" if ARCH_MULTI_V7
        select ARCH_REQUIRE_GPIOLIB
+       select ARCH_HAS_RESET_CONTROLLER
        select CLKSRC_MMIO
        select GENERIC_IRQ_CHIP
        select PINCTRL
        select SUN4I_TIMER
+       select RESET_CONTROLLER
 
 if ARCH_SUNXI
 
@@ -20,10 +22,8 @@ config MACH_SUN5I
 config MACH_SUN6I
        bool "Allwinner A31 (sun6i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
        select MFD_SUN6I_PRCM
-       select RESET_CONTROLLER
        select SUN5I_HSTIMER
 
 config MACH_SUN7I
@@ -37,16 +37,12 @@ config MACH_SUN7I
 config MACH_SUN8I
        bool "Allwinner A23 (sun8i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
        select MFD_SUN6I_PRCM
-       select RESET_CONTROLLER
 
 config MACH_SUN9I
        bool "Allwinner (sun9i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
-       select RESET_CONTROLLER
 
 endif
index c6c7696b8db97e33344fdec64767d9409800cb06..8f15f70622a6aa30a9ff7f20fb6cea3a963fc53b 100644 (file)
@@ -1131,23 +1131,22 @@ static void __init l2c310_of_parse(const struct device_node *np,
        }
 
        ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K);
-       if (ret)
-               return;
-
-       switch (assoc) {
-       case 16:
-               *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               *aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16;
-               *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               break;
-       case 8:
-               *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               break;
-       default:
-               pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
-                      assoc);
-               break;
+       if (!ret) {
+               switch (assoc) {
+               case 16:
+                       *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       *aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16;
+                       *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       break;
+               case 8:
+                       *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       break;
+               default:
+                       pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
+                              assoc);
+                       break;
+               }
        }
 
        prefetch = l2x0_saved_regs.prefetch_ctrl;
index 170a116d1b298c1befb81efdeaee49735362fd26..c27447653903f1134594fe309dc885285ea43bb3 100644 (file)
@@ -171,7 +171,7 @@ static int __dma_supported(struct device *dev, u64 mask, bool warn)
         */
        if (sizeof(mask) != sizeof(dma_addr_t) &&
            mask > (dma_addr_t)~0 &&
-           dma_to_pfn(dev, ~0) < max_pfn) {
+           dma_to_pfn(dev, ~0) < max_pfn - 1) {
                if (warn) {
                        dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n",
                                 mask);
index a982dc3190dfb3a841bbe196f76f58cdbb554f84..6333d9c178757fe4f365b8e765b2a9ea75e2b80b 100644 (file)
@@ -552,6 +552,7 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 
        pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n",
                inf->name, fsr, addr);
+       show_pte(current->mm, addr);
 
        info.si_signo = inf->sig;
        info.si_errno = 0;
index 004e35cdcfffea6fa4add161e7e4da0a17bf6a44..cf30daff8932504f95422c2aa3b5882b154713b5 100644 (file)
@@ -49,7 +49,10 @@ static int change_memory_common(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
-       if (!is_module_address(start) || !is_module_address(end - 1))
+       if (start < MODULES_VADDR || start >= MODULES_END)
+               return -EINVAL;
+
+       if (end < MODULES_VADDR || start >= MODULES_END)
                return -EINVAL;
 
        data.set_mask = set_mask;
index db10169a08de78980d0ad17b71224f96bbfb1d5c..8ca94d379bc35f2020dea0ea3e708b0fbb0bb827 100644 (file)
@@ -799,6 +799,7 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        const struct of_device_id *match;
        const struct dmtimer_platform_data *pdata;
+       int ret;
 
        match = of_match_device(of_match_ptr(omap_timer_match), dev);
        pdata = match ? match->data : dev->platform_data;
@@ -860,7 +861,12 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        }
 
        if (!timer->reserved) {
-               pm_runtime_get_sync(dev);
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0) {
+                       dev_err(dev, "%s: pm_runtime_get_sync failed!\n",
+                               __func__);
+                       goto err_get_sync;
+               }
                __omap_dm_timer_init_regs(timer);
                pm_runtime_put(dev);
        }
@@ -873,6 +879,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        dev_dbg(dev, "Device Probed.\n");
 
        return 0;
+
+err_get_sync:
+       pm_runtime_put_noidle(dev);
+       pm_runtime_disable(dev);
+       return ret;
 }
 
 /**
@@ -899,6 +910,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev)
                }
        spin_unlock_irqrestore(&dm_timer_lock, flags);
 
+       pm_runtime_disable(&pdev->dev);
+
        return ret;
 }
 
index f1ad9c2ab2e917197f3a3a00d7b8b8499138e933..a857794432d6756ac628d55f362512ed375bcabd 100644 (file)
                };
 
                sgenet0: ethernet@1f210000 {
-                       compatible = "apm,xgene-enet";
+                       compatible = "apm,xgene1-sgenet";
                        status = "disabled";
                        reg = <0x0 0x1f210000 0x0 0xd100>,
                              <0x0 0x1f200000 0x0 0Xc300>,
                };
 
                xgenet: ethernet@1f610000 {
-                       compatible = "apm,xgene-enet";
+                       compatible = "apm,xgene1-xgenet";
                        status = "disabled";
                        reg = <0x0 0x1f610000 0x0 0xd100>,
                              <0x0 0x1f600000 0x0 0Xc300>,
index 27f32962e55c60f8b0e28407f12746513473926f..4eac8dcea423e2ff50b0101555fa475507769c91 100644 (file)
@@ -34,6 +34,7 @@
                        reg = <0x0 0x0>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@1 {
                        device_type = "cpu";
@@ -41,6 +42,7 @@
                        reg = <0x0 0x1>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@2 {
                        device_type = "cpu";
@@ -48,6 +50,7 @@
                        reg = <0x0 0x2>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@3 {
                        device_type = "cpu";
                        reg = <0x0 0x3>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
                };
        };
 
index ea2b5666a16f5a3e6b194559e21fc2538f58b7f0..c9b89efe0f562a9dd7cd1a60126f42cb8948ff23 100644 (file)
@@ -8,7 +8,7 @@
  */
 
        /* SoC fixed clocks */
-       soc_uartclk: refclk72738khz {
+       soc_uartclk: refclk7273800hz {
                compatible = "fixed-clock";
                #clock-cells = <0>;
                clock-frequency = <7273800>;
index d429129ecb3d03fe3a7460ecd3ed9d02950cb193..133ee59de2d70672db3ca648952006cdfae7c7cb 100644 (file)
@@ -39,6 +39,7 @@
                        reg = <0x0 0x0>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A57_L2>;
                };
 
                A57_1: cpu@1 {
@@ -46,6 +47,7 @@
                        reg = <0x0 0x1>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A57_L2>;
                };
 
                A53_0: cpu@100 {
@@ -53,6 +55,7 @@
                        reg = <0x0 0x100>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
                };
 
                A53_1: cpu@101 {
@@ -60,6 +63,7 @@
                        reg = <0x0 0x101>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
                };
 
                A53_2: cpu@102 {
@@ -67,6 +71,7 @@
                        reg = <0x0 0x102>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
                };
 
                A53_3: cpu@103 {
                        reg = <0x0 0x103>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
+               };
+
+               A57_L2: l2-cache0 {
+                       compatible = "cache";
+               };
+
+               A53_L2: l2-cache1 {
+                       compatible = "cache";
                };
        };
 
index efc59b3baf63fb0eb374383a3eb9ebbd73dcbdb8..20addabbd127c89acf70399c5605dfedccb55203 100644 (file)
@@ -37,6 +37,7 @@
                        reg = <0x0 0x0>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@1 {
                        device_type = "cpu";
@@ -44,6 +45,7 @@
                        reg = <0x0 0x1>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@2 {
                        device_type = "cpu";
@@ -51,6 +53,7 @@
                        reg = <0x0 0x2>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@3 {
                        device_type = "cpu";
                        reg = <0x0 0x3>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
                };
        };
 
index 5720608c50b1b7f969f881b8695a78742868f379..abb79b3cfcfea158cdcaa8ac1ffcbd32699da9b0 100644 (file)
@@ -29,7 +29,7 @@ aes-ce-blk-y := aes-glue-ce.o aes-ce.o
 obj-$(CONFIG_CRYPTO_AES_ARM64_NEON_BLK) += aes-neon-blk.o
 aes-neon-blk-y := aes-glue-neon.o aes-neon.o
 
-AFLAGS_aes-ce.o                := -DINTERLEAVE=2 -DINTERLEAVE_INLINE
+AFLAGS_aes-ce.o                := -DINTERLEAVE=4
 AFLAGS_aes-neon.o      := -DINTERLEAVE=4
 
 CFLAGS_aes-glue-ce.o   := -DUSE_V8_CRYPTO_EXTENSIONS
index 5901480bfdcaf1cd65aeb5b8ffd31c337ea73aed..750bac4e637e5323f29bd4859b6e655b3a035d95 100644 (file)
@@ -20,6 +20,9 @@
 #error "Only include this from assembly code"
 #endif
 
+#ifndef __ASM_ASSEMBLER_H
+#define __ASM_ASSEMBLER_H
+
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 
@@ -155,3 +158,5 @@ lr  .req    x30             // link register
 #endif
        orr     \rd, \lbits, \hbits, lsl #32
        .endm
+
+#endif /* __ASM_ASSEMBLER_H */
index cb9593079f29763c34f7e68fa89737355ac03adb..d8c25b7b18fbf42ddc66ab888fc22c530d752d15 100644 (file)
@@ -246,14 +246,30 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
        __ret; \
 })
 
-#define this_cpu_cmpxchg_1(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_2(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_4(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_8(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-
-#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
-       cmpxchg_double_local(raw_cpu_ptr(&(ptr1)), raw_cpu_ptr(&(ptr2)), \
-                               o1, o2, n1, n2)
+#define _protect_cmpxchg_local(pcp, o, n)                      \
+({                                                             \
+       typeof(*raw_cpu_ptr(&(pcp))) __ret;                     \
+       preempt_disable();                                      \
+       __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n);       \
+       preempt_enable();                                       \
+       __ret;                                                  \
+})
+
+#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+
+#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2)          \
+({                                                                     \
+       int __ret;                                                      \
+       preempt_disable();                                              \
+       __ret = cmpxchg_double_local(   raw_cpu_ptr(&(ptr1)),           \
+                                       raw_cpu_ptr(&(ptr2)),           \
+                                       o1, o2, n1, n2);                \
+       preempt_enable();                                               \
+       __ret;                                                          \
+})
 
 #define cmpxchg64(ptr,o,n)             cmpxchg((ptr),(o),(n))
 #define cmpxchg64_local(ptr,o,n)       cmpxchg_local((ptr),(o),(n))
index 0710654631e789121f7b0d2247b485ebf585685a..c60643f14cda97e7ba6dd9676f10b133af4b0627 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_CPUIDLE_H
 #define __ASM_CPUIDLE_H
 
+#include <asm/proc-fns.h>
+
 #ifdef CONFIG_CPU_IDLE
 extern int cpu_init_idle(unsigned int cpu);
 extern int cpu_suspend(unsigned long arg);
index e2ff32a93b5cefc2c6fc2866d4d7befed27259fc..d2f49423c5dcbad70f63cbe777d522edbd41da75 100644 (file)
@@ -264,8 +264,10 @@ __AARCH64_INSN_FUNCS(ands, 0x7F200000, 0x6A000000)
 __AARCH64_INSN_FUNCS(bics,     0x7F200000, 0x6A200000)
 __AARCH64_INSN_FUNCS(b,                0xFC000000, 0x14000000)
 __AARCH64_INSN_FUNCS(bl,       0xFC000000, 0x94000000)
-__AARCH64_INSN_FUNCS(cbz,      0xFE000000, 0x34000000)
-__AARCH64_INSN_FUNCS(cbnz,     0xFE000000, 0x35000000)
+__AARCH64_INSN_FUNCS(cbz,      0x7F000000, 0x34000000)
+__AARCH64_INSN_FUNCS(cbnz,     0x7F000000, 0x35000000)
+__AARCH64_INSN_FUNCS(tbz,      0x7F000000, 0x36000000)
+__AARCH64_INSN_FUNCS(tbnz,     0x7F000000, 0x37000000)
 __AARCH64_INSN_FUNCS(bcond,    0xFF000010, 0x54000000)
 __AARCH64_INSN_FUNCS(svc,      0xFFE0001F, 0xD4000001)
 __AARCH64_INSN_FUNCS(hvc,      0xFFE0001F, 0xD4000002)
index 94674eb7e7bb3cebaf671ef28ec7de05145bb0c9..54bb4ba974417e269656d50adb524654851fbbd2 100644 (file)
  * 40 bits wide (T0SZ = 24).  Systems with a PARange smaller than 40 bits are
  * not known to exist and will break with this configuration.
  *
+ * VTCR_EL2.PS is extracted from ID_AA64MMFR0_EL1.PARange at boot time
+ * (see hyp-init.S).
+ *
  * Note that when using 4K pages, we concatenate two first level page tables
  * together.
  *
 #ifdef CONFIG_ARM64_64K_PAGES
 /*
  * Stage2 translation configuration:
- * 40bits output (PS = 2)
  * 40bits input  (T0SZ = 24)
  * 64kB pages (TG0 = 1)
  * 2 level page tables (SL = 1)
 #else
 /*
  * Stage2 translation configuration:
- * 40bits output (PS = 2)
  * 40bits input  (T0SZ = 24)
  * 4kB pages (TG0 = 0)
  * 3 level page tables (SL = 1)
index 6458b53731421343e7640a922a202a2b4c9682be..bbfb600fa82295a8a81c85603254946422b70992 100644 (file)
@@ -158,6 +158,8 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
 #define PTRS_PER_S2_PGD                (1 << PTRS_PER_S2_PGD_SHIFT)
 #define S2_PGD_ORDER           get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
 
+#define kvm_pgd_index(addr)    (((addr) >> PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1))
+
 /*
  * If we are concatenating first level stage-2 page tables, we would have less
  * than or equal to 16 pointers in the fake PGD, because that's what the
@@ -171,43 +173,6 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
 #define KVM_PREALLOC_LEVEL     (0)
 #endif
 
-/**
- * kvm_prealloc_hwpgd - allocate inital table for VTTBR
- * @kvm:       The KVM struct pointer for the VM.
- * @pgd:       The kernel pseudo pgd
- *
- * When the kernel uses more levels of page tables than the guest, we allocate
- * a fake PGD and pre-populate it to point to the next-level page table, which
- * will be the real initial page table pointed to by the VTTBR.
- *
- * When KVM_PREALLOC_LEVEL==2, we allocate a single page for the PMD and
- * the kernel will use folded pud.  When KVM_PREALLOC_LEVEL==1, we
- * allocate 2 consecutive PUD pages.
- */
-static inline int kvm_prealloc_hwpgd(struct kvm *kvm, pgd_t *pgd)
-{
-       unsigned int i;
-       unsigned long hwpgd;
-
-       if (KVM_PREALLOC_LEVEL == 0)
-               return 0;
-
-       hwpgd = __get_free_pages(GFP_KERNEL | __GFP_ZERO, PTRS_PER_S2_PGD_SHIFT);
-       if (!hwpgd)
-               return -ENOMEM;
-
-       for (i = 0; i < PTRS_PER_S2_PGD; i++) {
-               if (KVM_PREALLOC_LEVEL == 1)
-                       pgd_populate(NULL, pgd + i,
-                                    (pud_t *)hwpgd + i * PTRS_PER_PUD);
-               else if (KVM_PREALLOC_LEVEL == 2)
-                       pud_populate(NULL, pud_offset(pgd, 0) + i,
-                                    (pmd_t *)hwpgd + i * PTRS_PER_PMD);
-       }
-
-       return 0;
-}
-
 static inline void *kvm_get_hwpgd(struct kvm *kvm)
 {
        pgd_t *pgd = kvm->arch.pgd;
@@ -224,12 +189,11 @@ static inline void *kvm_get_hwpgd(struct kvm *kvm)
        return pmd_offset(pud, 0);
 }
 
-static inline void kvm_free_hwpgd(struct kvm *kvm)
+static inline unsigned int kvm_get_hwpgd_size(void)
 {
-       if (KVM_PREALLOC_LEVEL > 0) {
-               unsigned long hwpgd = (unsigned long)kvm_get_hwpgd(kvm);
-               free_pages(hwpgd, PTRS_PER_S2_PGD_SHIFT);
-       }
+       if (KVM_PREALLOC_LEVEL > 0)
+               return PTRS_PER_S2_PGD * PAGE_SIZE;
+       return PTRS_PER_S2_PGD * sizeof(pgd_t);
 }
 
 static inline bool kvm_page_empty(void *ptr)
index a9eee33dfa62dc031ab8262c275eba79f8609bac..101a42bde728a8b9547bca989b696d473dcd7e42 100644 (file)
@@ -151,6 +151,15 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
 {
        unsigned int cpu = smp_processor_id();
 
+       /*
+        * init_mm.pgd does not contain any user mappings and it is always
+        * active for kernel addresses in TTBR1. Just set the reserved TTBR0.
+        */
+       if (next == &init_mm) {
+               cpu_set_reserved_ttbr0();
+               return;
+       }
+
        if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next)
                check_and_switch_context(next, tsk);
 }
index 09da25bc596fd0bdccdf03e94b37a4c81e0cc633..4fde8c1df97ffb46d9d2039a11cf574d05ed5a92 100644 (file)
@@ -204,25 +204,47 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
        return ret;
 }
 
+#define _percpu_read(pcp)                                              \
+({                                                                     \
+       typeof(pcp) __retval;                                           \
+       preempt_disable();                                              \
+       __retval = (typeof(pcp))__percpu_read(raw_cpu_ptr(&(pcp)),      \
+                                             sizeof(pcp));             \
+       preempt_enable();                                               \
+       __retval;                                                       \
+})
+
+#define _percpu_write(pcp, val)                                                \
+do {                                                                   \
+       preempt_disable();                                              \
+       __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val),       \
+                               sizeof(pcp));                           \
+       preempt_enable();                                               \
+} while(0)                                                             \
+
+#define _pcp_protect(operation, pcp, val)                      \
+({                                                             \
+       typeof(pcp) __retval;                                   \
+       preempt_disable();                                      \
+       __retval = (typeof(pcp))operation(raw_cpu_ptr(&(pcp)),  \
+                                         (val), sizeof(pcp));  \
+       preempt_enable();                                       \
+       __retval;                                               \
+})
+
 #define _percpu_add(pcp, val) \
-       __percpu_add(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+       _pcp_protect(__percpu_add, pcp, val)
 
-#define _percpu_add_return(pcp, val) (typeof(pcp)) (_percpu_add(pcp, val))
+#define _percpu_add_return(pcp, val) _percpu_add(pcp, val)
 
 #define _percpu_and(pcp, val) \
-       __percpu_and(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+       _pcp_protect(__percpu_and, pcp, val)
 
 #define _percpu_or(pcp, val) \
-       __percpu_or(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
-
-#define _percpu_read(pcp) (typeof(pcp))        \
-       (__percpu_read(raw_cpu_ptr(&(pcp)), sizeof(pcp)))
-
-#define _percpu_write(pcp, val) \
-       __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp))
+       _pcp_protect(__percpu_or, pcp, val)
 
 #define _percpu_xchg(pcp, val) (typeof(pcp)) \
-       (__percpu_xchg(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp)))
+       _pcp_protect(__percpu_xchg, pcp, (unsigned long)(val))
 
 #define this_cpu_add_1(pcp, val) _percpu_add(pcp, val)
 #define this_cpu_add_2(pcp, val) _percpu_add(pcp, val)
index 16449c535e50fdcf358df430d67f38cce3893df3..800ec0e87ed955bbd38e93e448b19b6b4401625b 100644 (file)
@@ -460,7 +460,7 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr)
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
-                             PTE_PROT_NONE | PTE_VALID | PTE_WRITE;
+                             PTE_PROT_NONE | PTE_WRITE | PTE_TYPE_MASK;
        pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
        return pte;
 }
index 9a8fd84f8fb2b67fe4bc2d845e7f6b584cbf0799..941c375616e2072d3b9fbf6442426c3491f00c01 100644 (file)
@@ -39,7 +39,11 @@ extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
 
 #include <asm/memory.h>
 
-#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
+#define cpu_switch_mm(pgd,mm)                          \
+do {                                                   \
+       BUG_ON(pgd == swapper_pg_dir);                  \
+       cpu_do_switch_mm(virt_to_phys(pgd),mm);         \
+} while (0)
 
 #define cpu_get_pgd()                                  \
 ({                                                     \
index f9be30ea1cbd8bc5b00cf2627c2e0be47ab54d98..20e9591a60cff97c5ef3c93cbadab1aa1312fe09 100644 (file)
@@ -45,7 +45,8 @@
 #define STACK_TOP              STACK_TOP_MAX
 #endif /* CONFIG_COMPAT */
 
-#define ARCH_LOW_ADDRESS_LIMIT PHYS_MASK
+extern phys_addr_t arm64_dma_phys_limit;
+#define ARCH_LOW_ADDRESS_LIMIT (arm64_dma_phys_limit - 1)
 #endif /* __KERNEL__ */
 
 struct debug_info {
index c028fe37456feade18c0c5737cf974899a8b6ee4..53d9c354219f9737c4d6e47ee3d1123c8e9588ce 100644 (file)
@@ -48,6 +48,7 @@ static inline void tlb_flush(struct mmu_gather *tlb)
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
                                  unsigned long addr)
 {
+       __flush_tlb_pgtable(tlb->mm, addr);
        pgtable_page_dtor(pte);
        tlb_remove_entry(tlb, pte);
 }
@@ -56,6 +57,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
 static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
                                  unsigned long addr)
 {
+       __flush_tlb_pgtable(tlb->mm, addr);
        tlb_remove_entry(tlb, virt_to_page(pmdp));
 }
 #endif
@@ -64,6 +66,7 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
 static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pudp,
                                  unsigned long addr)
 {
+       __flush_tlb_pgtable(tlb->mm, addr);
        tlb_remove_entry(tlb, virt_to_page(pudp));
 }
 #endif
index 73f0ce570fb31caa23fe7da9b99edd68d4ef6679..c3bb05b98616789a4143bb6d48333cf818653ab2 100644 (file)
 #include <linux/sched.h>
 #include <asm/cputype.h>
 
-extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
-extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
-
-extern struct cpu_tlb_fns cpu_tlb;
-
 /*
  *     TLB Management
  *     ==============
@@ -148,6 +143,19 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
                flush_tlb_all();
 }
 
+/*
+ * Used to invalidate the TLB (walk caches) corresponding to intermediate page
+ * table levels (pgd/pud/pmd).
+ */
+static inline void __flush_tlb_pgtable(struct mm_struct *mm,
+                                      unsigned long uaddr)
+{
+       unsigned long addr = uaddr >> 12 | ((unsigned long)ASID(mm) << 48);
+
+       dsb(ishst);
+       asm("tlbi       vae1is, %0" : : "r" (addr));
+       dsb(ish);
+}
 /*
  * On AArch64, the cache coherency is handled via the set_pte_at() function.
  */
index bef04afd603190135972256e52981b0889b047bf..5ee07eee80c2b0c1f5ba2b1292420eb396103be0 100644 (file)
@@ -15,8 +15,9 @@ CFLAGS_REMOVE_return_address.o = -pg
 arm64-obj-y            := cputable.o debug-monitors.o entry.o irq.o fpsimd.o   \
                           entry-fpsimd.o process.o ptrace.o setup.o signal.o   \
                           sys.o stacktrace.o time.o traps.o io.o vdso.o        \
-                          hyp-stub.o psci.o cpu_ops.o insn.o return_address.o  \
-                          cpuinfo.o cpu_errata.o alternative.o cacheinfo.o
+                          hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o       \
+                          return_address.o cpuinfo.o cpu_errata.o              \
+                          alternative.o cacheinfo.o
 
 arm64-obj-$(CONFIG_COMPAT)             += sys32.o kuser32.o signal32.o         \
                                           sys_compat.o entry32.o               \
index b42c7b480e1ee3da6f3e0896480c7888668bfe1d..ab21e0d58278825e5dfc0199cd18b853f07232c1 100644 (file)
@@ -337,7 +337,11 @@ core_initcall(arm64_dmi_init);
 
 static void efi_set_pgd(struct mm_struct *mm)
 {
-       cpu_switch_mm(mm->pgd, mm);
+       if (mm == &init_mm)
+               cpu_set_reserved_ttbr0();
+       else
+               cpu_switch_mm(mm->pgd, mm);
+
        flush_tlb_all();
        if (icache_is_aivivt())
                __flush_icache_all();
@@ -354,3 +358,12 @@ void efi_virtmap_unload(void)
        efi_set_pgd(current->active_mm);
        preempt_enable();
 }
+
+/*
+ * UpdateCapsule() depends on the system being shutdown via
+ * ResetSystem().
+ */
+bool efi_poweroff_required(void)
+{
+       return efi_enabled(EFI_RUNTIME_SERVICES);
+}
index cf8556ae09d04ad0c81855870aa052cef746f8e7..c851be795080336938f4826cc0608234b0e34bfa 100644 (file)
@@ -156,7 +156,7 @@ static int ftrace_modify_graph_caller(bool enable)
 
        branch = aarch64_insn_gen_branch_imm(pc,
                                             (unsigned long)ftrace_graph_caller,
-                                            AARCH64_INSN_BRANCH_LINK);
+                                            AARCH64_INSN_BRANCH_NOLINK);
        nop = aarch64_insn_gen_nop();
 
        if (enable)
index 8ce88e08c030e16b90d2772d377160a12465fce2..07f930540f4a8b96b520cb630226ce700f79e732 100644 (file)
@@ -585,8 +585,8 @@ ENDPROC(set_cpu_boot_mode_flag)
  * zeroing of .bss would clobber it.
  */
        .pushsection    .data..cacheline_aligned
-ENTRY(__boot_cpu_mode)
        .align  L1_CACHE_SHIFT
+ENTRY(__boot_cpu_mode)
        .long   BOOT_CPU_MODE_EL2
        .long   0
        .popsection
index 27d4864577e5d47cca67f626ea3638b9f3f8b4ec..c8eca88f12e6b2702df24bc758ac99815226827c 100644 (file)
@@ -87,8 +87,10 @@ static void __kprobes *patch_map(void *addr, int fixmap)
 
        if (module && IS_ENABLED(CONFIG_DEBUG_SET_MODULE_RONX))
                page = vmalloc_to_page(addr);
-       else
+       else if (!module && IS_ENABLED(CONFIG_DEBUG_RODATA))
                page = virt_to_page(addr);
+       else
+               return addr;
 
        BUG_ON(!page);
        set_fixmap(fixmap, page_to_phys(page));
index fde9923af859c5764110b1accf7a9da567559dd4..c6b1f3b96f4581f329a11805118797afa9556e1d 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdarg.h>
 
 #include <linux/compat.h>
+#include <linux/efi.h>
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -150,6 +151,13 @@ void machine_restart(char *cmd)
        local_irq_disable();
        smp_send_stop();
 
+       /*
+        * UpdateCapsule() depends on the system being reset via
+        * ResetSystem().
+        */
+       if (efi_enabled(EFI_RUNTIME_SERVICES))
+               efi_reboot(reboot_mode, NULL);
+
        /* Now call the architecture specific reboot code. */
        if (arm_pm_restart)
                arm_pm_restart(reboot_mode, cmd);
diff --git a/arch/arm64/kernel/psci-call.S b/arch/arm64/kernel/psci-call.S
new file mode 100644 (file)
index 0000000..cf83e61
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/linkage.h>
+
+/* int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
+ENTRY(__invoke_psci_fn_hvc)
+       hvc     #0
+       ret
+ENDPROC(__invoke_psci_fn_hvc)
+
+/* int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
+ENTRY(__invoke_psci_fn_smc)
+       smc     #0
+       ret
+ENDPROC(__invoke_psci_fn_smc)
index 3425f311c49ed99588998d3a9b42e035bf592d84..9b8a70ae64a187d2647a10576a789ebba213788c 100644 (file)
@@ -57,6 +57,9 @@ static struct psci_operations psci_ops;
 static int (*invoke_psci_fn)(u64, u64, u64, u64);
 typedef int (*psci_initcall_t)(const struct device_node *);
 
+asmlinkage int __invoke_psci_fn_hvc(u64, u64, u64, u64);
+asmlinkage int __invoke_psci_fn_smc(u64, u64, u64, u64);
+
 enum psci_function {
        PSCI_FN_CPU_SUSPEND,
        PSCI_FN_CPU_ON,
@@ -109,40 +112,6 @@ static void psci_power_state_unpack(u32 power_state,
                        PSCI_0_2_POWER_STATE_AFFL_SHIFT;
 }
 
-/*
- * The following two functions are invoked via the invoke_psci_fn pointer
- * and will not be inlined, allowing us to piggyback on the AAPCS.
- */
-static noinline int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1,
-                                        u64 arg2)
-{
-       asm volatile(
-                       __asmeq("%0", "x0")
-                       __asmeq("%1", "x1")
-                       __asmeq("%2", "x2")
-                       __asmeq("%3", "x3")
-                       "hvc    #0\n"
-               : "+r" (function_id)
-               : "r" (arg0), "r" (arg1), "r" (arg2));
-
-       return function_id;
-}
-
-static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
-                                        u64 arg2)
-{
-       asm volatile(
-                       __asmeq("%0", "x0")
-                       __asmeq("%1", "x1")
-                       __asmeq("%2", "x2")
-                       __asmeq("%3", "x3")
-                       "smc    #0\n"
-               : "+r" (function_id)
-               : "r" (arg0), "r" (arg1), "r" (arg2));
-
-       return function_id;
-}
-
 static int psci_get_version(void)
 {
        int err;
index c20a300e22137f741a236cb8385864b90fac9df4..d26fcd4cd6e6219cae5213b4b329d53d90a86a9b 100644 (file)
@@ -154,8 +154,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
        case __SI_TIMER:
                 err |= __put_user(from->si_tid, &to->si_tid);
                 err |= __put_user(from->si_overrun, &to->si_overrun);
-                err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr,
-                                  &to->si_ptr);
+                err |= __put_user(from->si_int, &to->si_int);
                break;
        case __SI_POLL:
                err |= __put_user(from->si_band, &to->si_band);
@@ -184,7 +183,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
        case __SI_MESGQ: /* But this is */
                err |= __put_user(from->si_pid, &to->si_pid);
                err |= __put_user(from->si_uid, &to->si_uid);
-               err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr);
+               err |= __put_user(from->si_int, &to->si_int);
                break;
        case __SI_SYS:
                err |= __put_user((compat_uptr_t)(unsigned long)
index fe652ffd34c28090076b8d8358c6e40f7d77034d..efa79e8d4196d01318779cd76f2e926c40765ae9 100644 (file)
@@ -174,8 +174,6 @@ ENDPROC(__kernel_clock_gettime)
 /* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */
 ENTRY(__kernel_clock_getres)
        .cfi_startproc
-       cbz     w1, 3f
-
        cmp     w0, #CLOCK_REALTIME
        ccmp    w0, #CLOCK_MONOTONIC, #0x4, ne
        b.ne    1f
@@ -188,6 +186,7 @@ ENTRY(__kernel_clock_getres)
        b.ne    4f
        ldr     x2, 6f
 2:
+       cbz     w1, 3f
        stp     xzr, x2, [x1]
 
 3:     /* res == NULL. */
index 0a24b9b8c6982ddc675bbbd40b7baaecc247f1f6..ef7d112f5ce0df9ca1c1a793301c2c1b3874e23f 100644 (file)
@@ -51,7 +51,7 @@ static int __init early_coherent_pool(char *p)
 }
 early_param("coherent_pool", early_coherent_pool);
 
-static void *__alloc_from_pool(size_t size, struct page **ret_page)
+static void *__alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags)
 {
        unsigned long val;
        void *ptr = NULL;
@@ -67,6 +67,8 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page)
 
                *ret_page = phys_to_page(phys);
                ptr = (void *)val;
+               if (flags & __GFP_ZERO)
+                       memset(ptr, 0, size);
        }
 
        return ptr;
@@ -101,6 +103,7 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
                flags |= GFP_DMA;
        if (IS_ENABLED(CONFIG_DMA_CMA) && (flags & __GFP_WAIT)) {
                struct page *page;
+               void *addr;
 
                size = PAGE_ALIGN(size);
                page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
@@ -109,7 +112,10 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
                        return NULL;
 
                *dma_handle = phys_to_dma(dev, page_to_phys(page));
-               return page_address(page);
+               addr = page_address(page);
+               if (flags & __GFP_ZERO)
+                       memset(addr, 0, size);
+               return addr;
        } else {
                return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
        }
@@ -146,7 +152,7 @@ static void *__dma_alloc(struct device *dev, size_t size,
 
        if (!coherent && !(flags & __GFP_WAIT)) {
                struct page *page = NULL;
-               void *addr = __alloc_from_pool(size, &page);
+               void *addr = __alloc_from_pool(size, &page, flags);
 
                if (addr)
                        *dma_handle = phys_to_dma(dev, page_to_phys(page));
@@ -348,8 +354,6 @@ static struct dma_map_ops swiotlb_dma_ops = {
        .mapping_error = swiotlb_dma_mapping_error,
 };
 
-extern int swiotlb_late_init_with_default_size(size_t default_size);
-
 static int __init atomic_pool_init(void)
 {
        pgprot_t prot = __pgprot(PROT_NORMAL_NC);
@@ -411,21 +415,13 @@ out:
        return -ENOMEM;
 }
 
-static int __init swiotlb_late_init(void)
+static int __init arm64_dma_init(void)
 {
-       size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT);
+       int ret;
 
        dma_ops = &swiotlb_dma_ops;
 
-       return swiotlb_late_init_with_default_size(swiotlb_size);
-}
-
-static int __init arm64_dma_init(void)
-{
-       int ret = 0;
-
-       ret |= swiotlb_late_init();
-       ret |= atomic_pool_init();
+       ret = atomic_pool_init();
 
        return ret;
 }
index 71145f952070ebcd6067fcb49c5ad29e5c2ec11f..ae85da6307bb921e286bb7a99a218cab5dbe137e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dma-contiguous.h>
 #include <linux/efi.h>
+#include <linux/swiotlb.h>
 
 #include <asm/fixmap.h>
 #include <asm/memory.h>
@@ -45,6 +46,7 @@
 #include "mm.h"
 
 phys_addr_t memstart_addr __read_mostly = 0;
+phys_addr_t arm64_dma_phys_limit __read_mostly;
 
 #ifdef CONFIG_BLK_DEV_INITRD
 static int __init early_initrd(char *p)
@@ -85,7 +87,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
 
        /* 4GB maximum for 32-bit only capable devices */
        if (IS_ENABLED(CONFIG_ZONE_DMA)) {
-               max_dma = PFN_DOWN(max_zone_dma_phys());
+               max_dma = PFN_DOWN(arm64_dma_phys_limit);
                zone_size[ZONE_DMA] = max_dma - min;
        }
        zone_size[ZONE_NORMAL] = max - max_dma;
@@ -156,8 +158,6 @@ early_param("mem", early_mem);
 
 void __init arm64_memblock_init(void)
 {
-       phys_addr_t dma_phys_limit = 0;
-
        memblock_enforce_memory_limit(memory_limit);
 
        /*
@@ -174,8 +174,10 @@ void __init arm64_memblock_init(void)
 
        /* 4GB maximum for 32-bit only capable devices */
        if (IS_ENABLED(CONFIG_ZONE_DMA))
-               dma_phys_limit = max_zone_dma_phys();
-       dma_contiguous_reserve(dma_phys_limit);
+               arm64_dma_phys_limit = max_zone_dma_phys();
+       else
+               arm64_dma_phys_limit = PHYS_MASK + 1;
+       dma_contiguous_reserve(arm64_dma_phys_limit);
 
        memblock_allow_resize();
        memblock_dump_all();
@@ -276,6 +278,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       swiotlb_init(1);
+
        set_max_mapnr(pfn_to_page(max_pfn) - mem_map);
 
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
index bb0ea94c4ba1a563383f92f0f6f212c770b82d23..1d3ec3ddd84b72e654819b7818d03cbaf082815e 100644 (file)
@@ -51,7 +51,10 @@ static int change_memory_common(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
-       if (!is_module_address(start) || !is_module_address(end - 1))
+       if (start < MODULES_VADDR || start >= MODULES_END)
+               return -EINVAL;
+
+       if (end < MODULES_VADDR || end >= MODULES_END)
                return -EINVAL;
 
        data.set_mask = set_mask;
index 78d4483ba40c83fcd458fcda183c5b3d6a828267..ec4db6df5e0dde575278b3d11a6a90a2f5ffb224 100644 (file)
@@ -67,6 +67,11 @@ extern unsigned long empty_zero_page;
  */
 #define pgtable_cache_init()   do { } while (0)
 
+/*
+ * c6x is !MMU, so define the simpliest implementation
+ */
+#define pgprot_writecombine pgprot_noncached
+
 #include <asm-generic/pgtable.h>
 
 #endif /* _ASM_C6X_PGTABLE_H */
index 93bcf2abd1a15d4df394ed2a6b2d203dcbea620a..07d7a7ef8bd59c7387328e6add1b6426b0b51a52 100644 (file)
@@ -123,12 +123,14 @@ extern unsigned long empty_zero_page;
 #define PGDIR_MASK             (~(PGDIR_SIZE - 1))
 #define PTRS_PER_PGD           64
 
+#define __PAGETABLE_PUD_FOLDED
 #define PUD_SHIFT              26
 #define PTRS_PER_PUD           1
 #define PUD_SIZE               (1UL << PUD_SHIFT)
 #define PUD_MASK               (~(PUD_SIZE - 1))
 #define PUE_SIZE               256
 
+#define __PAGETABLE_PMD_FOLDED
 #define PMD_SHIFT              26
 #define PMD_SIZE               (1UL << PMD_SHIFT)
 #define PMD_MASK               (~(PMD_SIZE - 1))
index 8fd8ee70266a13cb61646b3b59530ee4181291cf..421e6ba3a173794d5a9cc8ba3b0465f2056a328f 100644 (file)
@@ -13,6 +13,7 @@
  * the M32R is two-level, so we don't really have any
  * PMD directory physically.
  */
+#define __PAGETABLE_PMD_FOLDED
 #define PMD_SHIFT      22
 #define PTRS_PER_PMD   1
 
index 28a145bfbb7151a567dd825026eac10f07845e74..35ed4a9981aefb627ed785ce311198c59000c396 100644 (file)
  */
 #ifdef CONFIG_SUN3
 #define PTRS_PER_PTE   16
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   2048
 #elif defined(CONFIG_COLDFIRE)
 #define PTRS_PER_PTE   512
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   1024
 #else
index 9359e504844258b12d2efd9c752859813210dd1a..d5779b0ec5730a01963a4a86940d1f5eb500084e 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_METAG_IO_H
 
 #include <linux/types.h>
+#include <asm/pgtable-bits.h>
 
 #define IO_SPACE_LIMIT  0
 
diff --git a/arch/metag/include/asm/pgtable-bits.h b/arch/metag/include/asm/pgtable-bits.h
new file mode 100644 (file)
index 0000000..25ba672
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Meta page table definitions.
+ */
+
+#ifndef _METAG_PGTABLE_BITS_H
+#define _METAG_PGTABLE_BITS_H
+
+#include <asm/metag_mem.h>
+
+/*
+ * Definitions for MMU descriptors
+ *
+ * These are the hardware bits in the MMCU pte entries.
+ * Derived from the Meta toolkit headers.
+ */
+#define _PAGE_PRESENT          MMCU_ENTRY_VAL_BIT
+#define _PAGE_WRITE            MMCU_ENTRY_WR_BIT
+#define _PAGE_PRIV             MMCU_ENTRY_PRIV_BIT
+/* Write combine bit - this can cause writes to occur out of order */
+#define _PAGE_WR_COMBINE       MMCU_ENTRY_WRC_BIT
+/* Sys coherent bit - this bit is never used by Linux */
+#define _PAGE_SYS_COHERENT     MMCU_ENTRY_SYS_BIT
+#define _PAGE_ALWAYS_ZERO_1    0x020
+#define _PAGE_CACHE_CTRL0      0x040
+#define _PAGE_CACHE_CTRL1      0x080
+#define _PAGE_ALWAYS_ZERO_2    0x100
+#define _PAGE_ALWAYS_ZERO_3    0x200
+#define _PAGE_ALWAYS_ZERO_4    0x400
+#define _PAGE_ALWAYS_ZERO_5    0x800
+
+/* These are software bits that we stuff into the gaps in the hardware
+ * pte entries that are not used.  Note, these DO get stored in the actual
+ * hardware, but the hardware just does not use them.
+ */
+#define _PAGE_ACCESSED         _PAGE_ALWAYS_ZERO_1
+#define _PAGE_DIRTY            _PAGE_ALWAYS_ZERO_2
+
+/* Pages owned, and protected by, the kernel. */
+#define _PAGE_KERNEL           _PAGE_PRIV
+
+/* No cacheing of this page */
+#define _PAGE_CACHE_WIN0       (MMCU_CWIN_UNCACHED << MMCU_ENTRY_CWIN_S)
+/* burst cacheing - good for data streaming */
+#define _PAGE_CACHE_WIN1       (MMCU_CWIN_BURST << MMCU_ENTRY_CWIN_S)
+/* One cache way per thread */
+#define _PAGE_CACHE_WIN2       (MMCU_CWIN_C1SET << MMCU_ENTRY_CWIN_S)
+/* Full on cacheing */
+#define _PAGE_CACHE_WIN3       (MMCU_CWIN_CACHED << MMCU_ENTRY_CWIN_S)
+
+#define _PAGE_CACHEABLE                (_PAGE_CACHE_WIN3 | _PAGE_WR_COMBINE)
+
+/* which bits are used for cache control ... */
+#define _PAGE_CACHE_MASK       (_PAGE_CACHE_CTRL0 | _PAGE_CACHE_CTRL1 | \
+                                _PAGE_WR_COMBINE)
+
+/* This is a mask of the bits that pte_modify is allowed to change. */
+#define _PAGE_CHG_MASK         (PAGE_MASK)
+
+#define _PAGE_SZ_SHIFT         1
+#define _PAGE_SZ_4K            (0x0)
+#define _PAGE_SZ_8K            (0x1 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_16K           (0x2 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_32K           (0x3 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_64K           (0x4 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_128K          (0x5 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_256K          (0x6 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_512K          (0x7 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_1M            (0x8 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_2M            (0x9 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_4M            (0xa << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_MASK          (0xf << _PAGE_SZ_SHIFT)
+
+#if defined(CONFIG_PAGE_SIZE_4K)
+#define _PAGE_SZ               (_PAGE_SZ_4K)
+#elif defined(CONFIG_PAGE_SIZE_8K)
+#define _PAGE_SZ               (_PAGE_SZ_8K)
+#elif defined(CONFIG_PAGE_SIZE_16K)
+#define _PAGE_SZ               (_PAGE_SZ_16K)
+#endif
+#define _PAGE_TABLE            (_PAGE_SZ | _PAGE_PRESENT)
+
+#if defined(CONFIG_HUGETLB_PAGE_SIZE_8K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_8K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_16K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_32K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_32K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_64K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_128K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_128K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_256K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_512K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_1M)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_2M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_2M)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_4M)
+#endif
+
+#endif /* _METAG_PGTABLE_BITS_H */
index d0604c0a87022231f37157531e1175894545ee4a..ffa3a3a2ecadda8bed7cf5e7b1508cd98c43abf8 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef _METAG_PGTABLE_H
 #define _METAG_PGTABLE_H
 
+#include <asm/pgtable-bits.h>
 #include <asm-generic/pgtable-nopmd.h>
 
 /* Invalid regions on Meta: 0x00000000-0x001FFFFF and 0xFFFF0000-0xFFFFFFFF */
 #define VMALLOC_END            0x7FFFFFFF
 #endif
 
-/*
- * Definitions for MMU descriptors
- *
- * These are the hardware bits in the MMCU pte entries.
- * Derived from the Meta toolkit headers.
- */
-#define _PAGE_PRESENT          MMCU_ENTRY_VAL_BIT
-#define _PAGE_WRITE            MMCU_ENTRY_WR_BIT
-#define _PAGE_PRIV             MMCU_ENTRY_PRIV_BIT
-/* Write combine bit - this can cause writes to occur out of order */
-#define _PAGE_WR_COMBINE       MMCU_ENTRY_WRC_BIT
-/* Sys coherent bit - this bit is never used by Linux */
-#define _PAGE_SYS_COHERENT     MMCU_ENTRY_SYS_BIT
-#define _PAGE_ALWAYS_ZERO_1    0x020
-#define _PAGE_CACHE_CTRL0      0x040
-#define _PAGE_CACHE_CTRL1      0x080
-#define _PAGE_ALWAYS_ZERO_2    0x100
-#define _PAGE_ALWAYS_ZERO_3    0x200
-#define _PAGE_ALWAYS_ZERO_4    0x400
-#define _PAGE_ALWAYS_ZERO_5    0x800
-
-/* These are software bits that we stuff into the gaps in the hardware
- * pte entries that are not used.  Note, these DO get stored in the actual
- * hardware, but the hardware just does not use them.
- */
-#define _PAGE_ACCESSED         _PAGE_ALWAYS_ZERO_1
-#define _PAGE_DIRTY            _PAGE_ALWAYS_ZERO_2
-
-/* Pages owned, and protected by, the kernel. */
-#define _PAGE_KERNEL           _PAGE_PRIV
-
-/* No cacheing of this page */
-#define _PAGE_CACHE_WIN0       (MMCU_CWIN_UNCACHED << MMCU_ENTRY_CWIN_S)
-/* burst cacheing - good for data streaming */
-#define _PAGE_CACHE_WIN1       (MMCU_CWIN_BURST << MMCU_ENTRY_CWIN_S)
-/* One cache way per thread */
-#define _PAGE_CACHE_WIN2       (MMCU_CWIN_C1SET << MMCU_ENTRY_CWIN_S)
-/* Full on cacheing */
-#define _PAGE_CACHE_WIN3       (MMCU_CWIN_CACHED << MMCU_ENTRY_CWIN_S)
-
-#define _PAGE_CACHEABLE                (_PAGE_CACHE_WIN3 | _PAGE_WR_COMBINE)
-
-/* which bits are used for cache control ... */
-#define _PAGE_CACHE_MASK       (_PAGE_CACHE_CTRL0 | _PAGE_CACHE_CTRL1 | \
-                                _PAGE_WR_COMBINE)
-
-/* This is a mask of the bits that pte_modify is allowed to change. */
-#define _PAGE_CHG_MASK         (PAGE_MASK)
-
-#define _PAGE_SZ_SHIFT         1
-#define _PAGE_SZ_4K            (0x0)
-#define _PAGE_SZ_8K            (0x1 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_16K           (0x2 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_32K           (0x3 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_64K           (0x4 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_128K          (0x5 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_256K          (0x6 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_512K          (0x7 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_1M            (0x8 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_2M            (0x9 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_4M            (0xa << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_MASK          (0xf << _PAGE_SZ_SHIFT)
-
-#if defined(CONFIG_PAGE_SIZE_4K)
-#define _PAGE_SZ               (_PAGE_SZ_4K)
-#elif defined(CONFIG_PAGE_SIZE_8K)
-#define _PAGE_SZ               (_PAGE_SZ_8K)
-#elif defined(CONFIG_PAGE_SIZE_16K)
-#define _PAGE_SZ               (_PAGE_SZ_16K)
-#endif
-#define _PAGE_TABLE            (_PAGE_SZ | _PAGE_PRESENT)
-
-#if defined(CONFIG_HUGETLB_PAGE_SIZE_8K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_8K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_16K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_32K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_32K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_64K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_128K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_128K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_256K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_512K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_1M)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_2M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_2M)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_4M)
-#endif
-
 /*
  * The Linux memory management assumes a three-level page table setup. On
  * Meta, we use that, but "fold" the mid level into the top-level page
index 881071c0794221475308604464cd7bd441b95945..13272fd5a5baec8e3b1a4de778a6982abf0adae7 100644 (file)
@@ -149,8 +149,8 @@ extern void exit_thread(void);
 
 unsigned long get_wchan(struct task_struct *p);
 
-#define        KSTK_EIP(tsk)   ((tsk)->thread.kernel_context->CurrPC)
-#define        KSTK_ESP(tsk)   ((tsk)->thread.kernel_context->AX[0].U0)
+#define        KSTK_EIP(tsk)   (task_pt_regs(tsk)->ctx.CurrPC)
+#define        KSTK_ESP(tsk)   (task_pt_regs(tsk)->ctx.AX[0].U0)
 
 #define user_stack_pointer(regs)        ((regs)->ctx.AX[0].U0)
 
index 0536bc021cc6c66667f0cbb66601c86b0ace9c10..ef548510b951b306d7b70cb941d08dc0dec3e4dd 100644 (file)
@@ -348,8 +348,9 @@ C_ENTRY(_user_exception):
  * The LP register should point to the location where the called function
  * should return.  [note that MAKE_SYS_CALL uses label 1] */
        /* See if the system call number is valid */
+       blti    r12, 5f
        addi    r11, r12, -__NR_syscalls;
-       bgei    r11,5f;
+       bgei    r11, 5f;
        /* Figure out which function to use for this system call.  */
        /* Note Microblaze barrel shift is optional, so don't rely on it */
        add     r12, r12, r12;                  /* convert num -> ptr */
@@ -375,7 +376,7 @@ C_ENTRY(_user_exception):
 
        /* The syscall number is invalid, return an error.  */
 5:
-       rtsd    r15, 8;         /* looks like a normal subroutine return */
+       braid   ret_from_trap
        addi    r3, r0, -ENOSYS;
 
 /* Entry point used to return from a syscall/trap */
@@ -411,7 +412,7 @@ C_ENTRY(ret_from_trap):
        bri     1b
 
        /* Maybe handle a signal */
-5:     
+5:
        andi    r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
        beqi    r11, 4f;                /* Signals to handle, handle them */
 
index bbcd82242059d36f91f2f4a7dfbd8d22fb479ea6..b6beb0e07b1b3b535f7625d61100e6c0087de00d 100644 (file)
@@ -216,6 +216,7 @@ int kvm_mips_host_tlb_write(struct kvm_vcpu *vcpu, unsigned long entryhi,
        if (idx > current_cpu_data.tlbsize) {
                kvm_err("%s: Invalid Index: %d\n", __func__, idx);
                kvm_mips_dump_host_tlbs();
+               local_irq_restore(flags);
                return -1;
        }
 
index c1388d40663b0143501bacae8af8f2793e54c815..bd6437f67dc03b01c3a76e57a53a811a61f0ebe7 100644 (file)
@@ -24,18 +24,18 @@ TRACE_EVENT(kvm_exit,
            TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
            TP_ARGS(vcpu, reason),
            TP_STRUCT__entry(
-                       __field(struct kvm_vcpu *, vcpu)
+                       __field(unsigned long, pc)
                        __field(unsigned int, reason)
            ),
 
            TP_fast_assign(
-                       __entry->vcpu = vcpu;
+                       __entry->pc = vcpu->arch.pc;
                        __entry->reason = reason;
            ),
 
            TP_printk("[%s]PC: 0x%08lx",
                      kvm_mips_exit_types_str[__entry->reason],
-                     __entry->vcpu->arch.pc)
+                     __entry->pc)
 );
 
 #endif /* _TRACE_KVM_H */
index afab728ab65ecde48b3c50c78e1dd19a795ad99d..96d3f9deb59c38b2172f7b3b7a81c1397ceebad9 100644 (file)
@@ -56,7 +56,9 @@ extern void paging_init(void);
 #define PGDIR_SHIFT    22
 #define PTRS_PER_PGD   1024
 #define PTRS_PER_PUD   1       /* we don't really have any PUD physically */
+#define __PAGETABLE_PUD_FOLDED
 #define PTRS_PER_PMD   1       /* we don't really have any PMD physically */
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PTE   1024
 
 #define PGD_SIZE       PAGE_SIZE
index 20fb1cf2dab63238b0e8b464a7b08a447257946e..64246214487288eb5cc352dd625b4e55538dded2 100644 (file)
 
 #include <uapi/asm/ptrace.h>
 
+/* This struct defines the way the registers are stored on the
+   stack during a system call.  */
+
 #ifndef __ASSEMBLY__
+struct pt_regs {
+       unsigned long  r8;      /* r8-r15 Caller-saved GP registers */
+       unsigned long  r9;
+       unsigned long  r10;
+       unsigned long  r11;
+       unsigned long  r12;
+       unsigned long  r13;
+       unsigned long  r14;
+       unsigned long  r15;
+       unsigned long  r1;      /* Assembler temporary */
+       unsigned long  r2;      /* Retval LS 32bits */
+       unsigned long  r3;      /* Retval MS 32bits */
+       unsigned long  r4;      /* r4-r7 Register arguments */
+       unsigned long  r5;
+       unsigned long  r6;
+       unsigned long  r7;
+       unsigned long  orig_r2; /* Copy of r2 ?? */
+       unsigned long  ra;      /* Return address */
+       unsigned long  fp;      /* Frame pointer */
+       unsigned long  sp;      /* Stack pointer */
+       unsigned long  gp;      /* Global pointer */
+       unsigned long  estatus;
+       unsigned long  ea;      /* Exception return address (pc) */
+       unsigned long  orig_r7;
+};
+
+/*
+ * This is the extended stack used by signal handlers and the context
+ * switcher: it's pushed after the normal "struct pt_regs".
+ */
+struct switch_stack {
+       unsigned long  r16;     /* r16-r23 Callee-saved GP registers */
+       unsigned long  r17;
+       unsigned long  r18;
+       unsigned long  r19;
+       unsigned long  r20;
+       unsigned long  r21;
+       unsigned long  r22;
+       unsigned long  r23;
+       unsigned long  fp;
+       unsigned long  gp;
+       unsigned long  ra;
+};
+
 #define user_mode(regs)        (((regs)->estatus & ESTATUS_EU))
 
 #define instruction_pointer(regs)      ((regs)->ra)
diff --git a/arch/nios2/include/asm/ucontext.h b/arch/nios2/include/asm/ucontext.h
deleted file mode 100644 (file)
index 2c87614..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
- * Copyright (C) 2004 Microtronix Datacom Ltd
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_NIOS2_UCONTEXT_H
-#define _ASM_NIOS2_UCONTEXT_H
-
-typedef int greg_t;
-#define NGREG 32
-typedef greg_t gregset_t[NGREG];
-
-struct mcontext {
-       int version;
-       gregset_t gregs;
-};
-
-#define MCONTEXT_VERSION 2
-
-struct ucontext {
-       unsigned long     uc_flags;
-       struct ucontext  *uc_link;
-       stack_t           uc_stack;
-       struct mcontext   uc_mcontext;
-       sigset_t          uc_sigmask;   /* mask last for extensibility */
-};
-
-#endif
index 4f07ca3f8d10edd443595bac553bb170f192ce58..e0bb972a50d7425b3f422605ab64bbc82c428cc0 100644 (file)
@@ -1,4 +1,5 @@
 include include/uapi/asm-generic/Kbuild.asm
 
 header-y += elf.h
-header-y += ucontext.h
+
+generic-y += ucontext.h
index a5b91ae5cf56fb5fcff4cfb6e3ad62bd96998491..6f06d3b2949e7ffd3d95c4951517a99abdcdeea1 100644 (file)
@@ -50,9 +50,7 @@
 
 typedef unsigned long elf_greg_t;
 
-#define ELF_NGREG      \
-       ((sizeof(struct pt_regs) + sizeof(struct switch_stack)) /       \
-               sizeof(elf_greg_t))
+#define ELF_NGREG              49
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 typedef unsigned long elf_fpregset_t;
index e83a7c9d1c36c4bc6a2690bfac8fc4a05f015cfa..71a330597adff689dcae092d63839aad1fb8b7d3 100644 (file)
 
 #define NUM_PTRACE_REG (PTR_TLBMISC + 1)
 
-/* this struct defines the way the registers are stored on the
-   stack during a system call.
-
-   There is a fake_regs in setup.c that has to match pt_regs.*/
-
-struct pt_regs {
-       unsigned long  r8;              /* r8-r15 Caller-saved GP registers */
-       unsigned long  r9;
-       unsigned long  r10;
-       unsigned long  r11;
-       unsigned long  r12;
-       unsigned long  r13;
-       unsigned long  r14;
-       unsigned long  r15;
-       unsigned long  r1;              /* Assembler temporary */
-       unsigned long  r2;              /* Retval LS 32bits */
-       unsigned long  r3;              /* Retval MS 32bits */
-       unsigned long  r4;              /* r4-r7 Register arguments */
-       unsigned long  r5;
-       unsigned long  r6;
-       unsigned long  r7;
-       unsigned long  orig_r2;         /* Copy of r2 ?? */
-       unsigned long  ra;              /* Return address */
-       unsigned long  fp;              /* Frame pointer */
-       unsigned long  sp;              /* Stack pointer */
-       unsigned long  gp;              /* Global pointer */
-       unsigned long  estatus;
-       unsigned long  ea;              /* Exception return address (pc) */
-       unsigned long  orig_r7;
-};
-
-/*
- * This is the extended stack used by signal handlers and the context
- * switcher: it's pushed after the normal "struct pt_regs".
- */
-struct switch_stack {
-       unsigned long  r16;             /* r16-r23 Callee-saved GP registers */
-       unsigned long  r17;
-       unsigned long  r18;
-       unsigned long  r19;
-       unsigned long  r20;
-       unsigned long  r21;
-       unsigned long  r22;
-       unsigned long  r23;
-       unsigned long  fp;
-       unsigned long  gp;
-       unsigned long  ra;
+/* User structures for general purpose registers.  */
+struct user_pt_regs {
+       __u32           regs[49];
 };
 
 #endif /* __ASSEMBLY__ */
index 7b8bb41867d4416e7b1cfeb61e1b930fc68c71dc..b67944a509273a020a8e13e9ebf0e039e492867c 100644 (file)
  * details.
  */
 
-#ifndef _ASM_NIOS2_SIGCONTEXT_H
-#define _ASM_NIOS2_SIGCONTEXT_H
+#ifndef _UAPI__ASM_SIGCONTEXT_H
+#define _UAPI__ASM_SIGCONTEXT_H
 
-#include <asm/ptrace.h>
+#include <linux/types.h>
+
+#define MCONTEXT_VERSION 2
 
 struct sigcontext {
-       struct pt_regs regs;
-       unsigned long  sc_mask; /* old sigmask */
+       int version;
+       unsigned long gregs[32];
 };
 
 #endif
index 2d0ea25be1717de06d8cd138032dc5c7c5f3970d..dda41e4fe7070885ee7ab77e4c5e9e18e51dd0a3 100644 (file)
@@ -39,7 +39,7 @@ static inline int rt_restore_ucontext(struct pt_regs *regs,
                                        struct ucontext *uc, int *pr2)
 {
        int temp;
-       greg_t *gregs = uc->uc_mcontext.gregs;
+       unsigned long *gregs = uc->uc_mcontext.gregs;
        int err;
 
        /* Always make any pending restarted system calls return -EINTR */
@@ -127,7 +127,7 @@ badframe:
 static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
 {
        struct switch_stack *sw = (struct switch_stack *)regs - 1;
-       greg_t *gregs = uc->uc_mcontext.gregs;
+       unsigned long *gregs = uc->uc_mcontext.gregs;
        int err = 0;
 
        err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
index 0d231adfe576b897073c924e02211dea7b110285..0c9b6afe69e9094815cc1e73084422368b3a2e52 100644 (file)
@@ -126,7 +126,6 @@ good_area:
                break;
        }
 
-survive:
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
@@ -220,11 +219,6 @@ no_context:
  */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       if (is_global_init(tsk)) {
-               yield();
-               down_read(&mm->mmap_sem);
-               goto survive;
-       }
        if (!user_mode(regs))
                goto no_context;
        pagefault_out_of_memory();
index f213f5b4c4239b961e260c659447886a8646f0bd..d17437238a2cef75dd4d46593c760320933b6d38 100644 (file)
@@ -26,7 +26,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
        if (likely(pgd != NULL)) {
                memset(pgd, 0, PAGE_SIZE<<PGD_ALLOC_ORDER);
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
                actual_pgd += PTRS_PER_PGD;
                /* Populate first pmd with allocated memory.  We mark it
                 * with PxD_FLAG_ATTACHED as a signal to the system that this
@@ -45,7 +45,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
        pgd -= PTRS_PER_PGD;
 #endif
        free_pages((unsigned long)pgd, PGD_ALLOC_ORDER);
@@ -72,12 +72,15 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 
 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
-#ifdef CONFIG_64BIT
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
-               /* This is the permanent pmd attached to the pgd;
-                * cannot free it */
+               /*
+                * This is the permanent pmd attached to the pgd;
+                * cannot free it.
+                * Increment the counter to compensate for the decrement
+                * done by generic mm code.
+                */
+               mm_inc_nr_pmds(mm);
                return;
-#endif
        free_pages((unsigned long)pmd, PMD_ORDER);
 }
 
@@ -99,7 +102,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 static inline void
 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 {
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
        /* preserve the gateway marker if this is the beginning of
         * the permanent pmd */
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
index 8c966b2270aa6692c6f085027a8c70098b447733..15207b9362bfd0947064f7572ad34fdfb6e4d30c 100644 (file)
@@ -96,6 +96,7 @@ extern void purge_tlb_entries(struct mm_struct *, unsigned long);
 #if PT_NLEVELS == 3
 #define BITS_PER_PMD   (PAGE_SHIFT + PMD_ORDER - BITS_PER_PMD_ENTRY)
 #else
+#define __PAGETABLE_PMD_FOLDED
 #define BITS_PER_PMD   0
 #endif
 #define PTRS_PER_PMD    (1UL << BITS_PER_PMD)
index 5a8997d63899346a82e759f30b601eaf907bac37..8eefb12d1d33f3fc87195a0cd9efe0d0fd0301b2 100644 (file)
@@ -55,8 +55,8 @@
 #define ENTRY_COMP(_name_) .word sys_##_name_
 #endif
 
-       ENTRY_SAME(restart_syscall)     /* 0 */
-       ENTRY_SAME(exit)
+90:    ENTRY_SAME(restart_syscall)     /* 0 */
+91:    ENTRY_SAME(exit)
        ENTRY_SAME(fork_wrapper)
        ENTRY_SAME(read)
        ENTRY_SAME(write)
        ENTRY_SAME(bpf)
        ENTRY_COMP(execveat)
 
-       /* Nothing yet */
+
+.ifne (. - 90b) - (__NR_Linux_syscalls * (91b - 90b))
+.error "size of syscall table does not fit value of __NR_Linux_syscalls"
+.endif
 
 #undef ENTRY_SAME
 #undef ENTRY_DIFF
index 9cfa3706a1b8750942d7e41a91ef44996053a2ad..f1ea5972f6eccddceb7b776961ff67dcf2cb14e6 100644 (file)
@@ -113,6 +113,7 @@ extern void iommu_register_group(struct iommu_table *tbl,
                                 int pci_domain_number, unsigned long pe_num);
 extern int iommu_add_device(struct device *dev);
 extern void iommu_del_device(struct device *dev);
+extern int __init tce_iommu_bus_notifier_init(void);
 #else
 static inline void iommu_register_group(struct iommu_table *tbl,
                                        int pci_domain_number,
@@ -128,6 +129,11 @@ static inline int iommu_add_device(struct device *dev)
 static inline void iommu_del_device(struct device *dev)
 {
 }
+
+static inline int __init tce_iommu_bus_notifier_init(void)
+{
+        return 0;
+}
 #endif /* !CONFIG_IOMMU_API */
 
 static inline void set_iommu_table_base_and_group(struct device *dev,
diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h
new file mode 100644 (file)
index 0000000..744fd54
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _ASM_POWERPC_IRQ_WORK_H
+#define _ASM_POWERPC_IRQ_WORK_H
+
+static inline bool arch_irq_work_has_interrupt(void)
+{
+       return true;
+}
+
+#endif /* _ASM_POWERPC_IRQ_WORK_H */
index 03cd858a401c067b1b34f18e9b5fddd521e8fe2d..4cbe23af400ab622749b31f980d5d72d6b8587ac 100644 (file)
 #define PPC_INST_MFSPR_PVR_MASK                0xfc1fffff
 #define PPC_INST_MFTMR                 0x7c0002dc
 #define PPC_INST_MSGSND                        0x7c00019c
+#define PPC_INST_MSGCLR                        0x7c0001dc
 #define PPC_INST_MSGSNDP               0x7c00011c
 #define PPC_INST_MTTMR                 0x7c0003dc
 #define PPC_INST_NOP                   0x60000000
                                        ___PPC_RB(b) | __PPC_EH(eh))
 #define PPC_MSGSND(b)          stringify_in_c(.long PPC_INST_MSGSND | \
                                        ___PPC_RB(b))
+#define PPC_MSGCLR(b)          stringify_in_c(.long PPC_INST_MSGCLR | \
+                                       ___PPC_RB(b))
 #define PPC_MSGSNDP(b)         stringify_in_c(.long PPC_INST_MSGSNDP | \
                                        ___PPC_RB(b))
 #define PPC_POPCNTB(a, s)      stringify_in_c(.long PPC_INST_POPCNTB | \
index 1c874fb533bbf22fe8ff019b328ae623214243bb..af56b5c6c81ab18aefe24b16c810a3b89604434d 100644 (file)
 #define   SRR1_ISI_N_OR_G      0x10000000 /* ISI: Access is no-exec or G */
 #define   SRR1_ISI_PROT                0x08000000 /* ISI: Other protection fault */
 #define   SRR1_WAKEMASK                0x00380000 /* reason for wakeup */
+#define   SRR1_WAKEMASK_P8     0x003c0000 /* reason for wakeup on POWER8 */
 #define   SRR1_WAKESYSERR      0x00300000 /* System error */
 #define   SRR1_WAKEEE          0x00200000 /* External interrupt */
 #define   SRR1_WAKEMT          0x00280000 /* mtctrl */
 #define          SRR1_WAKEHMI          0x00280000 /* Hypervisor maintenance */
 #define   SRR1_WAKEDEC         0x00180000 /* Decrementer interrupt */
+#define   SRR1_WAKEDBELL       0x00140000 /* Privileged doorbell on P8 */
 #define   SRR1_WAKETHERM       0x00100000 /* Thermal management interrupt */
 #define          SRR1_WAKERESET        0x00100000 /* System reset */
+#define   SRR1_WAKEHDBELL      0x000c0000 /* Hypervisor doorbell on P8 */
 #define          SRR1_WAKESTATE        0x00030000 /* Powersave exit mask [46:47] */
 #define          SRR1_WS_DEEPEST       0x00030000 /* Some resources not maintained,
                                          * may not be recoverable */
index f337666768a76594b41b59f283efa3b891988193..f8304687833651975722e4f8aa51741fffad63d9 100644 (file)
@@ -437,6 +437,26 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check_early    = __machine_check_early_realmode_p8,
                .platform               = "power8",
        },
+       {       /* Power8NVL */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x004c0000,
+               .cpu_name               = "POWER8NVL (raw)",
+               .cpu_features           = CPU_FTRS_POWER8,
+               .cpu_user_features      = COMMON_USER_POWER8,
+               .cpu_user_features2     = COMMON_USER2_POWER8,
+               .mmu_features           = MMU_FTRS_POWER8,
+               .icache_bsize           = 128,
+               .dcache_bsize           = 128,
+               .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_IBM,
+               .oprofile_cpu_type      = "ppc64/power8",
+               .oprofile_type          = PPC_OPROFILE_INVALID,
+               .cpu_setup              = __setup_cpu_power8,
+               .cpu_restore            = __restore_cpu_power8,
+               .flush_tlb              = __flush_tlb_power8,
+               .machine_check_early    = __machine_check_early_realmode_p8,
+               .platform               = "power8",
+       },
        {       /* Power8 DD1: Does not support doorbell IPIs */
                .pvr_mask               = 0xffffff00,
                .pvr_value              = 0x004d0100,
index f4217819cc31fd417243d17f079c8bf2471d37a5..2128f3a96c32dd743908f286d4cf72d6d7701568 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/dbell.h>
 #include <asm/irq_regs.h>
+#include <asm/kvm_ppc.h>
 
 #ifdef CONFIG_SMP
 void doorbell_setup_this_cpu(void)
@@ -41,6 +42,7 @@ void doorbell_exception(struct pt_regs *regs)
 
        may_hard_irq_enable();
 
+       kvmppc_set_host_ipi(smp_processor_id(), 0);
        __this_cpu_inc(irq_stat.doorbell_irqs);
 
        smp_ipi_demux();
index c2df8150bd7a0425fc00ebcc78d784d6b280c146..9519e6bdc6d75c324334bf4f0f52dd6da9d9bbcc 100644 (file)
@@ -1408,7 +1408,7 @@ machine_check_handle_early:
        bne     9f                      /* continue in V mode if we are. */
 
 5:
-#ifdef CONFIG_KVM_BOOK3S_64_HV
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
        /*
         * We are coming from kernel context. Check if we are coming from
         * guest. if yes, then we can continue. We will fall through
index 5d3968c4d79973a4645f9d7b4069056311fd42cc..b054f33ab1fbcdad3bff7fda332c9e55dcda1d2f 100644 (file)
@@ -1175,4 +1175,30 @@ void iommu_del_device(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(iommu_del_device);
 
+static int tce_iommu_bus_notifier(struct notifier_block *nb,
+                unsigned long action, void *data)
+{
+        struct device *dev = data;
+
+        switch (action) {
+        case BUS_NOTIFY_ADD_DEVICE:
+                return iommu_add_device(dev);
+        case BUS_NOTIFY_DEL_DEVICE:
+                if (dev->iommu_group)
+                        iommu_del_device(dev);
+                return 0;
+        default:
+                return 0;
+        }
+}
+
+static struct notifier_block tce_iommu_bus_nb = {
+        .notifier_call = tce_iommu_bus_notifier,
+};
+
+int __init tce_iommu_bus_notifier_init(void)
+{
+        bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
+        return 0;
+}
 #endif /* CONFIG_IOMMU_API */
index 6e19afa35a153d2736af94bc845008d724fe735f..ec9ec2058d2d3f3ec6db2dfbe25b35ab1f4cfb0b 100644 (file)
@@ -541,8 +541,8 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
        if (smp_ops->give_timebase)
                smp_ops->give_timebase();
 
-       /* Wait until cpu puts itself in the online map */
-       while (!cpu_online(cpu))
+       /* Wait until cpu puts itself in the online & active maps */
+       while (!cpu_online(cpu) || !cpu_active(cpu))
                cpu_relax();
 
        return 0;
index de4018a1bc4bd290ecd0e970bd51960b281497c3..de747563d29df39be580e6cd67c54769194dce42 100644 (file)
@@ -636,7 +636,7 @@ static int kvmppc_get_yield_count(struct kvm_vcpu *vcpu)
        spin_lock(&vcpu->arch.vpa_update_lock);
        lppaca = (struct lppaca *)vcpu->arch.vpa.pinned_addr;
        if (lppaca)
-               yield_count = lppaca->yield_count;
+               yield_count = be32_to_cpu(lppaca->yield_count);
        spin_unlock(&vcpu->arch.vpa_update_lock);
        return yield_count;
 }
@@ -942,20 +942,20 @@ static int kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu,
 static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                bool preserve_top32)
 {
+       struct kvm *kvm = vcpu->kvm;
        struct kvmppc_vcore *vc = vcpu->arch.vcore;
        u64 mask;
 
+       mutex_lock(&kvm->lock);
        spin_lock(&vc->lock);
        /*
         * If ILE (interrupt little-endian) has changed, update the
         * MSR_LE bit in the intr_msr for each vcpu in this vcore.
         */
        if ((new_lpcr & LPCR_ILE) != (vc->lpcr & LPCR_ILE)) {
-               struct kvm *kvm = vcpu->kvm;
                struct kvm_vcpu *vcpu;
                int i;
 
-               mutex_lock(&kvm->lock);
                kvm_for_each_vcpu(i, vcpu, kvm) {
                        if (vcpu->arch.vcore != vc)
                                continue;
@@ -964,7 +964,6 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                        else
                                vcpu->arch.intr_msr &= ~MSR_LE;
                }
-               mutex_unlock(&kvm->lock);
        }
 
        /*
@@ -981,6 +980,7 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                mask &= 0xFFFFFFFF;
        vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask);
        spin_unlock(&vc->lock);
+       mutex_unlock(&kvm->lock);
 }
 
 static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
index bb94e6f20c813bbcdb8297d9fb860a538c5e4f08..6cbf1630cb70c9d8b306a7628c91a3c9acf35785 100644 (file)
@@ -1005,6 +1005,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        /* Save HEIR (HV emulation assist reg) in emul_inst
           if this is an HEI (HV emulation interrupt, e40) */
        li      r3,KVM_INST_FETCH_FAILED
+       stw     r3,VCPU_LAST_INST(r9)
        cmpwi   r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
        bne     11f
        mfspr   r3,SPRN_HEIR
index e69142f4af089cf986dd84f3fb2731ae705cf1f2..54323d6b5166218fa4e9c548a0511c7ec64884dd 100644 (file)
@@ -836,30 +836,4 @@ void __init pnv_pci_init(void)
 #endif
 }
 
-static int tce_iommu_bus_notifier(struct notifier_block *nb,
-               unsigned long action, void *data)
-{
-       struct device *dev = data;
-
-       switch (action) {
-       case BUS_NOTIFY_ADD_DEVICE:
-               return iommu_add_device(dev);
-       case BUS_NOTIFY_DEL_DEVICE:
-               if (dev->iommu_group)
-                       iommu_del_device(dev);
-               return 0;
-       default:
-               return 0;
-       }
-}
-
-static struct notifier_block tce_iommu_bus_nb = {
-       .notifier_call = tce_iommu_bus_notifier,
-};
-
-static int __init tce_iommu_bus_notifier_init(void)
-{
-       bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
-       return 0;
-}
 machine_subsys_initcall_sync(powernv, tce_iommu_bus_notifier_init);
index fc34025ef82270b00c7c32811dca20552a61d2fe..38a45088f633bb190ff53b5f7ac8306fd24acb4e 100644 (file)
@@ -33,6 +33,8 @@
 #include <asm/runlatch.h>
 #include <asm/code-patching.h>
 #include <asm/dbell.h>
+#include <asm/kvm_ppc.h>
+#include <asm/ppc-opcode.h>
 
 #include "powernv.h"
 
@@ -149,7 +151,7 @@ static int pnv_smp_cpu_disable(void)
 static void pnv_smp_cpu_kill_self(void)
 {
        unsigned int cpu;
-       unsigned long srr1;
+       unsigned long srr1, wmask;
        u32 idle_states;
 
        /* Standard hot unplug procedure */
@@ -161,6 +163,10 @@ static void pnv_smp_cpu_kill_self(void)
        generic_set_cpu_dead(cpu);
        smp_wmb();
 
+       wmask = SRR1_WAKEMASK;
+       if (cpu_has_feature(CPU_FTR_ARCH_207S))
+               wmask = SRR1_WAKEMASK_P8;
+
        idle_states = pnv_get_supported_cpuidle_states();
        /* We don't want to take decrementer interrupts while we are offline,
         * so clear LPCR:PECE1. We keep PECE2 enabled.
@@ -191,10 +197,14 @@ static void pnv_smp_cpu_kill_self(void)
                 * having finished executing in a KVM guest, then srr1
                 * contains 0.
                 */
-               if ((srr1 & SRR1_WAKEMASK) == SRR1_WAKEEE) {
+               if ((srr1 & wmask) == SRR1_WAKEEE) {
                        icp_native_flush_interrupt();
                        local_paca->irq_happened &= PACA_IRQ_HARD_DIS;
                        smp_mb();
+               } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
+                       unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
+                       asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
+                       kvmppc_set_host_ipi(cpu, 0);
                }
 
                if (cpu_core_split_required())
index 1d3d52dc3ff31ed6ce0ab9b554c45c1233d0f039..7803a19adb31822fbe1c679160ff7655ec5c5411 100644 (file)
@@ -1340,3 +1340,5 @@ static int __init disable_multitce(char *str)
 }
 
 __setup("multitce=", disable_multitce);
+
+machine_subsys_initcall_sync(pseries, tce_iommu_bus_notifier_init);
index 90cf3dcbd9f268b5430a1cb69bb44cd0fd75d54a..8f35d525cede8327ac73c2129810d83456d35c15 100644 (file)
 static struct kobject *mobility_kobj;
 
 struct update_props_workarea {
-       u32 phandle;
-       u32 state;
-       u64 reserved;
-       u32 nprops;
+       __be32 phandle;
+       __be32 state;
+       __be64 reserved;
+       __be32 nprops;
 } __packed;
 
 #define NODE_ACTION_MASK       0xff000000
@@ -54,11 +54,11 @@ static int mobility_rtas_call(int token, char *buf, s32 scope)
        return rc;
 }
 
-static int delete_dt_node(u32 phandle)
+static int delete_dt_node(__be32 phandle)
 {
        struct device_node *dn;
 
-       dn = of_find_node_by_phandle(phandle);
+       dn = of_find_node_by_phandle(be32_to_cpu(phandle));
        if (!dn)
                return -ENOENT;
 
@@ -127,7 +127,7 @@ static int update_dt_property(struct device_node *dn, struct property **prop,
        return 0;
 }
 
-static int update_dt_node(u32 phandle, s32 scope)
+static int update_dt_node(__be32 phandle, s32 scope)
 {
        struct update_props_workarea *upwa;
        struct device_node *dn;
@@ -136,6 +136,7 @@ static int update_dt_node(u32 phandle, s32 scope)
        char *prop_data;
        char *rtas_buf;
        int update_properties_token;
+       u32 nprops;
        u32 vd;
 
        update_properties_token = rtas_token("ibm,update-properties");
@@ -146,7 +147,7 @@ static int update_dt_node(u32 phandle, s32 scope)
        if (!rtas_buf)
                return -ENOMEM;
 
-       dn = of_find_node_by_phandle(phandle);
+       dn = of_find_node_by_phandle(be32_to_cpu(phandle));
        if (!dn) {
                kfree(rtas_buf);
                return -ENOENT;
@@ -162,6 +163,7 @@ static int update_dt_node(u32 phandle, s32 scope)
                        break;
 
                prop_data = rtas_buf + sizeof(*upwa);
+               nprops = be32_to_cpu(upwa->nprops);
 
                /* On the first call to ibm,update-properties for a node the
                 * the first property value descriptor contains an empty
@@ -170,17 +172,17 @@ static int update_dt_node(u32 phandle, s32 scope)
                 */
                if (*prop_data == 0) {
                        prop_data++;
-                       vd = *(u32 *)prop_data;
+                       vd = be32_to_cpu(*(__be32 *)prop_data);
                        prop_data += vd + sizeof(vd);
-                       upwa->nprops--;
+                       nprops--;
                }
 
-               for (i = 0; i < upwa->nprops; i++) {
+               for (i = 0; i < nprops; i++) {
                        char *prop_name;
 
                        prop_name = prop_data;
                        prop_data += strlen(prop_name) + 1;
-                       vd = *(u32 *)prop_data;
+                       vd = be32_to_cpu(*(__be32 *)prop_data);
                        prop_data += sizeof(vd);
 
                        switch (vd) {
@@ -212,13 +214,13 @@ static int update_dt_node(u32 phandle, s32 scope)
        return 0;
 }
 
-static int add_dt_node(u32 parent_phandle, u32 drc_index)
+static int add_dt_node(__be32 parent_phandle, __be32 drc_index)
 {
        struct device_node *dn;
        struct device_node *parent_dn;
        int rc;
 
-       parent_dn = of_find_node_by_phandle(parent_phandle);
+       parent_dn = of_find_node_by_phandle(be32_to_cpu(parent_phandle));
        if (!parent_dn)
                return -ENOENT;
 
@@ -237,7 +239,7 @@ static int add_dt_node(u32 parent_phandle, u32 drc_index)
 int pseries_devicetree_update(s32 scope)
 {
        char *rtas_buf;
-       u32 *data;
+       __be32 *data;
        int update_nodes_token;
        int rc;
 
@@ -254,17 +256,17 @@ int pseries_devicetree_update(s32 scope)
                if (rc && rc != 1)
                        break;
 
-               data = (u32 *)rtas_buf + 4;
-               while (*data & NODE_ACTION_MASK) {
+               data = (__be32 *)rtas_buf + 4;
+               while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
                        int i;
-                       u32 action = *data & NODE_ACTION_MASK;
-                       int node_count = *data & NODE_COUNT_MASK;
+                       u32 action = be32_to_cpu(*data) & NODE_ACTION_MASK;
+                       u32 node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
 
                        data++;
 
                        for (i = 0; i < node_count; i++) {
-                               u32 phandle = *data++;
-                               u32 drc_index;
+                               __be32 phandle = *data++;
+                               __be32 drc_index;
 
                                switch (action) {
                                case DELETE_DT_NODE:
index c9df40b5c0ac1915eac7d6a794b25f7f9d6173b5..c9c875d9ed318cc75f7123a8d999b464201a4fd5 100644 (file)
@@ -211,7 +211,7 @@ do {                                                                \
 
 extern unsigned long mmap_rnd_mask;
 
-#define STACK_RND_MASK (mmap_rnd_mask)
+#define STACK_RND_MASK (test_thread_flag(TIF_31BIT) ? 0x7ff : mmap_rnd_mask)
 
 #define ARCH_DLINFO                                                        \
 do {                                                                       \
index d84559e31f3222c9dc9500c07750beccb733ab82..f407bbf5ee94ca5e2f6122951e52ce2d7db1a7ef 100644 (file)
@@ -515,15 +515,15 @@ struct s390_io_adapter {
 #define S390_ARCH_FAC_MASK_SIZE_U64 \
        (S390_ARCH_FAC_MASK_SIZE_BYTE / sizeof(u64))
 
-struct s390_model_fac {
-       /* facilities used in SIE context */
-       __u64 sie[S390_ARCH_FAC_LIST_SIZE_U64];
-       /* subset enabled by kvm */
-       __u64 kvm[S390_ARCH_FAC_LIST_SIZE_U64];
+struct kvm_s390_fac {
+       /* facility list requested by guest */
+       __u64 list[S390_ARCH_FAC_LIST_SIZE_U64];
+       /* facility mask supported by kvm & hosting machine */
+       __u64 mask[S390_ARCH_FAC_LIST_SIZE_U64];
 };
 
 struct kvm_s390_cpu_model {
-       struct s390_model_fac *fac;
+       struct kvm_s390_fac *fac;
        struct cpuid cpu_id;
        unsigned short ibc;
 };
index f49b719546541d7dad60d78fd1a1d86daec1f7c2..8fb3802f8fad0f8ff150ae14250fc73b8936ab78 100644 (file)
@@ -62,6 +62,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 {
        int cpu = smp_processor_id();
 
+       S390_lowcore.user_asce = next->context.asce_bits | __pa(next->pgd);
        if (prev == next)
                return;
        if (MACHINE_HAS_TLB_LC)
@@ -73,7 +74,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        atomic_dec(&prev->context.attach_count);
        if (MACHINE_HAS_TLB_LC)
                cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask);
-       S390_lowcore.user_asce = next->context.asce_bits | __pa(next->pgd);
 }
 
 #define finish_arch_post_lock_switch finish_arch_post_lock_switch
index 7b2ac6e44166ac258ebd6481cb1691e77be53b71..53eacbd4f09bf4c32ac051f1be7f9d3e5445e0df 100644 (file)
@@ -37,16 +37,7 @@ static inline void storage_key_init_range(unsigned long start, unsigned long end
 #endif
 }
 
-static inline void clear_page(void *page)
-{
-       register unsigned long reg1 asm ("1") = 0;
-       register void *reg2 asm ("2") = page;
-       register unsigned long reg3 asm ("3") = 4096;
-       asm volatile(
-               "       mvcl    2,0"
-               : "+d" (reg2), "+d" (reg3) : "d" (reg1)
-               : "memory", "cc");
-}
+#define clear_page(page)       memset((page), 0, PAGE_SIZE)
 
 /*
  * copy_page uses the mvcl instruction with 0xb0 padding byte in order to
index fbb5ee3ae57c6d21b589a2a3f38437a17a218f2b..e08ec38f8c6eb74b7cf998e18e022db4c206b616 100644 (file)
@@ -91,7 +91,9 @@ extern unsigned long zero_page_mask;
  */
 #define PTRS_PER_PTE   256
 #ifndef CONFIG_64BIT
+#define __PAGETABLE_PUD_FOLDED
 #define PTRS_PER_PMD   1
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PUD   1
 #else /* CONFIG_64BIT */
 #define PTRS_PER_PMD   2048
index 82c19899574f83070158c09c5eed5b438bc092c1..6c79f1b44fe7f7aafd8b5379833fb6ae42cf6f72 100644 (file)
 
 unsigned long ftrace_plt;
 
+static inline void ftrace_generate_orig_insn(struct ftrace_insn *insn)
+{
+#ifdef CC_USING_HOTPATCH
+       /* brcl 0,0 */
+       insn->opc = 0xc004;
+       insn->disp = 0;
+#else
+       /* stg r14,8(r15) */
+       insn->opc = 0xe3e0;
+       insn->disp = 0xf0080024;
+#endif
+}
+
+static inline int is_kprobe_on_ftrace(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       if (insn->opc == BREAKPOINT_INSTRUCTION)
+               return 1;
+#endif
+       return 0;
+}
+
+static inline void ftrace_generate_kprobe_nop_insn(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       insn->opc = BREAKPOINT_INSTRUCTION;
+       insn->disp = KPROBE_ON_FTRACE_NOP;
+#endif
+}
+
+static inline void ftrace_generate_kprobe_call_insn(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       insn->opc = BREAKPOINT_INSTRUCTION;
+       insn->disp = KPROBE_ON_FTRACE_CALL;
+#endif
+}
+
 int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
                       unsigned long addr)
 {
@@ -72,16 +110,9 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
                return -EFAULT;
        if (addr == MCOUNT_ADDR) {
                /* Initial code replacement */
-#ifdef CC_USING_HOTPATCH
-               /* We expect to see brcl 0,0 */
-               ftrace_generate_nop_insn(&orig);
-#else
-               /* We expect to see stg r14,8(r15) */
-               orig.opc = 0xe3e0;
-               orig.disp = 0xf0080024;
-#endif
+               ftrace_generate_orig_insn(&orig);
                ftrace_generate_nop_insn(&new);
-       } else if (old.opc == BREAKPOINT_INSTRUCTION) {
+       } else if (is_kprobe_on_ftrace(&old)) {
                /*
                 * If we find a breakpoint instruction, a kprobe has been
                 * placed at the beginning of the function. We write the
@@ -89,9 +120,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
                 * bytes of the original instruction so that the kprobes
                 * handler can execute a nop, if it reaches this breakpoint.
                 */
-               new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
-               orig.disp = KPROBE_ON_FTRACE_CALL;
-               new.disp = KPROBE_ON_FTRACE_NOP;
+               ftrace_generate_kprobe_call_insn(&orig);
+               ftrace_generate_kprobe_nop_insn(&new);
        } else {
                /* Replace ftrace call with a nop. */
                ftrace_generate_call_insn(&orig, rec->ip);
@@ -111,7 +141,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 
        if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
                return -EFAULT;
-       if (old.opc == BREAKPOINT_INSTRUCTION) {
+       if (is_kprobe_on_ftrace(&old)) {
                /*
                 * If we find a breakpoint instruction, a kprobe has been
                 * placed at the beginning of the function. We write the
@@ -119,9 +149,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
                 * bytes of the original instruction so that the kprobes
                 * handler can execute a brasl if it reaches this breakpoint.
                 */
-               new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
-               orig.disp = KPROBE_ON_FTRACE_NOP;
-               new.disp = KPROBE_ON_FTRACE_CALL;
+               ftrace_generate_kprobe_nop_insn(&orig);
+               ftrace_generate_kprobe_call_insn(&new);
        } else {
                /* Replace nop with an ftrace call. */
                ftrace_generate_nop_insn(&orig);
index cb2d51e779dfafe0bf02077bdd68918dde731511..830066f936c8ffbb6c5359f600f3b1d4a6f7c747 100644 (file)
@@ -36,16 +36,20 @@ static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)
        insn->offset = (entry->target - entry->code) >> 1;
 }
 
-static void jump_label_bug(struct jump_entry *entry, struct insn *insn)
+static void jump_label_bug(struct jump_entry *entry, struct insn *expected,
+                          struct insn *new)
 {
        unsigned char *ipc = (unsigned char *)entry->code;
-       unsigned char *ipe = (unsigned char *)insn;
+       unsigned char *ipe = (unsigned char *)expected;
+       unsigned char *ipn = (unsigned char *)new;
 
        pr_emerg("Jump label code mismatch at %pS [%p]\n", ipc, ipc);
        pr_emerg("Found:    %02x %02x %02x %02x %02x %02x\n",
                 ipc[0], ipc[1], ipc[2], ipc[3], ipc[4], ipc[5]);
        pr_emerg("Expected: %02x %02x %02x %02x %02x %02x\n",
                 ipe[0], ipe[1], ipe[2], ipe[3], ipe[4], ipe[5]);
+       pr_emerg("New:      %02x %02x %02x %02x %02x %02x\n",
+                ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], ipn[5]);
        panic("Corrupted kernel text");
 }
 
@@ -69,10 +73,10 @@ static void __jump_label_transform(struct jump_entry *entry,
        }
        if (init) {
                if (memcmp((void *)entry->code, &orignop, sizeof(orignop)))
-                       jump_label_bug(entry, &old);
+                       jump_label_bug(entry, &orignop, &new);
        } else {
                if (memcmp((void *)entry->code, &old, sizeof(old)))
-                       jump_label_bug(entry, &old);
+                       jump_label_bug(entry, &old, &new);
        }
        probe_kernel_write((void *)entry->code, &new, sizeof(new));
 }
index 36154a2f1814f71a036b68713eeaaf9b1bea7f1f..2ca95862e336d0a040ccc4d968f7aa20da8c4056 100644 (file)
@@ -436,6 +436,7 @@ int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
 {
+       jump_label_apply_nops(me);
        vfree(me->arch.syminfo);
        me->arch.syminfo = NULL;
        return 0;
index c3f8d157cb0d11898bbd72d103dd7b4aceb4b654..e6a1578fc00095929db02b51d4894fe9ad59802c 100644 (file)
@@ -1415,7 +1415,7 @@ CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC_DIAG, PERF_EVENT_CPUM_SF_DIAG);
 
 static struct attribute *cpumsf_pmu_events_attr[] = {
        CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC),
-       CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG),
+       NULL,
        NULL,
 };
 
@@ -1606,8 +1606,11 @@ static int __init init_cpum_sampling_pmu(void)
                return -EINVAL;
        }
 
-       if (si.ad)
+       if (si.ad) {
                sfb_set_limits(CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB);
+               cpumsf_pmu_events_attr[1] =
+                       CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG);
+       }
 
        sfdbg = debug_register(KMSG_COMPONENT, 2, 1, 80);
        if (!sfdbg)
index 26108232fcaaf049f4e4caa3938e537af5066ac6..dc488e13b7e35b216335323a68bd6eac422ce172 100644 (file)
@@ -18,7 +18,7 @@
 
 static DEFINE_PER_CPU(struct cpuid, cpu_id);
 
-void cpu_relax(void)
+void notrace cpu_relax(void)
 {
        if (!smp_cpu_mtid && MACHINE_HAS_DIAG44)
                asm volatile("diag 0,0,0x44");
index 6b09fdffbd2f7e7a787ca5100f074be15ff71f33..ca6294645dd37eeec22c4ab3d26226da37686cd0 100644 (file)
@@ -177,6 +177,17 @@ restart_entry:
        lhi     %r1,1
        sigp    %r1,%r0,SIGP_SET_ARCHITECTURE
        sam64
+#ifdef CONFIG_SMP
+       larl    %r1,smp_cpu_mt_shift
+       icm     %r1,15,0(%r1)
+       jz      smt_done
+       llgfr   %r1,%r1
+smt_loop:
+       sigp    %r1,%r0,SIGP_SET_MULTI_THREADING
+       brc     8,smt_done                      /* accepted */
+       brc     2,smt_loop                      /* busy, try again */
+smt_done:
+#endif
        larl    %r1,.Lnew_pgm_check_psw
        lpswe   0(%r1)
 pgm_check_entry:
index 0c362392756310e1ce0e2da8e35c6bedb5cf0849..19e17bd7aec09b2662874a3925e3d55f4e4207f4 100644 (file)
@@ -165,7 +165,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_ONE_REG:
        case KVM_CAP_ENABLE_CAP:
        case KVM_CAP_S390_CSS_SUPPORT:
-       case KVM_CAP_IRQFD:
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_DEVICE_CTRL:
        case KVM_CAP_ENABLE_CAP_VM:
@@ -522,7 +521,7 @@ static int kvm_s390_set_processor(struct kvm *kvm, struct kvm_device_attr *attr)
                memcpy(&kvm->arch.model.cpu_id, &proc->cpuid,
                       sizeof(struct cpuid));
                kvm->arch.model.ibc = proc->ibc;
-               memcpy(kvm->arch.model.fac->kvm, proc->fac_list,
+               memcpy(kvm->arch.model.fac->list, proc->fac_list,
                       S390_ARCH_FAC_LIST_SIZE_BYTE);
        } else
                ret = -EFAULT;
@@ -556,7 +555,7 @@ static int kvm_s390_get_processor(struct kvm *kvm, struct kvm_device_attr *attr)
        }
        memcpy(&proc->cpuid, &kvm->arch.model.cpu_id, sizeof(struct cpuid));
        proc->ibc = kvm->arch.model.ibc;
-       memcpy(&proc->fac_list, kvm->arch.model.fac->kvm, S390_ARCH_FAC_LIST_SIZE_BYTE);
+       memcpy(&proc->fac_list, kvm->arch.model.fac->list, S390_ARCH_FAC_LIST_SIZE_BYTE);
        if (copy_to_user((void __user *)attr->addr, proc, sizeof(*proc)))
                ret = -EFAULT;
        kfree(proc);
@@ -576,10 +575,10 @@ static int kvm_s390_get_machine(struct kvm *kvm, struct kvm_device_attr *attr)
        }
        get_cpu_id((struct cpuid *) &mach->cpuid);
        mach->ibc = sclp_get_ibc();
-       memcpy(&mach->fac_mask, kvm_s390_fac_list_mask,
-              kvm_s390_fac_list_mask_size() * sizeof(u64));
+       memcpy(&mach->fac_mask, kvm->arch.model.fac->mask,
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
        memcpy((unsigned long *)&mach->fac_list, S390_lowcore.stfle_fac_list,
-              S390_ARCH_FAC_LIST_SIZE_U64);
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
        if (copy_to_user((void __user *)attr->addr, mach, sizeof(*mach)))
                ret = -EFAULT;
        kfree(mach);
@@ -778,15 +777,18 @@ long kvm_arch_vm_ioctl(struct file *filp,
 static int kvm_s390_query_ap_config(u8 *config)
 {
        u32 fcn_code = 0x04000000UL;
-       u32 cc;
+       u32 cc = 0;
 
+       memset(config, 0, 128);
        asm volatile(
                "lgr 0,%1\n"
                "lgr 2,%2\n"
                ".long 0xb2af0000\n"            /* PQAP(QCI) */
-               "ipm %0\n"
+               "0: ipm %0\n"
                "srl %0,28\n"
-               : "=r" (cc)
+               "1:\n"
+               EX_TABLE(0b, 1b)
+               : "+r" (cc)
                : "r" (fcn_code), "r" (config)
                : "cc", "0", "2", "memory"
        );
@@ -839,9 +841,13 @@ static int kvm_s390_crypto_init(struct kvm *kvm)
 
        kvm_s390_set_crycb_format(kvm);
 
-       /* Disable AES/DEA protected key functions by default */
-       kvm->arch.crypto.aes_kw = 0;
-       kvm->arch.crypto.dea_kw = 0;
+       /* Enable AES/DEA protected key functions by default */
+       kvm->arch.crypto.aes_kw = 1;
+       kvm->arch.crypto.dea_kw = 1;
+       get_random_bytes(kvm->arch.crypto.crycb->aes_wrapping_key_mask,
+                        sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask));
+       get_random_bytes(kvm->arch.crypto.crycb->dea_wrapping_key_mask,
+                        sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask));
 
        return 0;
 }
@@ -886,40 +892,29 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        /*
         * The architectural maximum amount of facilities is 16 kbit. To store
         * this amount, 2 kbyte of memory is required. Thus we need a full
-        * page to hold the active copy (arch.model.fac->sie) and the current
-        * facilities set (arch.model.fac->kvm). Its address size has to be
+        * page to hold the guest facility list (arch.model.fac->list) and the
+        * facility mask (arch.model.fac->mask). Its address size has to be
         * 31 bits and word aligned.
         */
        kvm->arch.model.fac =
-               (struct s390_model_fac *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+               (struct kvm_s390_fac *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!kvm->arch.model.fac)
                goto out_nofac;
 
-       memcpy(kvm->arch.model.fac->kvm, S390_lowcore.stfle_fac_list,
-              S390_ARCH_FAC_LIST_SIZE_U64);
-
-       /*
-        * If this KVM host runs *not* in a LPAR, relax the facility bits
-        * of the kvm facility mask by all missing facilities. This will allow
-        * to determine the right CPU model by means of the remaining facilities.
-        * Live guest migration must prohibit the migration of KVMs running in
-        * a LPAR to non LPAR hosts.
-        */
-       if (!MACHINE_IS_LPAR)
-               for (i = 0; i < kvm_s390_fac_list_mask_size(); i++)
-                       kvm_s390_fac_list_mask[i] &= kvm->arch.model.fac->kvm[i];
-
-       /*
-        * Apply the kvm facility mask to limit the kvm supported/tolerated
-        * facility list.
-        */
+       /* Populate the facility mask initially. */
+       memcpy(kvm->arch.model.fac->mask, S390_lowcore.stfle_fac_list,
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
        for (i = 0; i < S390_ARCH_FAC_LIST_SIZE_U64; i++) {
                if (i < kvm_s390_fac_list_mask_size())
-                       kvm->arch.model.fac->kvm[i] &= kvm_s390_fac_list_mask[i];
+                       kvm->arch.model.fac->mask[i] &= kvm_s390_fac_list_mask[i];
                else
-                       kvm->arch.model.fac->kvm[i] = 0UL;
+                       kvm->arch.model.fac->mask[i] = 0UL;
        }
 
+       /* Populate the facility list initially. */
+       memcpy(kvm->arch.model.fac->list, kvm->arch.model.fac->mask,
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
+
        kvm_s390_get_cpu_id(&kvm->arch.model.cpu_id);
        kvm->arch.model.ibc = sclp_get_ibc() & 0x0fff;
 
@@ -1165,8 +1160,6 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 
        mutex_lock(&vcpu->kvm->lock);
        vcpu->arch.cpu_id = vcpu->kvm->arch.model.cpu_id;
-       memcpy(vcpu->kvm->arch.model.fac->sie, vcpu->kvm->arch.model.fac->kvm,
-              S390_ARCH_FAC_LIST_SIZE_BYTE);
        vcpu->arch.sie_block->ibc = vcpu->kvm->arch.model.ibc;
        mutex_unlock(&vcpu->kvm->lock);
 
@@ -1212,7 +1205,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
                vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
                set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
        }
-       vcpu->arch.sie_block->fac = (int) (long) kvm->arch.model.fac->sie;
+       vcpu->arch.sie_block->fac = (int) (long) kvm->arch.model.fac->list;
 
        spin_lock_init(&vcpu->arch.local_int.lock);
        vcpu->arch.local_int.float_int = &kvm->arch.float_int;
index 985c2114d7ef3b9d2b50eb9c33acd314ae9fa3ae..c34109aa552d9b1a6e5ea66f172b5c3e30ad001b 100644 (file)
@@ -128,7 +128,8 @@ static inline void kvm_s390_set_psw_cc(struct kvm_vcpu *vcpu, unsigned long cc)
 /* test availability of facility in a kvm intance */
 static inline int test_kvm_facility(struct kvm *kvm, unsigned long nr)
 {
-       return __test_facility(nr, kvm->arch.model.fac->kvm);
+       return __test_facility(nr, kvm->arch.model.fac->mask) &&
+               __test_facility(nr, kvm->arch.model.fac->list);
 }
 
 /* are cpu states controlled by user space */
index bdd9b5b17e03ed3ab113e73c955f35fbeb8d1560..351116939ea27f2fcf6eb4de60447d86335d0b6e 100644 (file)
@@ -348,7 +348,7 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
         * We need to shift the lower 32 facility bits (bit 0-31) from a u64
         * into a u32 memory representation. They will remain bits 0-31.
         */
-       fac = *vcpu->kvm->arch.model.fac->sie >> 32;
+       fac = *vcpu->kvm->arch.model.fac->list >> 32;
        rc = write_guest_lc(vcpu, offsetof(struct _lowcore, stfl_fac_list),
                            &fac, sizeof(fac));
        if (rc)
index 753a5673195112051667031bfee73921e149eef1..f0b85443e06093d2f5d3d4c5dbe85554e459c138 100644 (file)
@@ -287,7 +287,7 @@ void __iomem *pci_iomap_range(struct pci_dev *pdev,
        addr = ZPCI_IOMAP_ADDR_BASE | ((u64) idx << 48);
        return (void __iomem *) addr + offset;
 }
-EXPORT_SYMBOL_GPL(pci_iomap_range);
+EXPORT_SYMBOL(pci_iomap_range);
 
 void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
 {
@@ -309,7 +309,7 @@ void pci_iounmap(struct pci_dev *pdev, void __iomem *addr)
        }
        spin_unlock(&zpci_iomap_lock);
 }
-EXPORT_SYMBOL_GPL(pci_iounmap);
+EXPORT_SYMBOL(pci_iounmap);
 
 static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
                    int size, u32 *val)
@@ -483,9 +483,8 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev)
        airq_iv_free_bit(zpci_aisb_iv, zdev->aisb);
 }
 
-static void zpci_map_resources(struct zpci_dev *zdev)
+static void zpci_map_resources(struct pci_dev *pdev)
 {
-       struct pci_dev *pdev = zdev->pdev;
        resource_size_t len;
        int i;
 
@@ -499,9 +498,8 @@ static void zpci_map_resources(struct zpci_dev *zdev)
        }
 }
 
-static void zpci_unmap_resources(struct zpci_dev *zdev)
+static void zpci_unmap_resources(struct pci_dev *pdev)
 {
-       struct pci_dev *pdev = zdev->pdev;
        resource_size_t len;
        int i;
 
@@ -651,7 +649,7 @@ int pcibios_add_device(struct pci_dev *pdev)
 
        zdev->pdev = pdev;
        pdev->dev.groups = zpci_attr_groups;
-       zpci_map_resources(zdev);
+       zpci_map_resources(pdev);
 
        for (i = 0; i < PCI_BAR_COUNT; i++) {
                res = &pdev->resource[i];
@@ -663,6 +661,11 @@ int pcibios_add_device(struct pci_dev *pdev)
        return 0;
 }
 
+void pcibios_release_device(struct pci_dev *pdev)
+{
+       zpci_unmap_resources(pdev);
+}
+
 int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
        struct zpci_dev *zdev = get_zdev(pdev);
@@ -670,7 +673,6 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask)
        zdev->pdev = pdev;
        zpci_debug_init_device(zdev);
        zpci_fmb_enable_device(zdev);
-       zpci_map_resources(zdev);
 
        return pci_enable_resources(pdev, mask);
 }
@@ -679,7 +681,6 @@ void pcibios_disable_device(struct pci_dev *pdev)
 {
        struct zpci_dev *zdev = get_zdev(pdev);
 
-       zpci_unmap_resources(zdev);
        zpci_fmb_disable_device(zdev);
        zpci_debug_exit_device(zdev);
        zdev->pdev = NULL;
@@ -688,7 +689,8 @@ void pcibios_disable_device(struct pci_dev *pdev)
 #ifdef CONFIG_HIBERNATE_CALLBACKS
 static int zpci_restore(struct device *dev)
 {
-       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct zpci_dev *zdev = get_zdev(pdev);
        int ret = 0;
 
        if (zdev->state != ZPCI_FN_STATE_ONLINE)
@@ -698,7 +700,7 @@ static int zpci_restore(struct device *dev)
        if (ret)
                goto out;
 
-       zpci_map_resources(zdev);
+       zpci_map_resources(pdev);
        zpci_register_ioat(zdev, 0, zdev->start_dma + PAGE_OFFSET,
                           zdev->start_dma + zdev->iommu_size - 1,
                           (u64) zdev->dma_table);
@@ -709,12 +711,14 @@ out:
 
 static int zpci_freeze(struct device *dev)
 {
-       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct zpci_dev *zdev = get_zdev(pdev);
 
        if (zdev->state != ZPCI_FN_STATE_ONLINE)
                return 0;
 
        zpci_unregister_ioat(zdev, 0);
+       zpci_unmap_resources(pdev);
        return clp_disable_fh(zdev);
 }
 
index 8aa271b3d1ad95b79cb0fa40d130ab76d26fc2bd..b1bb2b72302ca43836720f5232af0a43b0db8d12 100644 (file)
@@ -64,8 +64,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr,
        if (copy_from_user(buf, user_buffer, length))
                goto out;
 
-       memcpy_toio(io_addr, buf, length);
-       ret = 0;
+       ret = zpci_memcpy_toio(io_addr, buf, length);
 out:
        if (buf != local_buf)
                kfree(buf);
@@ -98,16 +97,16 @@ SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr,
                goto out;
        io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
 
-       ret = -EFAULT;
-       if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
+       if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) {
+               ret = -EFAULT;
                goto out;
-
-       memcpy_fromio(buf, io_addr, length);
-
-       if (copy_to_user(user_buffer, buf, length))
+       }
+       ret = zpci_memcpy_fromio(buf, io_addr, length);
+       if (ret)
                goto out;
+       if (copy_to_user(user_buffer, buf, length))
+               ret = -EFAULT;
 
-       ret = 0;
 out:
        if (buf != local_buf)
                kfree(buf);
index 96ac69c5eba016a7b5c1ef93fd35baccf8e2f52b..efb00ec758058afebb97f912e2bc6f142bbd43ff 100644 (file)
@@ -86,6 +86,9 @@ config ARCH_DEFCONFIG
        default "arch/sparc/configs/sparc32_defconfig" if SPARC32
        default "arch/sparc/configs/sparc64_defconfig" if SPARC64
 
+config ARCH_PROC_KCORE_TEXT
+       def_bool y
+
 config IOMMU_HELPER
        bool
        default y if SPARC64
index 4f6725ff4c336878fd3600f840f81897fdc65099..f5b6537306f0b3259e2313f3ec03b3ed32215c49 100644 (file)
@@ -2957,6 +2957,17 @@ unsigned long sun4v_t5_set_perfreg(unsigned long reg_num,
                                   unsigned long reg_val);
 #endif
 
+
+#define HV_FAST_M7_GET_PERFREG 0x43
+#define HV_FAST_M7_SET_PERFREG 0x44
+
+#ifndef        __ASSEMBLY__
+unsigned long sun4v_m7_get_perfreg(unsigned long reg_num,
+                                     unsigned long *reg_val);
+unsigned long sun4v_m7_set_perfreg(unsigned long reg_num,
+                                     unsigned long reg_val);
+#endif
+
 /* Function numbers for HV_CORE_TRAP.  */
 #define HV_CORE_SET_VER                        0x00
 #define HV_CORE_PUTCHAR                        0x01
@@ -2981,6 +2992,7 @@ unsigned long sun4v_t5_set_perfreg(unsigned long reg_num,
 #define HV_GRP_SDIO                    0x0108
 #define HV_GRP_SDIO_ERR                        0x0109
 #define HV_GRP_REBOOT_DATA             0x0110
+#define HV_GRP_M7_PERF                 0x0114
 #define HV_GRP_NIAG_PERF               0x0200
 #define HV_GRP_FIRE_PERF               0x0201
 #define HV_GRP_N2_CPU                  0x0202
index 9b672be70dda6e84802853b0cd6acf7d5aa13e08..50d4840d9aebbfa036c7a110e9f866fa77007647 100644 (file)
@@ -407,16 +407,16 @@ static inline void iounmap(volatile void __iomem *addr)
 {
 }
 
-#define ioread8(X)                     readb(X)
-#define ioread16(X)                    readw(X)
-#define ioread16be(X)                  __raw_readw(X)
-#define ioread32(X)                    readl(X)
-#define ioread32be(X)                  __raw_readl(X)
-#define iowrite8(val,X)                        writeb(val,X)
-#define iowrite16(val,X)               writew(val,X)
-#define iowrite16be(val,X)             __raw_writew(val,X)
-#define iowrite32(val,X)               writel(val,X)
-#define iowrite32be(val,X)             __raw_writel(val,X)
+#define ioread8                        readb
+#define ioread16               readw
+#define ioread16be             __raw_readw
+#define ioread32               readl
+#define ioread32be             __raw_readl
+#define iowrite8               writeb
+#define iowrite16              writew
+#define iowrite16be            __raw_writew
+#define iowrite32              writel
+#define iowrite32be            __raw_writel
 
 /* Create a virtual mapping cookie for an IO port range */
 void __iomem *ioport_map(unsigned long port, unsigned int nr);
index c100dc27a0a9461e677e805224c586eb37082793..176fa0ad19f15d2d41a7234378cc36db144abd57 100644 (file)
@@ -12,7 +12,6 @@
 extern int this_is_starfire;
 
 void check_if_starfire(void);
-int starfire_hard_smp_processor_id(void);
 void starfire_hookup(int);
 unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
 
index 88d322b67fac4d4be308280dd59bd52f2ecf92c0..07cc49e541f40ea2cacc1f952aa7e07dd4a4e69b 100644 (file)
@@ -98,11 +98,7 @@ void sun4v_do_mna(struct pt_regs *regs,
 void do_privop(struct pt_regs *regs);
 void do_privact(struct pt_regs *regs);
 void do_cee(struct pt_regs *regs);
-void do_cee_tl1(struct pt_regs *regs);
-void do_dae_tl1(struct pt_regs *regs);
-void do_iae_tl1(struct pt_regs *regs);
 void do_div0_tl1(struct pt_regs *regs);
-void do_fpdis_tl1(struct pt_regs *regs);
 void do_fpieee_tl1(struct pt_regs *regs);
 void do_fpother_tl1(struct pt_regs *regs);
 void do_ill_tl1(struct pt_regs *regs);
index 5c55145bfbf02d616ec606feb94539e26cbe1831..662500fa555f74160f6449143e6d0785af2643e9 100644 (file)
@@ -48,6 +48,7 @@ static struct api_info api_table[] = {
        { .group = HV_GRP_VT_CPU,                               },
        { .group = HV_GRP_T5_CPU,                               },
        { .group = HV_GRP_DIAG,         .flags = FLAG_PRE_API   },
+       { .group = HV_GRP_M7_PERF,                              },
 };
 
 static DEFINE_SPINLOCK(hvapi_lock);
index caedf8320416e1fe8bfc4cb76369ce1efd8ce729..afbaba52d2f16cb30daf092f5cd3986e7ca9c299 100644 (file)
@@ -837,3 +837,19 @@ ENTRY(sun4v_t5_set_perfreg)
        retl
         nop
 ENDPROC(sun4v_t5_set_perfreg)
+
+ENTRY(sun4v_m7_get_perfreg)
+       mov     %o1, %o4
+       mov     HV_FAST_M7_GET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       stx     %o1, [%o4]
+       retl
+       nop
+ENDPROC(sun4v_m7_get_perfreg)
+
+ENTRY(sun4v_m7_set_perfreg)
+       mov     HV_FAST_M7_SET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       retl
+       nop
+ENDPROC(sun4v_m7_set_perfreg)
index 7e967c8018c8cf19ba1886b39b087d9eb0638b0c..eb978c77c76a78d401e5dce22b4f5bafa8ef948d 100644 (file)
@@ -217,6 +217,31 @@ static const struct pcr_ops n5_pcr_ops = {
        .pcr_nmi_disable        = PCR_N4_PICNPT,
 };
 
+static u64 m7_pcr_read(unsigned long reg_num)
+{
+       unsigned long val;
+
+       (void) sun4v_m7_get_perfreg(reg_num, &val);
+
+       return val;
+}
+
+static void m7_pcr_write(unsigned long reg_num, u64 val)
+{
+       (void) sun4v_m7_set_perfreg(reg_num, val);
+}
+
+static const struct pcr_ops m7_pcr_ops = {
+       .read_pcr               = m7_pcr_read,
+       .write_pcr              = m7_pcr_write,
+       .read_pic               = n4_pic_read,
+       .write_pic              = n4_pic_write,
+       .nmi_picl_value         = n4_picl_value,
+       .pcr_nmi_enable         = (PCR_N4_PICNPT | PCR_N4_STRACE |
+                                  PCR_N4_UTRACE | PCR_N4_TOE |
+                                  (26 << PCR_N4_SL_SHIFT)),
+       .pcr_nmi_disable        = PCR_N4_PICNPT,
+};
 
 static unsigned long perf_hsvc_group;
 static unsigned long perf_hsvc_major;
@@ -248,6 +273,10 @@ static int __init register_perf_hsvc(void)
                        perf_hsvc_group = HV_GRP_T5_CPU;
                        break;
 
+               case SUN4V_CHIP_SPARC_M7:
+                       perf_hsvc_group = HV_GRP_M7_PERF;
+                       break;
+
                default:
                        return -ENODEV;
                }
@@ -293,6 +322,10 @@ static int __init setup_sun4v_pcr_ops(void)
                pcr_ops = &n5_pcr_ops;
                break;
 
+       case SUN4V_CHIP_SPARC_M7:
+               pcr_ops = &m7_pcr_ops;
+               break;
+
        default:
                ret = -ENODEV;
                break;
index 46a5e4508752814cb0ec21b820673cd445b19ada..86eebfa3b15873dfd60117389e9c80f0018a13e0 100644 (file)
@@ -792,6 +792,42 @@ static const struct sparc_pmu niagara4_pmu = {
        .num_pic_regs   = 4,
 };
 
+static void sparc_m7_write_pmc(int idx, u64 val)
+{
+       u64 pcr;
+
+       pcr = pcr_ops->read_pcr(idx);
+       /* ensure ov and ntc are reset */
+       pcr &= ~(PCR_N4_OV | PCR_N4_NTC);
+
+       pcr_ops->write_pic(idx, val & 0xffffffff);
+
+       pcr_ops->write_pcr(idx, pcr);
+}
+
+static const struct sparc_pmu sparc_m7_pmu = {
+       .event_map      = niagara4_event_map,
+       .cache_map      = &niagara4_cache_map,
+       .max_events     = ARRAY_SIZE(niagara4_perfmon_event_map),
+       .read_pmc       = sparc_vt_read_pmc,
+       .write_pmc      = sparc_m7_write_pmc,
+       .upper_shift    = 5,
+       .lower_shift    = 5,
+       .event_mask     = 0x7ff,
+       .user_bit       = PCR_N4_UTRACE,
+       .priv_bit       = PCR_N4_STRACE,
+
+       /* We explicitly don't support hypervisor tracing. */
+       .hv_bit         = 0,
+
+       .irq_bit        = PCR_N4_TOE,
+       .upper_nop      = 0,
+       .lower_nop      = 0,
+       .flags          = 0,
+       .max_hw_events  = 4,
+       .num_pcrs       = 4,
+       .num_pic_regs   = 4,
+};
 static const struct sparc_pmu *sparc_pmu __read_mostly;
 
 static u64 event_encoding(u64 event_id, int idx)
@@ -960,6 +996,8 @@ out:
        cpuc->pcr[0] |= cpuc->event[0]->hw.config_base;
 }
 
+static void sparc_pmu_start(struct perf_event *event, int flags);
+
 /* On this PMU each PIC has it's own PCR control register.  */
 static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc)
 {
@@ -972,20 +1010,13 @@ static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc)
                struct perf_event *cp = cpuc->event[i];
                struct hw_perf_event *hwc = &cp->hw;
                int idx = hwc->idx;
-               u64 enc;
 
                if (cpuc->current_idx[i] != PIC_NO_INDEX)
                        continue;
 
-               sparc_perf_event_set_period(cp, hwc, idx);
                cpuc->current_idx[i] = idx;
 
-               enc = perf_event_get_enc(cpuc->events[i]);
-               cpuc->pcr[idx] &= ~mask_for_index(idx);
-               if (hwc->state & PERF_HES_STOPPED)
-                       cpuc->pcr[idx] |= nop_for_index(idx);
-               else
-                       cpuc->pcr[idx] |= event_encoding(enc, idx);
+               sparc_pmu_start(cp, PERF_EF_RELOAD);
        }
 out:
        for (i = 0; i < cpuc->n_events; i++) {
@@ -1101,7 +1132,6 @@ static void sparc_pmu_del(struct perf_event *event, int _flags)
        int i;
 
        local_irq_save(flags);
-       perf_pmu_disable(event->pmu);
 
        for (i = 0; i < cpuc->n_events; i++) {
                if (event == cpuc->event[i]) {
@@ -1127,7 +1157,6 @@ static void sparc_pmu_del(struct perf_event *event, int _flags)
                }
        }
 
-       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
 }
 
@@ -1361,7 +1390,6 @@ static int sparc_pmu_add(struct perf_event *event, int ef_flags)
        unsigned long flags;
 
        local_irq_save(flags);
-       perf_pmu_disable(event->pmu);
 
        n0 = cpuc->n_events;
        if (n0 >= sparc_pmu->max_hw_events)
@@ -1394,7 +1422,6 @@ nocheck:
 
        ret = 0;
 out:
-       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
        return ret;
 }
@@ -1667,6 +1694,10 @@ static bool __init supported_pmu(void)
                sparc_pmu = &niagara4_pmu;
                return true;
        }
+       if (!strcmp(sparc_pmu_type, "sparc-m7")) {
+               sparc_pmu = &sparc_m7_pmu;
+               return true;
+       }
        return false;
 }
 
index 0be7bf978cb1da03b8d657958ec6d0ec3c4e7d8b..46a59643bb1cee71edbd3d91d3f8f2eb09b3a26a 100644 (file)
@@ -287,6 +287,8 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
                        printk("             TPC[%lx] O7[%lx] I7[%lx] RPC[%lx]\n",
                               gp->tpc, gp->o7, gp->i7, gp->rpc);
                }
+
+               touch_nmi_watchdog();
        }
 
        memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
@@ -362,6 +364,8 @@ static void pmu_snapshot_all_cpus(void)
                       (cpu == this_cpu ? '*' : ' '), cpu,
                       pp->pcr[0], pp->pcr[1], pp->pcr[2], pp->pcr[3],
                       pp->pic[0], pp->pic[1], pp->pic[2], pp->pic[3]);
+
+               touch_nmi_watchdog();
        }
 
        memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
index da6f1a7fc4db4713425d1927af185cb797b4c1fc..61139d9924cae4a8fdf5d4d5366a31052ea29616 100644 (file)
@@ -1406,11 +1406,32 @@ void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
        scheduler_ipi();
 }
 
-/* This is a nop because we capture all other cpus
- * anyways when making the PROM active.
- */
+static void stop_this_cpu(void *dummy)
+{
+       prom_stopself();
+}
+
 void smp_send_stop(void)
 {
+       int cpu;
+
+       if (tlb_type == hypervisor) {
+               for_each_online_cpu(cpu) {
+                       if (cpu == smp_processor_id())
+                               continue;
+#ifdef CONFIG_SUN_LDOMS
+                       if (ldom_domaining_enabled) {
+                               unsigned long hv_err;
+                               hv_err = sun4v_cpu_stop(cpu);
+                               if (hv_err)
+                                       printk(KERN_ERR "sun4v_cpu_stop() "
+                                              "failed err=%lu\n", hv_err);
+                       } else
+#endif
+                               prom_stopcpu_cpuid(cpu);
+               }
+       } else
+               smp_call_function(stop_this_cpu, NULL, 0);
 }
 
 /**
index 82281a566bb86b866525a18b8fc4ca453d2e1e60..167fdfd9c83702bd2ccdc737625fcc8f57c9619c 100644 (file)
@@ -28,11 +28,6 @@ void check_if_starfire(void)
                this_is_starfire = 1;
 }
 
-int starfire_hard_smp_processor_id(void)
-{
-       return upa_readl(0x1fff40000d0UL);
-}
-
 /*
  * Each Starfire board has 32 registers which perform translation
  * and delivery of traditional interrupt packets into the extended
index c85403d0496c24f7639a32fa06b7dc53c1559381..30e7ddb27a3a966e74e5ab79ad686bab26eab459 100644 (file)
@@ -333,7 +333,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
        long err;
 
        /* No need for backward compatibility. We can start fresh... */
-       if (call <= SEMCTL) {
+       if (call <= SEMTIMEDOP) {
                switch (call) {
                case SEMOP:
                        err = sys_semtimedop(first, ptr,
index a27651e866e7a108dca92cf88c14ec8f21ae5b5b..0e699745d64311d44439327d3e971ce78114b7da 100644 (file)
@@ -2427,6 +2427,8 @@ void __noreturn die_if_kernel(char *str, struct pt_regs *regs)
                }
                user_instruction_dump ((unsigned int __user *) regs->tpc);
        }
+       if (panic_on_oops)
+               panic("Fatal exception");
        if (regs->tstate & TSTATE_PRIV)
                do_exit(SIGKILL);
        do_exit(SIGSEGV);
@@ -2564,27 +2566,6 @@ void do_cee(struct pt_regs *regs)
        die_if_kernel("TL0: Cache Error Exception", regs);
 }
 
-void do_cee_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Cache Error Exception", regs);
-}
-
-void do_dae_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Data Access Exception", regs);
-}
-
-void do_iae_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Instruction Access Exception", regs);
-}
-
 void do_div0_tl1(struct pt_regs *regs)
 {
        exception_enter();
@@ -2592,13 +2573,6 @@ void do_div0_tl1(struct pt_regs *regs)
        die_if_kernel("TL1: DIV0 Exception", regs);
 }
 
-void do_fpdis_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: FPU Disabled", regs);
-}
-
 void do_fpieee_tl1(struct pt_regs *regs)
 {
        exception_enter();
index b7f6334e159f9d22fc34ccc2f003511009ca9b61..857ad4f8905f942f44ac40770c9277323e4e3c09 100644 (file)
@@ -8,9 +8,11 @@
 
        .text
 ENTRY(memmove) /* o0=dst o1=src o2=len */
-       mov             %o0, %g1
+       brz,pn          %o2, 99f
+        mov            %o0, %g1
+
        cmp             %o0, %o1
-       bleu,pt         %xcc, memcpy
+       bleu,pt         %xcc, 2f
         add            %o1, %o2, %g7
        cmp             %g7, %o0
        bleu,pt         %xcc, memcpy
@@ -24,7 +26,34 @@ ENTRY(memmove) /* o0=dst o1=src o2=len */
        stb             %g7, [%o0]
        bne,pt          %icc, 1b
         sub            %o0, 1, %o0
-
+99:
        retl
         mov            %g1, %o0
+
+       /* We can't just call memcpy for these memmove cases.  On some
+        * chips the memcpy uses cache initializing stores and when dst
+        * and src are close enough, those can clobber the source data
+        * before we've loaded it in.
+        */
+2:     or              %o0, %o1, %g7
+       or              %o2, %g7, %g7
+       andcc           %g7, 0x7, %g0
+       bne,pn          %xcc, 4f
+        nop
+
+3:     ldx             [%o1], %g7
+       add             %o1, 8, %o1
+       subcc           %o2, 8, %o2
+       add             %o0, 8, %o0
+       bne,pt          %icc, 3b
+        stx            %g7, [%o0 - 0x8]
+       ba,a,pt         %xcc, 99b
+
+4:     ldub            [%o1], %g7
+       add             %o1, 1, %o1
+       subcc           %o2, 1, %o2
+       add             %o0, 1, %o0
+       bne,pt          %icc, 4b
+        stb            %g7, [%o0 - 0x1]
+       ba,a,pt         %xcc, 99b
 ENDPROC(memmove)
index 3ea267c53320d49683ab39c9e0d95189e4adb56e..4ca0d6ba5ec8331c67f43f8515eb3737526208bb 100644 (file)
@@ -2820,7 +2820,7 @@ static int __init report_memory(void)
 
        return 0;
 }
-device_initcall(report_memory);
+arch_initcall(report_memory);
 
 #ifdef CONFIG_SMP
 #define do_flush_tlb_kernel_range      smp_flush_tlb_kernel_range
index c2fb8a87dccb2990a794bb8960bfdad85eb9a390..b7d31ca5518744983c77bc8339f30756621dfea0 100644 (file)
@@ -499,6 +499,7 @@ config X86_INTEL_QUARK
        depends on X86_IO_APIC
        select IOSF_MBI
        select INTEL_IMR
+       select COMMON_CLK
        ---help---
          Select to include support for Quark X1000 SoC.
          Say Y here if you have a Quark based system such as the Arduino
index 7083c16cccba0b2b144ea5e03e160ebafe81e855..bb1376381985edb9f96e49c0a1b0269e56bd0f9e 100644 (file)
 static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
                LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
 
-struct kaslr_setup_data {
-       __u64 next;
-       __u32 type;
-       __u32 len;
-       __u8 data[1];
-} kaslr_setup_data;
-
 #define I8254_PORT_CONTROL     0x43
 #define I8254_PORT_COUNTER0    0x40
 #define I8254_CMD_READBACK     0xC0
@@ -302,29 +295,7 @@ static unsigned long find_random_addr(unsigned long minimum,
        return slots_fetch_random();
 }
 
-static void add_kaslr_setup_data(struct boot_params *params, __u8 enabled)
-{
-       struct setup_data *data;
-
-       kaslr_setup_data.type = SETUP_KASLR;
-       kaslr_setup_data.len = 1;
-       kaslr_setup_data.next = 0;
-       kaslr_setup_data.data[0] = enabled;
-
-       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
-
-       while (data && data->next)
-               data = (struct setup_data *)(unsigned long)data->next;
-
-       if (data)
-               data->next = (unsigned long)&kaslr_setup_data;
-       else
-               params->hdr.setup_data = (unsigned long)&kaslr_setup_data;
-
-}
-
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size)
@@ -335,17 +306,14 @@ unsigned char *choose_kernel_location(struct boot_params *params,
 #ifdef CONFIG_HIBERNATION
        if (!cmdline_find_option_bool("kaslr")) {
                debug_putstr("KASLR disabled by default...\n");
-               add_kaslr_setup_data(params, 0);
                goto out;
        }
 #else
        if (cmdline_find_option_bool("nokaslr")) {
                debug_putstr("KASLR disabled by cmdline...\n");
-               add_kaslr_setup_data(params, 0);
                goto out;
        }
 #endif
-       add_kaslr_setup_data(params, 1);
 
        /* Record the various known unsafe memory ranges. */
        mem_avoid_init((unsigned long)input, input_size,
index 5903089c818f6843b9d1cc7c83507cf0d28a3e26..a950864a64dab3d558197c77bef3c56a07961494 100644 (file)
@@ -401,8 +401,7 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
         * the entire decompressed kernel plus relocation table, or the
         * entire decompressed kernel plus .bss and .brk sections.
         */
-       output = choose_kernel_location(real_mode, input_data, input_len,
-                                       output,
+       output = choose_kernel_location(input_data, input_len, output,
                                        output_len > run_size ? output_len
                                                              : run_size);
 
index ee3576b2666b8139eedf25077ce769da10712c11..04477d68403f1fe6197d82276033ce27338c1bac 100644 (file)
@@ -57,8 +57,7 @@ int cmdline_find_option_bool(const char *option);
 
 #if CONFIG_RANDOMIZE_BASE
 /* aslr.c */
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size);
@@ -66,8 +65,7 @@ unsigned char *choose_kernel_location(struct boot_params *params,
 bool has_cpuflag(int flag);
 #else
 static inline
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size)
index 947c6bf52c330452cfb7ac4a19d368f68f4e4509..54f60ab41c63025fd2cb42e5579df7f69c3d9b60 100644 (file)
@@ -1155,7 +1155,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
                src = kmalloc(req->cryptlen + req->assoclen, GFP_ATOMIC);
                if (!src)
                        return -ENOMEM;
-               assoc = (src + req->cryptlen + auth_tag_len);
+               assoc = (src + req->cryptlen);
                scatterwalk_map_and_copy(src, req->src, 0, req->cryptlen, 0);
                scatterwalk_map_and_copy(assoc, req->assoc, 0,
                        req->assoclen, 0);
@@ -1180,7 +1180,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
                scatterwalk_done(&src_sg_walk, 0, 0);
                scatterwalk_done(&assoc_sg_walk, 0, 0);
        } else {
-               scatterwalk_map_and_copy(dst, req->dst, 0, req->cryptlen, 1);
+               scatterwalk_map_and_copy(dst, req->dst, 0, tempCipherLen, 1);
                kfree(src);
        }
        return retval;
index 0dbc08282291044216456e6c14a802d56a0e40d8..72ba21a8b5fc2ff8b76c6c3e53b331ca6a558339 100644 (file)
@@ -370,7 +370,7 @@ static inline void drop_fpu(struct task_struct *tsk)
        preempt_disable();
        tsk->thread.fpu_counter = 0;
        __drop_fpu(tsk);
-       clear_used_math();
+       clear_stopped_child_used_math(tsk);
        preempt_enable();
 }
 
index 95e11f79f123c6aadd5ed8888a51e1870405deeb..f97fbe3abb67f5059d4e6f0a37261d6113df19de 100644 (file)
@@ -51,8 +51,6 @@ extern int devmem_is_allowed(unsigned long pagenr);
 extern unsigned long max_low_pfn_mapped;
 extern unsigned long max_pfn_mapped;
 
-extern bool kaslr_enabled;
-
 static inline phys_addr_t get_max_mapped(void)
 {
        return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT;
index fa1195dae42541aaa1d836782a3a65aa25640e74..164e3f8d3c3dbb6eb4fc0ea60e01cae15fe5116e 100644 (file)
@@ -93,6 +93,8 @@ extern raw_spinlock_t pci_config_lock;
 extern int (*pcibios_enable_irq)(struct pci_dev *dev);
 extern void (*pcibios_disable_irq)(struct pci_dev *dev);
 
+extern bool mp_should_keep_irq(struct device *dev);
+
 struct pci_raw_ops {
        int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
                                                int reg, int len, u32 *val);
index 5fa9770035dc935c0a90899f470e668ab889ec7f..c9a6d68b8d623b84d169f61c4680c194ea8d137a 100644 (file)
@@ -82,18 +82,15 @@ static inline int xsave_state_booting(struct xsave_struct *fx, u64 mask)
        if (boot_cpu_has(X86_FEATURE_XSAVES))
                asm volatile("1:"XSAVES"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
        else
                asm volatile("1:"XSAVE"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
-
-       asm volatile(xstate_fault
-                    : "0" (0)
-                    : "memory");
-
        return err;
 }
 
@@ -112,18 +109,15 @@ static inline int xrstor_state_booting(struct xsave_struct *fx, u64 mask)
        if (boot_cpu_has(X86_FEATURE_XSAVES))
                asm volatile("1:"XRSTORS"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
        else
                asm volatile("1:"XRSTOR"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
-
-       asm volatile(xstate_fault
-                    : "0" (0)
-                    : "memory");
-
        return err;
 }
 
@@ -149,9 +143,9 @@ static inline int xsave_state(struct xsave_struct *fx, u64 mask)
         */
        alternative_input_2(
                "1:"XSAVE,
-               "1:"XSAVEOPT,
+               XSAVEOPT,
                X86_FEATURE_XSAVEOPT,
-               "1:"XSAVES,
+               XSAVES,
                X86_FEATURE_XSAVES,
                [fx] "D" (fx), "a" (lmask), "d" (hmask) :
                "memory");
@@ -178,7 +172,7 @@ static inline int xrstor_state(struct xsave_struct *fx, u64 mask)
         */
        alternative_input(
                "1: " XRSTOR,
-               "1: " XRSTORS,
+               XRSTORS,
                X86_FEATURE_XSAVES,
                "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                : "memory");
index 44e6dd7e36a23becd48def85b218b1d70ac938e6..225b0988043a0a78ac9092a9af7a265122c685cd 100644 (file)
@@ -7,7 +7,6 @@
 #define SETUP_DTB                      2
 #define SETUP_PCI                      3
 #define SETUP_EFI                      4
-#define SETUP_KASLR                    5
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK       0x07FF
index 3d525c6124f6c720e02d2761b283151be97cf6d7..803b684676ff3d0bcc6a17c530a457efcf485fca 100644 (file)
@@ -1337,6 +1337,26 @@ static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
        return 0;
 }
 
+/*
+ * ACPI offers an alternative platform interface model that removes
+ * ACPI hardware requirements for platforms that do not implement
+ * the PC Architecture.
+ *
+ * We initialize the Hardware-reduced ACPI model here:
+ */
+static void __init acpi_reduced_hw_init(void)
+{
+       if (acpi_gbl_reduced_hardware) {
+               /*
+                * Override x86_init functions and bypass legacy pic
+                * in Hardware-reduced ACPI mode
+                */
+               x86_init.timers.timer_init      = x86_init_noop;
+               x86_init.irqs.pre_vector_init   = x86_init_noop;
+               legacy_pic                      = &null_legacy_pic;
+       }
+}
+
 /*
  * If your system is blacklisted here, but you find that acpi=force
  * works for you, please contact linux-acpi@vger.kernel.org
@@ -1536,6 +1556,11 @@ int __init early_acpi_boot_init(void)
         */
        early_acpi_process_madt();
 
+       /*
+        * Hardware-reduced ACPI mode initialization:
+        */
+       acpi_reduced_hw_init();
+
        return 0;
 }
 
index c2fd21fed00284066ab138354a4daefbc1b775ac..017149cded0760ccc842db2a50d3c2013321aa52 100644 (file)
@@ -37,10 +37,12 @@ static const struct apic apic_numachip;
 static unsigned int get_apic_id(unsigned long x)
 {
        unsigned long value;
-       unsigned int id;
+       unsigned int id = (x >> 24) & 0xff;
 
-       rdmsrl(MSR_FAM10H_NODE_ID, value);
-       id = ((x >> 24) & 0xffU) | ((value << 2) & 0xff00U);
+       if (static_cpu_has_safe(X86_FEATURE_NODEID_MSR)) {
+               rdmsrl(MSR_FAM10H_NODE_ID, value);
+               id |= (value << 2) & 0xff00;
+       }
 
        return id;
 }
@@ -155,10 +157,18 @@ static int __init numachip_probe(void)
 
 static void fixup_cpu_id(struct cpuinfo_x86 *c, int node)
 {
-       if (c->phys_proc_id != node) {
-               c->phys_proc_id = node;
-               per_cpu(cpu_llc_id, smp_processor_id()) = node;
+       u64 val;
+       u32 nodes = 1;
+
+       this_cpu_write(cpu_llc_id, node);
+
+       /* Account for nodes per socket in multi-core-module processors */
+       if (static_cpu_has_safe(X86_FEATURE_NODEID_MSR)) {
+               rdmsrl(MSR_FAM10H_NODE_ID, val);
+               nodes = ((val >> 3) & 7) + 1;
        }
+
+       c->phys_proc_id = node / nodes;
 }
 
 static int __init numachip_system_init(void)
index b5c8ff5e9dfcad79075a1af5f41b0ac0ee37231b..2346c95c6ab1945077fdde28c129342ffe09749d 100644 (file)
@@ -1396,6 +1396,12 @@ void cpu_init(void)
 
        wait_for_master_cpu(cpu);
 
+       /*
+        * Initialize the CR4 shadow before doing anything that could
+        * try to read it.
+        */
+       cr4_init_shadow();
+
        show_ucode_info_early();
 
        printk(KERN_INFO "Initializing CPU#%d\n", cpu);
index 94d7dcb1214530dfa86b4fef2f2bcbf007d32fe4..50163fa9034f0d2f4db28767432a249ad9e0cb35 100644 (file)
@@ -565,8 +565,8 @@ static const struct _tlb_table intel_tlb_table[] = {
        { 0xb2, TLB_INST_4K,            64,     " TLB_INST 4KByte pages, 4-way set associative" },
        { 0xb3, TLB_DATA_4K,            128,    " TLB_DATA 4 KByte pages, 4-way set associative" },
        { 0xb4, TLB_DATA_4K,            256,    " TLB_DATA 4 KByte pages, 4-way associative" },
-       { 0xb5, TLB_INST_4K,            64,     " TLB_INST 4 KByte pages, 8-way set ssociative" },
-       { 0xb6, TLB_INST_4K,            128,    " TLB_INST 4 KByte pages, 8-way set ssociative" },
+       { 0xb5, TLB_INST_4K,            64,     " TLB_INST 4 KByte pages, 8-way set associative" },
+       { 0xb6, TLB_INST_4K,            128,    " TLB_INST 4 KByte pages, 8-way set associative" },
        { 0xba, TLB_DATA_4K,            64,     " TLB_DATA 4 KByte pages, 4-way associative" },
        { 0xc0, TLB_DATA_4K_4M,         8,      " TLB_DATA 4 KByte and 4 MByte pages, 4-way associative" },
        { 0xc1, STLB_4K_2M,             1024,   " STLB 4 KByte and 2 MByte pages, 8-way associative" },
index 000d4199b03e69905527d7972ccd918835e6cc1f..31e2d5bf3e38887ca06402bff6c647b9aa9a3c5c 100644 (file)
@@ -982,6 +982,9 @@ ENTRY(xen_hypervisor_callback)
 ENTRY(xen_do_upcall)
 1:     mov %esp, %eax
        call xen_evtchn_do_upcall
+#ifndef CONFIG_PREEMPT
+       call xen_maybe_preempt_hcall
+#endif
        jmp  ret_from_intr
        CFI_ENDPROC
 ENDPROC(xen_hypervisor_callback)
index db13655c3a2aff4a4475a9adf6ce1cb5b3639220..2babb393915e76dbeb8a1b757305b819fddd324b 100644 (file)
@@ -269,11 +269,14 @@ ENTRY(ret_from_fork)
        testl $3, CS-ARGOFFSET(%rsp)            # from kernel_thread?
        jz   1f
 
-       testl $_TIF_IA32, TI_flags(%rcx)        # 32-bit compat task needs IRET
-       jnz  int_ret_from_sys_call
-
-       RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET
-       jmp ret_from_sys_call                   # go to the SYSRET fastpath
+       /*
+        * By the time we get here, we have no idea whether our pt_regs,
+        * ti flags, and ti status came from the 64-bit SYSCALL fast path,
+        * the slow path, or one of the ia32entry paths.
+        * Use int_ret_from_sys_call to return, since it can safely handle
+        * all of the above.
+        */
+       jmp  int_ret_from_sys_call
 
 1:
        subq $REST_SKIP, %rsp   # leave space for volatiles
@@ -361,12 +364,21 @@ system_call_fastpath:
  * Has incomplete stack frame and undefined top of stack.
  */
 ret_from_sys_call:
-       testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
-       jnz int_ret_from_sys_call_fixup /* Go the the slow path */
-
        LOCKDEP_SYS_EXIT
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
+
+       /*
+        * We must check ti flags with interrupts (or at least preemption)
+        * off because we must *never* return to userspace without
+        * processing exit work that is enqueued if we're preempted here.
+        * In particular, returning to userspace with any of the one-shot
+        * flags (TIF_NOTIFY_RESUME, TIF_USER_RETURN_NOTIFY, etc) set is
+        * very bad.
+        */
+       testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
+       jnz int_ret_from_sys_call_fixup /* Go the the slow path */
+
        CFI_REMEMBER_STATE
        /*
         * sysretq will re-enable interrupts:
@@ -383,7 +395,7 @@ ret_from_sys_call:
 
 int_ret_from_sys_call_fixup:
        FIXUP_TOP_OF_STACK %r11, -ARGOFFSET
-       jmp int_ret_from_sys_call
+       jmp int_ret_from_sys_call_irqs_off
 
        /* Do syscall tracing */
 tracesys:
@@ -429,6 +441,7 @@ tracesys_phase2:
 GLOBAL(int_ret_from_sys_call)
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
+int_ret_from_sys_call_irqs_off:
        movl $_TIF_ALLWORK_MASK,%edi
        /* edi: mask to check */
 GLOBAL(int_with_check)
@@ -1208,6 +1221,9 @@ ENTRY(xen_do_hypervisor_callback)   # do_hypervisor_callback(struct *pt_regs)
        popq %rsp
        CFI_DEF_CFA_REGISTER rsp
        decl PER_CPU_VAR(irq_count)
+#ifndef CONFIG_PREEMPT
+       call xen_maybe_preempt_hcall
+#endif
        jmp  error_exit
        CFI_ENDPROC
 END(xen_do_hypervisor_callback)
index 6a1146ea4d4d885dfa197e4d6aea6562c5d05c7e..4e3d5a9621fe0052fac43d5ad6c109b9d3f54447 100644 (file)
@@ -223,27 +223,48 @@ static unsigned long
 __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
 {
        struct kprobe *kp;
+       unsigned long faddr;
 
        kp = get_kprobe((void *)addr);
-       /* There is no probe, return original address */
-       if (!kp)
+       faddr = ftrace_location(addr);
+       /*
+        * Addresses inside the ftrace location are refused by
+        * arch_check_ftrace_location(). Something went terribly wrong
+        * if such an address is checked here.
+        */
+       if (WARN_ON(faddr && faddr != addr))
+               return 0UL;
+       /*
+        * Use the current code if it is not modified by Kprobe
+        * and it cannot be modified by ftrace.
+        */
+       if (!kp && !faddr)
                return addr;
 
        /*
-        *  Basically, kp->ainsn.insn has an original instruction.
-        *  However, RIP-relative instruction can not do single-stepping
-        *  at different place, __copy_instruction() tweaks the displacement of
-        *  that instruction. In that case, we can't recover the instruction
-        *  from the kp->ainsn.insn.
+        * Basically, kp->ainsn.insn has an original instruction.
+        * However, RIP-relative instruction can not do single-stepping
+        * at different place, __copy_instruction() tweaks the displacement of
+        * that instruction. In that case, we can't recover the instruction
+        * from the kp->ainsn.insn.
         *
-        *  On the other hand, kp->opcode has a copy of the first byte of
-        *  the probed instruction, which is overwritten by int3. And
-        *  the instruction at kp->addr is not modified by kprobes except
-        *  for the first byte, we can recover the original instruction
-        *  from it and kp->opcode.
+        * On the other hand, in case on normal Kprobe, kp->opcode has a copy
+        * of the first byte of the probed instruction, which is overwritten
+        * by int3. And the instruction at kp->addr is not modified by kprobes
+        * except for the first byte, we can recover the original instruction
+        * from it and kp->opcode.
+        *
+        * In case of Kprobes using ftrace, we do not have a copy of
+        * the original instruction. In fact, the ftrace location might
+        * be modified at anytime and even could be in an inconsistent state.
+        * Fortunately, we know that the original code is the ideal 5-byte
+        * long NOP.
         */
-       memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
-       buf[0] = kp->opcode;
+       memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+       if (faddr)
+               memcpy(buf, ideal_nops[NOP_ATOMIC5], 5);
+       else
+               buf[0] = kp->opcode;
        return (unsigned long)buf;
 }
 
@@ -251,6 +272,7 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
  * Recover the probed instruction at addr for further analysis.
  * Caller must lock kprobes by kprobe_mutex, or disable preemption
  * for preventing to release referencing kprobes.
+ * Returns zero if the instruction can not get recovered.
  */
 unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
 {
@@ -285,6 +307,8 @@ static int can_probe(unsigned long paddr)
                 * normally used, we just go through if there is no kprobe.
                 */
                __addr = recover_probed_instruction(buf, addr);
+               if (!__addr)
+                       return 0;
                kernel_insn_init(&insn, (void *)__addr, MAX_INSN_SIZE);
                insn_get_length(&insn);
 
@@ -333,6 +357,8 @@ int __copy_instruction(u8 *dest, u8 *src)
        unsigned long recovered_insn =
                recover_probed_instruction(buf, (unsigned long)src);
 
+       if (!recovered_insn)
+               return 0;
        kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
        insn_get_length(&insn);
        /* Another subsystem puts a breakpoint, failed to recover */
index 0dd8d089c315e0e9df338e9144799c6e900df831..7b3b9d15c47a63953d6932026cc57db795e3a507 100644 (file)
@@ -259,6 +259,8 @@ static int can_optimize(unsigned long paddr)
                         */
                        return 0;
                recovered_insn = recover_probed_instruction(buf, addr);
+               if (!recovered_insn)
+                       return 0;
                kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
                insn_get_length(&insn);
                /* Another subsystem puts a breakpoint */
index 9bbb9b35c144a4f721ed4e7dcfc07aee6abdc2cb..d1ac80b72c72184a0b999c2b299b5e265d26de7a 100644 (file)
@@ -47,13 +47,21 @@ do {                                                        \
 
 #ifdef CONFIG_RANDOMIZE_BASE
 static unsigned long module_load_offset;
+static int randomize_modules = 1;
 
 /* Mutex protects the module_load_offset. */
 static DEFINE_MUTEX(module_kaslr_mutex);
 
+static int __init parse_nokaslr(char *p)
+{
+       randomize_modules = 0;
+       return 0;
+}
+early_param("nokaslr", parse_nokaslr);
+
 static unsigned long int get_module_load_offset(void)
 {
-       if (kaslr_enabled) {
+       if (randomize_modules) {
                mutex_lock(&module_kaslr_mutex);
                /*
                 * Calculate the module_load_offset the first time this
index 98dc9317286e1e0fad25f3d10efaa3134a9134c0..0a2421cca01fad095bbb7caa8e7c779d910d751b 100644 (file)
 unsigned long max_low_pfn_mapped;
 unsigned long max_pfn_mapped;
 
-bool __read_mostly kaslr_enabled = false;
-
 #ifdef CONFIG_DMI
 RESERVE_BRK(dmi_alloc, 65536);
 #endif
@@ -427,11 +425,6 @@ static void __init reserve_initrd(void)
 }
 #endif /* CONFIG_BLK_DEV_INITRD */
 
-static void __init parse_kaslr_setup(u64 pa_data, u32 data_len)
-{
-       kaslr_enabled = (bool)(pa_data + sizeof(struct setup_data));
-}
-
 static void __init parse_setup_data(void)
 {
        struct setup_data *data;
@@ -457,9 +450,6 @@ static void __init parse_setup_data(void)
                case SETUP_EFI:
                        parse_efi_setup(pa_data, data_len);
                        break;
-               case SETUP_KASLR:
-                       parse_kaslr_setup(pa_data, data_len);
-                       break;
                default:
                        break;
                }
@@ -842,14 +832,10 @@ static void __init trim_low_memory_range(void)
 static int
 dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
 {
-       if (kaslr_enabled)
-               pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n",
-                        (unsigned long)&_text - __START_KERNEL,
-                        __START_KERNEL,
-                        __START_KERNEL_map,
-                        MODULES_VADDR-1);
-       else
-               pr_emerg("Kernel Offset: disabled\n");
+       pr_emerg("Kernel Offset: 0x%lx from 0x%lx "
+                "(relocation range: 0x%lx-0x%lx)\n",
+                (unsigned long)&_text - __START_KERNEL, __START_KERNEL,
+                __START_KERNEL_map, MODULES_VADDR-1);
 
        return 0;
 }
index 9d2073e2ecc92f5c97d51178236d8b2bc63ac029..4ff5d162ff9fd55381259ff8dd96f84064ecea72 100644 (file)
@@ -384,7 +384,7 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
                goto exit;
        conditional_sti(regs);
 
-       if (!user_mode(regs))
+       if (!user_mode_vm(regs))
                die("bounds", regs, error_code);
 
        if (!cpu_feature_enabled(X86_FEATURE_MPX)) {
@@ -637,7 +637,7 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code)
         * then it's very likely the result of an icebp/int01 trap.
         * User wants a sigtrap for that.
         */
-       if (!dr6 && user_mode(regs))
+       if (!dr6 && user_mode_vm(regs))
                user_icebp = 1;
 
        /* Catch kmemcheck conditions first of all! */
index 34f66e58a896693d392e4ed074b1f9ca664974d3..cdc6cf90307800abb83f1b4b516ba389212c3dd0 100644 (file)
@@ -379,7 +379,7 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
                 * thread's fpu state, reconstruct fxstate from the fsave
                 * header. Sanitize the copied state etc.
                 */
-               struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
+               struct fpu *fpu = &tsk->thread.fpu;
                struct user_i387_ia32_struct env;
                int err = 0;
 
@@ -393,14 +393,15 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
                 */
                drop_fpu(tsk);
 
-               if (__copy_from_user(xsave, buf_fx, state_size) ||
+               if (__copy_from_user(&fpu->state->xsave, buf_fx, state_size) ||
                    __copy_from_user(&env, buf, sizeof(env))) {
+                       fpu_finit(fpu);
                        err = -1;
                } else {
                        sanitize_restored_xstate(tsk, &env, xstate_bv, fx_only);
-                       set_used_math();
                }
 
+               set_used_math();
                if (use_eager_fpu()) {
                        preempt_disable();
                        math_state_restore();
index e0b794a84c35cdd7ecc03bc6de6500b0ac237f57..106c01557f2b63706eca28e462a3b072b590f0c5 100644 (file)
@@ -4950,7 +4950,8 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
                        goto done;
                }
        }
-       ctxt->dst.orig_val = ctxt->dst.val;
+       /* Copy full 64-bit value for CMPXCHG8B.  */
+       ctxt->dst.orig_val64 = ctxt->dst.val64;
 
 special_insn:
 
index cc31f7c06d3ddc8ab4ef61c775510e2dcbfde518..9541ba34126b90123ddfe383453145ddfcf789c4 100644 (file)
@@ -507,6 +507,7 @@ static int picdev_read(struct kvm_pic *s,
                return -EOPNOTSUPP;
 
        if (len != 1) {
+               memset(val, 0, len);
                pr_pic_unimpl("non byte read\n");
                return 0;
        }
index b1947e0f3e100d7552add9688125d9c86d29a8ab..46d4449772bc714daa658ea6424fb45659095c70 100644 (file)
@@ -422,6 +422,7 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
                        struct kvm_ioapic *ioapic, int vector, int trigger_mode)
 {
        int i;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
        for (i = 0; i < IOAPIC_NUM_PINS; i++) {
                union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
@@ -443,7 +444,8 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
                kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
                spin_lock(&ioapic->lock);
 
-               if (trigger_mode != IOAPIC_LEVEL_TRIG)
+               if (trigger_mode != IOAPIC_LEVEL_TRIG ||
+                   kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
                        continue;
 
                ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
index e55b5fc344eb911a7b4ed0c490d50a6767532d27..4ee827d7bf36f730c25d358f709aa99cda93260a 100644 (file)
@@ -833,8 +833,7 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
 
 static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
 {
-       if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
-           kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
+       if (kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
                int trigger_mode;
                if (apic_test_vector(vector, apic->regs + APIC_TMR))
                        trigger_mode = IOAPIC_LEVEL_TRIG;
@@ -1572,7 +1571,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
                apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
        }
        apic->irr_pending = kvm_apic_vid_enabled(vcpu->kvm);
-       apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm);
+       apic->isr_count = kvm_x86_ops->hwapic_isr_update ? 1 : 0;
        apic->highest_isr_cache = -1;
        update_divide_count(apic);
        atomic_set(&apic->lapic_timer.pending, 0);
@@ -1782,7 +1781,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
        update_divide_count(apic);
        start_apic_timer(apic);
        apic->irr_pending = true;
-       apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm) ?
+       apic->isr_count = kvm_x86_ops->hwapic_isr_update ?
                                1 : count_vectors(apic->regs + APIC_ISR);
        apic->highest_isr_cache = -1;
        if (kvm_x86_ops->hwapic_irr_update)
index d319e0c24758876178aeab46c65fe611cb02126e..cc618c882f900ad21cb4de57d94daa91a5f4ec4c 100644 (file)
@@ -3649,11 +3649,6 @@ static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
        return;
 }
 
-static void svm_hwapic_isr_update(struct kvm *kvm, int isr)
-{
-       return;
-}
-
 static void svm_sync_pir_to_irr(struct kvm_vcpu *vcpu)
 {
        return;
@@ -4403,7 +4398,6 @@ static struct kvm_x86_ops svm_x86_ops = {
        .set_virtual_x2apic_mode = svm_set_virtual_x2apic_mode,
        .vm_has_apicv = svm_vm_has_apicv,
        .load_eoi_exitmap = svm_load_eoi_exitmap,
-       .hwapic_isr_update = svm_hwapic_isr_update,
        .sync_pir_to_irr = svm_sync_pir_to_irr,
 
        .set_tss_addr = svm_set_tss_addr,
index 14c1a18d206aeee0d59637162b0f1a58056c8941..ae4f6d35d19c268315745741150dd6d1a7df5222 100644 (file)
@@ -2168,7 +2168,10 @@ static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
 {
        unsigned long *msr_bitmap;
 
-       if (irqchip_in_kernel(vcpu->kvm) && apic_x2apic_mode(vcpu->arch.apic)) {
+       if (is_guest_mode(vcpu))
+               msr_bitmap = vmx_msr_bitmap_nested;
+       else if (irqchip_in_kernel(vcpu->kvm) &&
+               apic_x2apic_mode(vcpu->arch.apic)) {
                if (is_long_mode(vcpu))
                        msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
                else
@@ -2476,8 +2479,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
        if (enable_ept) {
                /* nested EPT: emulate EPT also to L1 */
                vmx->nested.nested_vmx_secondary_ctls_high |=
-                       SECONDARY_EXEC_ENABLE_EPT |
-                       SECONDARY_EXEC_UNRESTRICTED_GUEST;
+                       SECONDARY_EXEC_ENABLE_EPT;
                vmx->nested.nested_vmx_ept_caps = VMX_EPT_PAGE_WALK_4_BIT |
                         VMX_EPTP_WB_BIT | VMX_EPT_2MB_PAGE_BIT |
                         VMX_EPT_INVEPT_BIT;
@@ -2491,6 +2493,10 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
        } else
                vmx->nested.nested_vmx_ept_caps = 0;
 
+       if (enable_unrestricted_guest)
+               vmx->nested.nested_vmx_secondary_ctls_high |=
+                       SECONDARY_EXEC_UNRESTRICTED_GUEST;
+
        /* miscellaneous data */
        rdmsr(MSR_IA32_VMX_MISC,
                vmx->nested.nested_vmx_misc_low,
@@ -4367,6 +4373,18 @@ static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_SMP
+       if (vcpu->mode == IN_GUEST_MODE) {
+               apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
+                               POSTED_INTR_VECTOR);
+               return true;
+       }
+#endif
+       return false;
+}
+
 static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
                                                int vector)
 {
@@ -4375,9 +4393,7 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
        if (is_guest_mode(vcpu) &&
            vector == vmx->nested.posted_intr_nv) {
                /* the PIR and ON have been set by L1. */
-               if (vcpu->mode == IN_GUEST_MODE)
-                       apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
-                               POSTED_INTR_VECTOR);
+               kvm_vcpu_trigger_posted_interrupt(vcpu);
                /*
                 * If a posted intr is not recognized by hardware,
                 * we will accomplish it in the next vmentry.
@@ -4409,12 +4425,7 @@ static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
 
        r = pi_test_and_set_on(&vmx->pi_desc);
        kvm_make_request(KVM_REQ_EVENT, vcpu);
-#ifdef CONFIG_SMP
-       if (!r && (vcpu->mode == IN_GUEST_MODE))
-               apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
-                               POSTED_INTR_VECTOR);
-       else
-#endif
+       if (r || !kvm_vcpu_trigger_posted_interrupt(vcpu))
                kvm_vcpu_kick(vcpu);
 }
 
@@ -9213,9 +9224,9 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        }
 
        if (cpu_has_vmx_msr_bitmap() &&
-           exec_control & CPU_BASED_USE_MSR_BITMAPS &&
-           nested_vmx_merge_msr_bitmap(vcpu, vmcs12)) {
-               vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_nested));
+           exec_control & CPU_BASED_USE_MSR_BITMAPS) {
+               nested_vmx_merge_msr_bitmap(vcpu, vmcs12);
+               /* MSR_BITMAP will be set by following vmx_set_efer. */
        } else
                exec_control &= ~CPU_BASED_USE_MSR_BITMAPS;
 
index bd7a70be41b35fa93ad952060fc2c7f432e5628e..32bf19ef3115f65c9dffc23a655be2763babcaff 100644 (file)
@@ -2744,7 +2744,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_USER_NMI:
        case KVM_CAP_REINJECT_CONTROL:
        case KVM_CAP_IRQ_INJECT_STATUS:
-       case KVM_CAP_IRQFD:
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_IOEVENTFD_NO_LENGTH:
        case KVM_CAP_PIT2:
index 4a0890f815c40dc2641d092ff7aeaee5cb6f0039..08f41caada45fae631599fde62f9b0d43902b7cd 100644 (file)
@@ -1,6 +1,6 @@
 config LGUEST_GUEST
        bool "Lguest guest support"
-       depends on X86_32 && PARAVIRT
+       depends on X86_32 && PARAVIRT && PCI
        select TTY
        select VIRTUALIZATION
        select VIRTIO
@@ -8,7 +8,7 @@ config LGUEST_GUEST
        help
          Lguest is a tiny in-kernel hypervisor.  Selecting this will
          allow your kernel to boot under lguest.  This option will increase
-         your kernel size by about 6k.  If in doubt, say N.
+         your kernel size by about 10k.  If in doubt, say N.
 
          If you say Y here, make sure you say Y (or M) to the virtio block
          and net drivers which lguest needs.
index 6ac273832f284635ac1a66bf3f8551de379fa0f0..e4695985f9de85778db5e084b37eda5719d3a82a 100644 (file)
@@ -331,7 +331,7 @@ static void probe_pci_root_info(struct pci_root_info *info,
                                struct list_head *list)
 {
        int ret;
-       struct resource_entry *entry;
+       struct resource_entry *entry, *tmp;
 
        sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
        info->bridge = device;
@@ -345,8 +345,13 @@ static void probe_pci_root_info(struct pci_root_info *info,
                dev_dbg(&device->dev,
                        "no IO and memory resources present in _CRS\n");
        else
-               resource_list_for_each_entry(entry, list)
-                       entry->res->name = info->name;
+               resource_list_for_each_entry_safe(entry, tmp, list) {
+                       if ((entry->res->flags & IORESOURCE_WINDOW) == 0 ||
+                           (entry->res->flags & IORESOURCE_DISABLED))
+                               resource_list_destroy_entry(entry);
+                       else
+                               entry->res->name = info->name;
+               }
 }
 
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
index 3d2612b68694efd294ca214d478c7777030f4b03..2fb384724ebb52d1cf0ba6131b418e81609ca55c 100644 (file)
@@ -513,31 +513,6 @@ void __init pcibios_set_cache_line_size(void)
        }
 }
 
-/*
- * Some device drivers assume dev->irq won't change after calling
- * pci_disable_device(). So delay releasing of IRQ resource to driver
- * unbinding time. Otherwise it will break PM subsystem and drivers
- * like xen-pciback etc.
- */
-static int pci_irq_notifier(struct notifier_block *nb, unsigned long action,
-                           void *data)
-{
-       struct pci_dev *dev = to_pci_dev(data);
-
-       if (action != BUS_NOTIFY_UNBOUND_DRIVER)
-               return NOTIFY_DONE;
-
-       if (pcibios_disable_irq)
-               pcibios_disable_irq(dev);
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block pci_irq_nb = {
-       .notifier_call = pci_irq_notifier,
-       .priority = INT_MIN,
-};
-
 int __init pcibios_init(void)
 {
        if (!raw_pci_ops) {
@@ -550,9 +525,6 @@ int __init pcibios_init(void)
 
        if (pci_bf_sort >= pci_force_bf)
                pci_sort_breadthfirst();
-
-       bus_register_notifier(&pci_bus_type, &pci_irq_nb);
-
        return 0;
 }
 
@@ -711,6 +683,12 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return 0;
 }
 
+void pcibios_disable_device (struct pci_dev *dev)
+{
+       if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
+               pcibios_disable_irq(dev);
+}
+
 int pci_ext_cfg_avail(void)
 {
        if (raw_pci_ext_ops)
index efb849323c745899f5e665364ceec36a1d15cb9d..852aa4c92da027cb07fb64c77c855aaf0877a1da 100644 (file)
@@ -234,10 +234,10 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
 
 static void intel_mid_pci_irq_disable(struct pci_dev *dev)
 {
-       if (dev->irq_managed && dev->irq > 0) {
+       if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed &&
+           dev->irq > 0) {
                mp_unmap_irq(dev->irq);
                dev->irq_managed = 0;
-               dev->irq = 0;
        }
 }
 
index e71b3dbd87b8f688d3f2cbfa995421bd516ba581..5dc6ca5e174131d2c7208ea1ed86739ef4532d22 100644 (file)
@@ -1256,9 +1256,22 @@ static int pirq_enable_irq(struct pci_dev *dev)
        return 0;
 }
 
+bool mp_should_keep_irq(struct device *dev)
+{
+       if (dev->power.is_prepared)
+               return true;
+#ifdef CONFIG_PM
+       if (dev->power.runtime_status == RPM_SUSPENDING)
+               return true;
+#endif
+
+       return false;
+}
+
 static void pirq_disable_irq(struct pci_dev *dev)
 {
-       if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) {
+       if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
+           dev->irq_managed && dev->irq) {
                mp_unmap_irq(dev->irq);
                dev->irq = 0;
                dev->irq_managed = 0;
index 1bbedc4b0f88d46bee5000779c4ef5aa4e4d0411..3005f0c89f2ecfbcc817c7e379c97586d5524e7f 100644 (file)
@@ -130,7 +130,7 @@ static void intel_mid_arch_setup(void)
                intel_mid_ops = get_intel_mid_ops[__intel_mid_cpu_chip]();
        else {
                intel_mid_ops = get_intel_mid_ops[INTEL_MID_CPU_CHIP_PENWELL]();
-               pr_info("ARCH: Uknown SoC, assuming PENWELL!\n");
+               pr_info("ARCH: Unknown SoC, assuming PENWELL!\n");
        }
 
 out:
index 31776d0efc8c40fa0aa6989731b1ddf23229029c..d7ec4e251c0a2e53572438891508dfeb4a3a016a 100644 (file)
@@ -17,6 +17,7 @@
        .text
        .globl __kernel_sigreturn
        .type __kernel_sigreturn,@function
+       nop /* this guy is needed for .LSTARTFDEDLSI1 below (watch for HACK) */
        ALIGN
 __kernel_sigreturn:
 .LSTART_sigreturn:
index bd8b8459c3d05923286b4dc6b5ebb7e37e51d926..5240f563076de2e0e27c92af2d04ad03d213ee8f 100644 (file)
@@ -1070,6 +1070,23 @@ static inline void xen_write_cr8(unsigned long val)
        BUG_ON(val);
 }
 #endif
+
+static u64 xen_read_msr_safe(unsigned int msr, int *err)
+{
+       u64 val;
+
+       val = native_read_msr_safe(msr, err);
+       switch (msr) {
+       case MSR_IA32_APICBASE:
+#ifdef CONFIG_X86_X2APIC
+               if (!(cpuid_ecx(1) & (1 << (X86_FEATURE_X2APIC & 31))))
+#endif
+                       val &= ~X2APIC_ENABLE;
+               break;
+       }
+       return val;
+}
+
 static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
 {
        int ret;
@@ -1240,7 +1257,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
 
        .wbinvd = native_wbinvd,
 
-       .read_msr = native_read_msr_safe,
+       .read_msr = xen_read_msr_safe,
        .write_msr = xen_write_msr_safe,
 
        .read_tsc = native_read_tsc,
@@ -1741,6 +1758,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
 #ifdef CONFIG_X86_32
        i386_start_kernel();
 #else
+       cr4_init_shadow(); /* 32b kernel does this in i386_start_kernel() */
        x86_64_start_reservations((char *)__pa_symbol(&boot_params));
 #endif
 }
index 740ae3026a148ec54800710427a455dc890351d3..9f93af56a5fc7bd4cf263406faf96f8a5fa56466 100644 (file)
@@ -563,7 +563,7 @@ static bool alloc_p2m(unsigned long pfn)
                if (p2m_pfn == PFN_DOWN(__pa(p2m_missing)))
                        p2m_init(p2m);
                else
-                       p2m_init_identity(p2m, pfn);
+                       p2m_init_identity(p2m, pfn & ~(P2M_PER_PAGE - 1));
 
                spin_lock_irqsave(&p2m_update_lock, flags);
 
index fc1ff3b1ea1f4a9ea2dcd18d6e49eea7281eb9b3..fd3fee81c23ce2f1cdc73d2bf4e76188c90358cb 100644 (file)
@@ -592,7 +592,7 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
        if (q->queue_flags & (1 << QUEUE_FLAG_SG_GAPS)) {
                struct bio_vec *bprev;
 
-               bprev = &rq->biotail->bi_io_vec[bio->bi_vcnt - 1];
+               bprev = &rq->biotail->bi_io_vec[rq->biotail->bi_vcnt - 1];
                if (bvec_gap_to_prev(bprev, bio->bi_io_vec[0].bv_offset))
                        return false;
        }
index d53a764b05eacde776a4454054795d1c0277d676..be3290cc0644efc9e3feec6fd891c7afe1a15775 100644 (file)
@@ -278,9 +278,11 @@ static int bt_get(struct blk_mq_alloc_data *data,
                /*
                 * We're out of tags on this hardware queue, kick any
                 * pending IO submits before going to sleep waiting for
-                * some to complete.
+                * some to complete. Note that hctx can be NULL here for
+                * reserved tag allocation.
                 */
-               blk_mq_run_hw_queue(hctx, false);
+               if (hctx)
+                       blk_mq_run_hw_queue(hctx, false);
 
                /*
                 * Retry tag allocation after running the hardware queue,
index 4f4bea21052e41068112ead8cbb4e0a42cb7a9d6..b7b8933ec24188b2807229af1aa844503b46dc89 100644 (file)
@@ -1938,7 +1938,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
         */
        if (percpu_ref_init(&q->mq_usage_counter, blk_mq_usage_counter_release,
                            PERCPU_REF_INIT_ATOMIC, GFP_KERNEL))
-               goto err_map;
+               goto err_mq_usage;
 
        setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q);
        blk_queue_rq_timeout(q, 30000);
@@ -1981,7 +1981,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
        blk_mq_init_cpu_queues(q, set->nr_hw_queues);
 
        if (blk_mq_init_hw_queues(q, set))
-               goto err_hw;
+               goto err_mq_usage;
 
        mutex_lock(&all_q_mutex);
        list_add_tail(&q->all_q_node, &all_q_list);
@@ -1993,7 +1993,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
 
        return q;
 
-err_hw:
+err_mq_usage:
        blk_cleanup_queue(q);
 err_hctxs:
        kfree(map);
index 657964e8ab7ed2ba9e56004d5f83881ad826e7b7..37fb1904760396751f27778e819d90c0fd9af83b 100644 (file)
@@ -65,6 +65,7 @@ struct lpss_private_data;
 
 struct lpss_device_desc {
        unsigned int flags;
+       const char *clk_con_id;
        unsigned int prv_offset;
        size_t prv_size_override;
        void (*setup)(struct lpss_private_data *pdata);
@@ -140,6 +141,7 @@ static struct lpss_device_desc lpt_i2c_dev_desc = {
 
 static struct lpss_device_desc lpt_uart_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR,
+       .clk_con_id = "baudclk",
        .prv_offset = 0x800,
        .setup = lpss_uart_setup,
 };
@@ -156,6 +158,7 @@ static struct lpss_device_desc byt_pwm_dev_desc = {
 
 static struct lpss_device_desc byt_uart_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+       .clk_con_id = "baudclk",
        .prv_offset = 0x800,
        .setup = lpss_uart_setup,
 };
@@ -313,7 +316,7 @@ out:
                return PTR_ERR(clk);
 
        pdata->clk = clk;
-       clk_register_clkdev(clk, NULL, devname);
+       clk_register_clkdev(clk, dev_desc->clk_con_id, devname);
        return 0;
 }
 
index e7f718d6918a6a29b775aa97f7a40dc654d47136..b1def411c0b89cbf7847b767063c5c2ab528e8a8 100644 (file)
@@ -485,6 +485,14 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        if (!pin || !dev->irq_managed || dev->irq <= 0)
                return;
 
+       /* Keep IOAPIC pin configuration when suspending */
+       if (dev->dev.power.is_prepared)
+               return;
+#ifdef CONFIG_PM
+       if (dev->dev.power.runtime_status == RPM_SUSPENDING)
+               return;
+#endif
+
        entry = acpi_pci_irq_lookup(dev, pin);
        if (!entry)
                return;
@@ -505,6 +513,5 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        if (gsi >= 0) {
                acpi_unregister_gsi(gsi);
                dev->irq_managed = 0;
-               dev->irq = 0;
        }
 }
index c723668e3e277def6f8d6309fe1af21b989951fb..5589a6e2a02346e3b2ce48656b3facea1abfc621 100644 (file)
@@ -42,8 +42,10 @@ static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io)
         * CHECKME: len might be required to check versus a minimum
         * length as well. 1 for io is fine, but for memory it does
         * not make any sense at all.
+        * Note: some BIOSes report incorrect length for ACPI address space
+        * descriptor, so remove check of 'reslen == len' to avoid regression.
         */
-       if (len && reslen && reslen == len && start <= end)
+       if (len && reslen && start <= end)
                return true;
 
        pr_debug("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n",
index debd30917010a17697102bc84d1e468c69c94d17..26eb70c8f5184f878ae489c4130e1b382d7394a2 100644 (file)
@@ -2110,7 +2110,8 @@ static int __init intel_opregion_present(void)
 
 int acpi_video_register(void)
 {
-       int result = 0;
+       int ret;
+
        if (register_count) {
                /*
                 * if the function of acpi_video_register is already called,
@@ -2122,9 +2123,9 @@ int acpi_video_register(void)
        mutex_init(&video_list_lock);
        INIT_LIST_HEAD(&video_bus_head);
 
-       result = acpi_bus_register_driver(&acpi_video_bus);
-       if (result < 0)
-               return -ENODEV;
+       ret = acpi_bus_register_driver(&acpi_video_bus);
+       if (ret)
+               return ret;
 
        /*
         * When the acpi_video_bus is loaded successfully, increase
@@ -2176,6 +2177,17 @@ EXPORT_SYMBOL(acpi_video_unregister_backlight);
 
 static int __init acpi_video_init(void)
 {
+       /*
+        * Let the module load even if ACPI is disabled (e.g. due to
+        * a broken BIOS) so that i915.ko can still be loaded on such
+        * old systems without an AcpiOpRegion.
+        *
+        * acpi_video_register() will report -ENODEV later as well due
+        * to acpi_disabled when i915.ko tries to register itself afterwards.
+        */
+       if (acpi_disabled)
+               return 0;
+
        dmi_check_system(video_dmi_table);
 
        if (intel_opregion_present())
index 33b09b6568a4a464657b51667ffe8596c7893b2f..6607f3c6ace1033fd4ca449d579bd2b7638e3963 100644 (file)
@@ -551,7 +551,6 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
 {
        void *page_addr;
        unsigned long user_page_addr;
-       struct vm_struct tmp_area;
        struct page **page;
        struct mm_struct *mm;
 
@@ -600,10 +599,11 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
                                proc->pid, page_addr);
                        goto err_alloc_page_failed;
                }
-               tmp_area.addr = page_addr;
-               tmp_area.size = PAGE_SIZE + PAGE_SIZE /* guard page? */;
-               ret = map_vm_area(&tmp_area, PAGE_KERNEL, page);
-               if (ret) {
+               ret = map_kernel_range_noflush((unsigned long)page_addr,
+                                       PAGE_SIZE, PAGE_KERNEL, page);
+               flush_cache_vmap((unsigned long)page_addr,
+                               (unsigned long)page_addr + PAGE_SIZE);
+               if (ret != 1) {
                        pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n",
                               proc->pid, page_addr);
                        goto err_map_kernel_failed;
index 4c35f0822d06e54dd5399a285d22cbcfe174b115..ef150ebb4c304efa1cbf5fb6e23a2a9da036ae91 100644 (file)
@@ -4737,7 +4737,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag)
                return NULL;
 
        /* libsas case */
-       if (!ap->scsi_host) {
+       if (ap->flags & ATA_FLAG_SAS_HOST) {
                tag = ata_sas_allocate_tag(ap);
                if (tag < 0)
                        return NULL;
@@ -4776,7 +4776,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
        tag = qc->tag;
        if (likely(ata_tag_valid(tag))) {
                qc->tag = ATA_TAG_POISON;
-               if (!ap->scsi_host)
+               if (ap->flags & ATA_FLAG_SAS_HOST)
                        ata_sas_free_tag(tag, ap);
        }
 }
index f9054cd36a7266bbed21db2503a63672d0d8040c..5389579c51204cf336f2689052ccf29c48b8af98 100644 (file)
@@ -869,6 +869,8 @@ try_offline_again:
         */
        ata_msleep(ap, 1);
 
+       sata_set_spd(link);
+
        /*
         * Now, bring the host controller online again, this can take time
         * as PHY reset and communication establishment, 1st D2H FIS and
index ba4abbe4693c3e29be764d66662295dd300d41c4..45937f88e77c88893f6f05430efcd2dd88449e9f 100644 (file)
@@ -2242,7 +2242,7 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)
 }
 
 static int pm_genpd_summary_one(struct seq_file *s,
-               struct generic_pm_domain *gpd)
+                               struct generic_pm_domain *genpd)
 {
        static const char * const status_lookup[] = {
                [GPD_STATE_ACTIVE] = "on",
@@ -2256,26 +2256,26 @@ static int pm_genpd_summary_one(struct seq_file *s,
        struct gpd_link *link;
        int ret;
 
-       ret = mutex_lock_interruptible(&gpd->lock);
+       ret = mutex_lock_interruptible(&genpd->lock);
        if (ret)
                return -ERESTARTSYS;
 
-       if (WARN_ON(gpd->status >= ARRAY_SIZE(status_lookup)))
+       if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
                goto exit;
-       seq_printf(s, "%-30s  %-15s  ", gpd->name, status_lookup[gpd->status]);
+       seq_printf(s, "%-30s  %-15s  ", genpd->name, status_lookup[genpd->status]);
 
        /*
         * Modifications on the list require holding locks on both
         * master and slave, so we are safe.
-        * Also gpd->name is immutable.
+        * Also genpd->name is immutable.
         */
-       list_for_each_entry(link, &gpd->master_links, master_node) {
+       list_for_each_entry(link, &genpd->master_links, master_node) {
                seq_printf(s, "%s", link->slave->name);
-               if (!list_is_last(&link->master_node, &gpd->master_links))
+               if (!list_is_last(&link->master_node, &genpd->master_links))
                        seq_puts(s, ", ");
        }
 
-       list_for_each_entry(pm_data, &gpd->dev_list, list_node) {
+       list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
                kobj_path = kobject_get_path(&pm_data->dev->kobj, GFP_KERNEL);
                if (kobj_path == NULL)
                        continue;
@@ -2287,14 +2287,14 @@ static int pm_genpd_summary_one(struct seq_file *s,
 
        seq_puts(s, "\n");
 exit:
-       mutex_unlock(&gpd->lock);
+       mutex_unlock(&genpd->lock);
 
        return 0;
 }
 
 static int pm_genpd_summary_show(struct seq_file *s, void *data)
 {
-       struct generic_pm_domain *gpd;
+       struct generic_pm_domain *genpd;
        int ret = 0;
 
        seq_puts(s, "    domain                      status         slaves\n");
@@ -2305,8 +2305,8 @@ static int pm_genpd_summary_show(struct seq_file *s, void *data)
        if (ret)
                return -ERESTARTSYS;
 
-       list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
-               ret = pm_genpd_summary_one(s, gpd);
+       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
+               ret = pm_genpd_summary_one(s, genpd);
                if (ret)
                        break;
        }
index c2744b30d5d92e9dde512e492cf9fdf44f21b5ef..aab7158d2afea87c5cee091eb2af3a1ae0a7222a 100644 (file)
@@ -730,6 +730,7 @@ void pm_system_wakeup(void)
        pm_abort_suspend = true;
        freeze_wake();
 }
+EXPORT_SYMBOL_GPL(pm_system_wakeup);
 
 void pm_wakeup_clear(void)
 {
index beb8b27d4621a6d9f839065c1296fa8ab67f3032..a13587b5c2be32b912f9fe0fd7544761a280bd57 100644 (file)
@@ -243,4 +243,12 @@ extern struct regcache_ops regcache_rbtree_ops;
 extern struct regcache_ops regcache_lzo_ops;
 extern struct regcache_ops regcache_flat_ops;
 
+static inline const char *regmap_name(const struct regmap *map)
+{
+       if (map->dev)
+               return dev_name(map->dev);
+
+       return map->name;
+}
+
 #endif
index d453a2c98ad0a6529170dc5a8f21bab9204255f7..81751a49d8bf2334612350bba52406b9af352258 100644 (file)
@@ -307,7 +307,7 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
        if (pos == 0) {
                memmove(blk + offset * map->cache_word_size,
                        blk, rbnode->blklen * map->cache_word_size);
-               bitmap_shift_right(present, present, offset, blklen);
+               bitmap_shift_left(present, present, offset, blklen);
        }
 
        /* update the rbnode block, its size and the base register */
index f373c35f9e1db239874589464b6375ebfe5d769a..87db9893b463ba505acc3c28e253b5a08cf20c90 100644 (file)
@@ -218,7 +218,7 @@ int regcache_read(struct regmap *map,
                ret = map->cache_ops->read(map, reg, value);
 
                if (ret == 0)
-                       trace_regmap_reg_read_cache(map->dev, reg, *value);
+                       trace_regmap_reg_read_cache(map, reg, *value);
 
                return ret;
        }
@@ -311,7 +311,7 @@ int regcache_sync(struct regmap *map)
        dev_dbg(map->dev, "Syncing %s cache\n",
                map->cache_ops->name);
        name = map->cache_ops->name;
-       trace_regcache_sync(map->dev, name, "start");
+       trace_regcache_sync(map, name, "start");
 
        if (!map->cache_dirty)
                goto out;
@@ -346,7 +346,7 @@ out:
 
        regmap_async_complete(map);
 
-       trace_regcache_sync(map->dev, name, "stop");
+       trace_regcache_sync(map, name, "stop");
 
        return ret;
 }
@@ -381,7 +381,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
        name = map->cache_ops->name;
        dev_dbg(map->dev, "Syncing %s cache from %d-%d\n", name, min, max);
 
-       trace_regcache_sync(map->dev, name, "start region");
+       trace_regcache_sync(map, name, "start region");
 
        if (!map->cache_dirty)
                goto out;
@@ -401,7 +401,7 @@ out:
 
        regmap_async_complete(map);
 
-       trace_regcache_sync(map->dev, name, "stop region");
+       trace_regcache_sync(map, name, "stop region");
 
        return ret;
 }
@@ -428,7 +428,7 @@ int regcache_drop_region(struct regmap *map, unsigned int min,
 
        map->lock(map->lock_arg);
 
-       trace_regcache_drop_region(map->dev, min, max);
+       trace_regcache_drop_region(map, min, max);
 
        ret = map->cache_ops->drop(map, min, max);
 
@@ -455,7 +455,7 @@ void regcache_cache_only(struct regmap *map, bool enable)
        map->lock(map->lock_arg);
        WARN_ON(map->cache_bypass && enable);
        map->cache_only = enable;
-       trace_regmap_cache_only(map->dev, enable);
+       trace_regmap_cache_only(map, enable);
        map->unlock(map->lock_arg);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -493,7 +493,7 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
        map->lock(map->lock_arg);
        WARN_ON(map->cache_only && enable);
        map->cache_bypass = enable;
-       trace_regmap_cache_bypass(map->dev, enable);
+       trace_regmap_cache_bypass(map, enable);
        map->unlock(map->lock_arg);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_bypass);
@@ -608,7 +608,8 @@ static int regcache_sync_block_single(struct regmap *map, void *block,
        for (i = start; i < end; i++) {
                regtmp = block_base + (i * map->reg_stride);
 
-               if (!regcache_reg_present(cache_present, i))
+               if (!regcache_reg_present(cache_present, i) ||
+                   !regmap_writeable(map, regtmp))
                        continue;
 
                val = regcache_get_val(map, block, i);
@@ -677,7 +678,8 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
        for (i = start; i < end; i++) {
                regtmp = block_base + (i * map->reg_stride);
 
-               if (!regcache_reg_present(cache_present, i)) {
+               if (!regcache_reg_present(cache_present, i) ||
+                   !regmap_writeable(map, regtmp)) {
                        ret = regcache_sync_block_raw_flush(map, &data,
                                                            base, regtmp);
                        if (ret != 0)
index 6299a50a59607f6d5598eac804817cef47e8c106..a6c3f75b4b01e1145c6eb5bb9816182a0f9c9fde 100644 (file)
@@ -499,7 +499,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                goto err_alloc;
        }
 
-       ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags,
+       ret = request_threaded_irq(irq, NULL, regmap_irq_thread,
+                                  irq_flags | IRQF_ONESHOT,
                                   chip->name, d);
        if (ret != 0) {
                dev_err(map->dev, "Failed to request IRQ %d for %s: %d\n",
index f99b098ddabfbd23dae3ab3ee7733b9ff24e28ef..dbfe6a69c3daa67969df7c670f9e5144a053afb6 100644 (file)
@@ -1281,7 +1281,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
        if (map->async && map->bus->async_write) {
                struct regmap_async *async;
 
-               trace_regmap_async_write_start(map->dev, reg, val_len);
+               trace_regmap_async_write_start(map, reg, val_len);
 
                spin_lock_irqsave(&map->async_lock, flags);
                async = list_first_entry_or_null(&map->async_free,
@@ -1339,8 +1339,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
                return ret;
        }
 
-       trace_regmap_hw_write_start(map->dev, reg,
-                                   val_len / map->format.val_bytes);
+       trace_regmap_hw_write_start(map, reg, val_len / map->format.val_bytes);
 
        /* If we're doing a single register write we can probably just
         * send the work_buf directly, otherwise try to do a gather
@@ -1372,8 +1371,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
                kfree(buf);
        }
 
-       trace_regmap_hw_write_done(map->dev, reg,
-                                  val_len / map->format.val_bytes);
+       trace_regmap_hw_write_done(map, reg, val_len / map->format.val_bytes);
 
        return ret;
 }
@@ -1407,12 +1405,12 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
 
        map->format.format_write(map, reg, val);
 
-       trace_regmap_hw_write_start(map->dev, reg, 1);
+       trace_regmap_hw_write_start(map, reg, 1);
 
        ret = map->bus->write(map->bus_context, map->work_buf,
                              map->format.buf_size);
 
-       trace_regmap_hw_write_done(map->dev, reg, 1);
+       trace_regmap_hw_write_done(map, reg, 1);
 
        return ret;
 }
@@ -1470,7 +1468,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
                dev_info(map->dev, "%x <= %x\n", reg, val);
 #endif
 
-       trace_regmap_reg_write(map->dev, reg, val);
+       trace_regmap_reg_write(map, reg, val);
 
        return map->reg_write(context, reg, val);
 }
@@ -1773,7 +1771,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
        for (i = 0; i < num_regs; i++) {
                int reg = regs[i].reg;
                int val = regs[i].def;
-               trace_regmap_hw_write_start(map->dev, reg, 1);
+               trace_regmap_hw_write_start(map, reg, 1);
                map->format.format_reg(u8, reg, map->reg_shift);
                u8 += reg_bytes + pad_bytes;
                map->format.format_val(u8, val, 0);
@@ -1788,7 +1786,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
 
        for (i = 0; i < num_regs; i++) {
                int reg = regs[i].reg;
-               trace_regmap_hw_write_done(map->dev, reg, 1);
+               trace_regmap_hw_write_done(map, reg, 1);
        }
        return ret;
 }
@@ -2059,15 +2057,13 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
         */
        u8[0] |= map->read_flag_mask;
 
-       trace_regmap_hw_read_start(map->dev, reg,
-                                  val_len / map->format.val_bytes);
+       trace_regmap_hw_read_start(map, reg, val_len / map->format.val_bytes);
 
        ret = map->bus->read(map->bus_context, map->work_buf,
                             map->format.reg_bytes + map->format.pad_bytes,
                             val, val_len);
 
-       trace_regmap_hw_read_done(map->dev, reg,
-                                 val_len / map->format.val_bytes);
+       trace_regmap_hw_read_done(map, reg, val_len / map->format.val_bytes);
 
        return ret;
 }
@@ -2123,7 +2119,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
                        dev_info(map->dev, "%x => %x\n", reg, *val);
 #endif
 
-               trace_regmap_reg_read(map->dev, reg, *val);
+               trace_regmap_reg_read(map, reg, *val);
 
                if (!map->cache_bypass)
                        regcache_write(map, reg, *val);
@@ -2480,7 +2476,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
        struct regmap *map = async->map;
        bool wake;
 
-       trace_regmap_async_io_complete(map->dev);
+       trace_regmap_async_io_complete(map);
 
        spin_lock(&map->async_lock);
        list_move(&async->list, &map->async_free);
@@ -2525,7 +2521,7 @@ int regmap_async_complete(struct regmap *map)
        if (!map->bus || !map->bus->async_write)
                return 0;
 
-       trace_regmap_async_complete_start(map->dev);
+       trace_regmap_async_complete_start(map);
 
        wait_event(map->async_waitq, regmap_async_is_done(map));
 
@@ -2534,7 +2530,7 @@ int regmap_async_complete(struct regmap *map)
        map->async_ret = 0;
        spin_unlock_irqrestore(&map->async_lock, flags);
 
-       trace_regmap_async_complete_done(map->dev);
+       trace_regmap_async_complete_done(map);
 
        return ret;
 }
index 4bc2a5cb9935fbc6f5256102bdf9c2c24b9e6d8c..a98c41f72c63f4ceac0cef519f12a7b1b5be7702 100644 (file)
@@ -803,10 +803,6 @@ static int __init nbd_init(void)
                return -EINVAL;
        }
 
-       nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
-       if (!nbd_dev)
-               return -ENOMEM;
-
        part_shift = 0;
        if (max_part > 0) {
                part_shift = fls(max_part);
@@ -828,6 +824,10 @@ static int __init nbd_init(void)
        if (nbds_max > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
 
+       nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
+       if (!nbd_dev)
+               return -ENOMEM;
+
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = alloc_disk(1 << part_shift);
                if (!disk)
index b64bccbb78c9a5223548f7b7e25e33c4eb51afd4..e23be20a341752c1b175cc05612c7e087ee24fa4 100644 (file)
@@ -482,6 +482,7 @@ static int nvme_error_status(u16 status)
        }
 }
 
+#ifdef CONFIG_BLK_DEV_INTEGRITY
 static void nvme_dif_prep(u32 p, u32 v, struct t10_pi_tuple *pi)
 {
        if (be32_to_cpu(pi->ref_tag) == v)
@@ -538,6 +539,58 @@ static void nvme_dif_remap(struct request *req,
        kunmap_atomic(pmap);
 }
 
+static int nvme_noop_verify(struct blk_integrity_iter *iter)
+{
+       return 0;
+}
+
+static int nvme_noop_generate(struct blk_integrity_iter *iter)
+{
+       return 0;
+}
+
+struct blk_integrity nvme_meta_noop = {
+       .name                   = "NVME_META_NOOP",
+       .generate_fn            = nvme_noop_generate,
+       .verify_fn              = nvme_noop_verify,
+};
+
+static void nvme_init_integrity(struct nvme_ns *ns)
+{
+       struct blk_integrity integrity;
+
+       switch (ns->pi_type) {
+       case NVME_NS_DPS_PI_TYPE3:
+               integrity = t10_pi_type3_crc;
+               break;
+       case NVME_NS_DPS_PI_TYPE1:
+       case NVME_NS_DPS_PI_TYPE2:
+               integrity = t10_pi_type1_crc;
+               break;
+       default:
+               integrity = nvme_meta_noop;
+               break;
+       }
+       integrity.tuple_size = ns->ms;
+       blk_integrity_register(ns->disk, &integrity);
+       blk_queue_max_integrity_segments(ns->queue, 1);
+}
+#else /* CONFIG_BLK_DEV_INTEGRITY */
+static void nvme_dif_remap(struct request *req,
+                       void (*dif_swap)(u32 p, u32 v, struct t10_pi_tuple *pi))
+{
+}
+static void nvme_dif_prep(u32 p, u32 v, struct t10_pi_tuple *pi)
+{
+}
+static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
+{
+}
+static void nvme_init_integrity(struct nvme_ns *ns)
+{
+}
+#endif
+
 static void req_completion(struct nvme_queue *nvmeq, void *ctx,
                                                struct nvme_completion *cqe)
 {
@@ -1959,43 +2012,6 @@ static void nvme_config_discard(struct nvme_ns *ns)
        queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
 }
 
-static int nvme_noop_verify(struct blk_integrity_iter *iter)
-{
-       return 0;
-}
-
-static int nvme_noop_generate(struct blk_integrity_iter *iter)
-{
-       return 0;
-}
-
-struct blk_integrity nvme_meta_noop = {
-       .name                   = "NVME_META_NOOP",
-       .generate_fn            = nvme_noop_generate,
-       .verify_fn              = nvme_noop_verify,
-};
-
-static void nvme_init_integrity(struct nvme_ns *ns)
-{
-       struct blk_integrity integrity;
-
-       switch (ns->pi_type) {
-       case NVME_NS_DPS_PI_TYPE3:
-               integrity = t10_pi_type3_crc;
-               break;
-       case NVME_NS_DPS_PI_TYPE1:
-       case NVME_NS_DPS_PI_TYPE2:
-               integrity = t10_pi_type1_crc;
-               break;
-       default:
-               integrity = nvme_meta_noop;
-               break;
-       }
-       integrity.tuple_size = ns->ms;
-       blk_integrity_register(ns->disk, &integrity);
-       blk_queue_max_integrity_segments(ns->queue, 1);
-}
-
 static int nvme_revalidate_disk(struct gendisk *disk)
 {
        struct nvme_ns *ns = disk->private_data;
@@ -2036,7 +2052,8 @@ static int nvme_revalidate_disk(struct gendisk *disk)
        pi_type = ns->ms == sizeof(struct t10_pi_tuple) ?
                                        id->dps & NVME_NS_DPS_PI_MASK : 0;
 
-       if (disk->integrity && (ns->pi_type != pi_type || ns->ms != old_ms ||
+       if (blk_get_integrity(disk) && (ns->pi_type != pi_type ||
+                               ns->ms != old_ms ||
                                bs != queue_logical_block_size(disk->queue) ||
                                (ns->ms && id->flbas & NVME_NS_FLBAS_META_EXT)))
                blk_integrity_unregister(disk);
@@ -2044,11 +2061,11 @@ static int nvme_revalidate_disk(struct gendisk *disk)
        ns->pi_type = pi_type;
        blk_queue_logical_block_size(ns->queue, bs);
 
-       if (ns->ms && !disk->integrity && (disk->flags & GENHD_FL_UP) &&
+       if (ns->ms && !blk_get_integrity(disk) && (disk->flags & GENHD_FL_UP) &&
                                !(id->flbas & NVME_NS_FLBAS_META_EXT))
                nvme_init_integrity(ns);
 
-       if (id->ncap == 0 || (ns->ms && !disk->integrity))
+       if (id->ncap == 0 || (ns->ms && !blk_get_integrity(disk)))
                set_capacity(disk, 0);
        else
                set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
@@ -2652,7 +2669,7 @@ static void nvme_dev_remove(struct nvme_dev *dev)
 
        list_for_each_entry(ns, &dev->namespaces, list) {
                if (ns->disk->flags & GENHD_FL_UP) {
-                       if (ns->disk->integrity)
+                       if (blk_get_integrity(ns->disk))
                                blk_integrity_unregister(ns->disk);
                        del_gendisk(ns->disk);
                }
@@ -2986,6 +3003,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        }
        get_device(dev->device);
 
+       INIT_LIST_HEAD(&dev->node);
        INIT_WORK(&dev->probe_work, nvme_async_probe);
        schedule_work(&dev->probe_work);
        return 0;
index 8e233edd7a097a0f91d323071c97f16e43308e5d..871bd3550cb0e0842296771412e749225542ffac 100644 (file)
@@ -528,7 +528,7 @@ out_cleanup:
 static inline void update_used_max(struct zram *zram,
                                        const unsigned long pages)
 {
-       int old_max, cur_max;
+       unsigned long old_max, cur_max;
 
        old_max = atomic_long_read(&zram->stats.max_used_pages);
 
index b876888811432a9bad46ab73a32ca40b04ed2ce4..8bfc4c2bba87b61f46dfbb4778463f393226f735 100644 (file)
@@ -272,6 +272,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
 
        /* Intel Bluetooth devices */
+       { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
        { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
        { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
        { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW },
index 1d278ccd751f07002e6f6c2d43ad07e030a29bff..e096e9cddb4014f6896be0341ace9ed61803da34 100644 (file)
@@ -140,24 +140,24 @@ static int tpm_dev_add_device(struct tpm_chip *chip)
 {
        int rc;
 
-       rc = device_add(&chip->dev);
+       rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
        if (rc) {
                dev_err(&chip->dev,
-                       "unable to device_register() %s, major %d, minor %d, err=%d\n",
+                       "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
                        chip->devname, MAJOR(chip->dev.devt),
                        MINOR(chip->dev.devt), rc);
 
+               device_unregister(&chip->dev);
                return rc;
        }
 
-       rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
+       rc = device_add(&chip->dev);
        if (rc) {
                dev_err(&chip->dev,
-                       "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
+                       "unable to device_register() %s, major %d, minor %d, err=%d\n",
                        chip->devname, MAJOR(chip->dev.devt),
                        MINOR(chip->dev.devt), rc);
 
-               device_unregister(&chip->dev);
                return rc;
        }
 
@@ -174,27 +174,17 @@ static void tpm_dev_del_device(struct tpm_chip *chip)
  * tpm_chip_register() - create a character device for the TPM chip
  * @chip: TPM chip to use.
  *
- * Creates a character device for the TPM chip and adds sysfs interfaces for
- * the device, PPI and TCPA. As the last step this function adds the
- * chip to the list of TPM chips available for use.
+ * Creates a character device for the TPM chip and adds sysfs attributes for
+ * the device. As the last step this function adds the chip to the list of TPM
+ * chips available for in-kernel use.
  *
- * NOTE: This function should be only called after the chip initialization
- * is complete.
- *
- * Called from tpm_<specific>.c probe function only for devices
- * the driver has determined it should claim.  Prior to calling
- * this function the specific probe function has called pci_enable_device
- * upon errant exit from this function specific probe function should call
- * pci_disable_device
+ * This function should be only called after the chip initialization is
+ * complete.
  */
 int tpm_chip_register(struct tpm_chip *chip)
 {
        int rc;
 
-       rc = tpm_dev_add_device(chip);
-       if (rc)
-               return rc;
-
        /* Populate sysfs for TPM1 devices. */
        if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
                rc = tpm_sysfs_add_device(chip);
@@ -208,6 +198,10 @@ int tpm_chip_register(struct tpm_chip *chip)
                chip->bios_dir = tpm_bios_log_setup(chip->devname);
        }
 
+       rc = tpm_dev_add_device(chip);
+       if (rc)
+               return rc;
+
        /* Make the chip available. */
        spin_lock(&driver_lock);
        list_add_rcu(&chip->list, &tpm_chip_list);
index b1e53e3aece5639e622dcced99ba2cd8396b8af7..42ffa5e7a1e0f6c912a0e214e67a3a99d1511a08 100644 (file)
@@ -124,7 +124,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
 {
        struct ibmvtpm_dev *ibmvtpm;
        struct ibmvtpm_crq crq;
-       u64 *word = (u64 *) &crq;
+       __be64 *word = (__be64 *)&crq;
        int rc;
 
        ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
@@ -145,11 +145,11 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
        memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
        crq.valid = (u8)IBMVTPM_VALID_CMD;
        crq.msg = (u8)VTPM_TPM_COMMAND;
-       crq.len = (u16)count;
-       crq.data = ibmvtpm->rtce_dma_handle;
+       crq.len = cpu_to_be16(count);
+       crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle);
 
-       rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(word[0]),
-                             cpu_to_be64(word[1]));
+       rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]),
+                             be64_to_cpu(word[1]));
        if (rc != H_SUCCESS) {
                dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
                rc = 0;
index f595f14426bf1fcf50f1f95f6e062b3e9fa22e22..6af92890518f8be2bed63503f6170ddbdb1476d2 100644 (file)
@@ -22,9 +22,9 @@
 struct ibmvtpm_crq {
        u8 valid;
        u8 msg;
-       u16 len;
-       u32 data;
-       u64 reserved;
+       __be16 len;
+       __be32 data;
+       __be64 reserved;
 } __attribute__((packed, aligned(8)));
 
 struct ibmvtpm_crq_queue {
index fae2dbbf57459fe4f4ac01bb0415a02abbda9e18..72d7028f779b55801795ef0fe49d9dda8cde7970 100644 (file)
@@ -142,6 +142,7 @@ struct ports_device {
         * notification
         */
        struct work_struct control_work;
+       struct work_struct config_work;
 
        struct list_head ports;
 
@@ -1837,10 +1838,21 @@ static void config_intr(struct virtio_device *vdev)
 
        portdev = vdev->priv;
 
+       if (!use_multiport(portdev))
+               schedule_work(&portdev->config_work);
+}
+
+static void config_work_handler(struct work_struct *work)
+{
+       struct ports_device *portdev;
+
+       portdev = container_of(work, struct ports_device, control_work);
        if (!use_multiport(portdev)) {
+               struct virtio_device *vdev;
                struct port *port;
                u16 rows, cols;
 
+               vdev = portdev->vdev;
                virtio_cread(vdev, struct virtio_console_config, cols, &cols);
                virtio_cread(vdev, struct virtio_console_config, rows, &rows);
 
@@ -2040,12 +2052,14 @@ static int virtcons_probe(struct virtio_device *vdev)
 
        virtio_device_ready(portdev->vdev);
 
+       INIT_WORK(&portdev->config_work, &config_work_handler);
+       INIT_WORK(&portdev->control_work, &control_work_handler);
+
        if (multiport) {
                unsigned int nr_added_bufs;
 
                spin_lock_init(&portdev->c_ivq_lock);
                spin_lock_init(&portdev->c_ovq_lock);
-               INIT_WORK(&portdev->control_work, &control_work_handler);
 
                nr_added_bufs = fill_queue(portdev->c_ivq,
                                           &portdev->c_ivq_lock);
@@ -2113,6 +2127,8 @@ static void virtcons_remove(struct virtio_device *vdev)
        /* Finish up work that's lined up */
        if (use_multiport(portdev))
                cancel_work_sync(&portdev->control_work);
+       else
+               cancel_work_sync(&portdev->config_work);
 
        list_for_each_entry_safe(port, port2, &portdev->ports, list)
                unplug_port(port);
@@ -2164,6 +2180,7 @@ static int virtcons_freeze(struct virtio_device *vdev)
 
        virtqueue_disable_cb(portdev->c_ivq);
        cancel_work_sync(&portdev->control_work);
+       cancel_work_sync(&portdev->config_work);
        /*
         * Once more: if control_work_handler() was running, it would
         * enable the cb as the last step.
index f07c8152e5cc42aa660f5c83c6c6470ee2e68502..3f27d21fb7297e70494bf35743f027f8c8005d73 100644 (file)
@@ -89,12 +89,29 @@ static int pmc_irq_set_type(struct irq_data *d, unsigned type)
        return 0;
 }
 
+static void pmc_irq_suspend(struct irq_data *d)
+{
+       struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
+
+       pmc->imr = pmc_read(pmc, AT91_PMC_IMR);
+       pmc_write(pmc, AT91_PMC_IDR, pmc->imr);
+}
+
+static void pmc_irq_resume(struct irq_data *d)
+{
+       struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
+
+       pmc_write(pmc, AT91_PMC_IER, pmc->imr);
+}
+
 static struct irq_chip pmc_irq = {
        .name = "PMC",
        .irq_disable = pmc_irq_mask,
        .irq_mask = pmc_irq_mask,
        .irq_unmask = pmc_irq_unmask,
        .irq_set_type = pmc_irq_set_type,
+       .irq_suspend = pmc_irq_suspend,
+       .irq_resume = pmc_irq_resume,
 };
 
 static struct lock_class_key pmc_lock_class;
@@ -224,7 +241,8 @@ static struct at91_pmc *__init at91_pmc_init(struct device_node *np,
                goto out_free_pmc;
 
        pmc_write(pmc, AT91_PMC_IDR, 0xffffffff);
-       if (request_irq(pmc->virq, pmc_irq_handler, IRQF_SHARED, "pmc", pmc))
+       if (request_irq(pmc->virq, pmc_irq_handler,
+                       IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc))
                goto out_remove_irqdomain;
 
        return pmc;
index 52d2041fa3f6354a4abfdc8f45ee147a75a370ef..69abb08cf146513b0307a4a78449b2e5da971282 100644 (file)
@@ -33,6 +33,7 @@ struct at91_pmc {
        spinlock_t lock;
        const struct at91_pmc_caps *caps;
        struct irq_domain *irqdomain;
+       u32 imr;
 };
 
 static inline void pmc_lock(struct at91_pmc *pmc)
index db7f8bce7467a2abfd37f6ccb8e22c784a6bce28..25006a8bb8e6d5af8d145472fc76e2ef45281f09 100644 (file)
@@ -144,12 +144,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
                                   divider->flags);
 }
 
-/*
- * The reverse of DIV_ROUND_UP: The maximum number which
- * divided by m is r
- */
-#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
-
 static bool _is_valid_table_div(const struct clk_div_table *table,
                                                         unsigned int div)
 {
@@ -225,19 +219,24 @@ static int _div_round_closest(const struct clk_div_table *table,
                              unsigned long parent_rate, unsigned long rate,
                              unsigned long flags)
 {
-       int up, down, div;
+       int up, down;
+       unsigned long up_rate, down_rate;
 
-       up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
+       up = DIV_ROUND_UP(parent_rate, rate);
+       down = parent_rate / rate;
 
        if (flags & CLK_DIVIDER_POWER_OF_TWO) {
-               up = __roundup_pow_of_two(div);
-               down = __rounddown_pow_of_two(div);
+               up = __roundup_pow_of_two(up);
+               down = __rounddown_pow_of_two(down);
        } else if (table) {
-               up = _round_up_table(table, div);
-               down = _round_down_table(table, div);
+               up = _round_up_table(table, up);
+               down = _round_down_table(table, down);
        }
 
-       return (up - div) <= (div - down) ? up : down;
+       up_rate = DIV_ROUND_UP(parent_rate, up);
+       down_rate = DIV_ROUND_UP(parent_rate, down);
+
+       return (rate - up_rate) <= (down_rate - rate) ? up : down;
 }
 
 static int _div_round(const struct clk_div_table *table,
@@ -313,7 +312,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
                        return i;
                }
                parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
-                               MULT_ROUND_UP(rate, i));
+                                              rate * i);
                now = DIV_ROUND_UP(parent_rate, i);
                if (_is_best_div(rate, now, best, flags)) {
                        bestdiv = i;
@@ -353,7 +352,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
                bestdiv = readl(divider->reg) >> divider->shift;
                bestdiv &= div_mask(divider->width);
                bestdiv = _get_div(divider->table, bestdiv, divider->flags);
-               return bestdiv;
+               return DIV_ROUND_UP(*prate, bestdiv);
        }
 
        return divider_round_rate(hw, rate, prate, divider->table,
index eb0152961d3c60652af108246e9d10be9d13a371..237f23f68bfce18cdfee3306487ba924906125c4 100644 (file)
@@ -1350,7 +1350,6 @@ static unsigned long clk_core_get_rate(struct clk_core *clk)
 
        return rate;
 }
-EXPORT_SYMBOL_GPL(clk_core_get_rate);
 
 /**
  * clk_get_rate - return the rate of clk
@@ -2170,6 +2169,32 @@ int clk_get_phase(struct clk *clk)
        return clk_core_get_phase(clk->core);
 }
 
+/**
+ * clk_is_match - check if two clk's point to the same hardware clock
+ * @p: clk compared against q
+ * @q: clk compared against p
+ *
+ * Returns true if the two struct clk pointers both point to the same hardware
+ * clock node. Put differently, returns true if struct clk *p and struct clk *q
+ * share the same struct clk_core object.
+ *
+ * Returns false otherwise. Note that two NULL clks are treated as matching.
+ */
+bool clk_is_match(const struct clk *p, const struct clk *q)
+{
+       /* trivial case: identical struct clk's or both NULL */
+       if (p == q)
+               return true;
+
+       /* true if clk->core pointers match. Avoid derefing garbage */
+       if (!IS_ERR_OR_NULL(p) && !IS_ERR_OR_NULL(q))
+               if (p->core == q->core)
+                       return true;
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(clk_is_match);
+
 /**
  * __clk_init - initialize the data structures in a struct clk
  * @dev:       device initializing this clk, placeholder for now
index b0b562b9ce0e0cc16949f588045b121cfc7d8046..e60feffc10a151dd77d291c71a81e8cb73234804 100644 (file)
@@ -48,6 +48,17 @@ static struct clk_pll pll3 = {
        },
 };
 
+static struct clk_regmap pll4_vote = {
+       .enable_reg = 0x34c0,
+       .enable_mask = BIT(4),
+       .hw.init = &(struct clk_init_data){
+               .name = "pll4_vote",
+               .parent_names = (const char *[]){ "pll4" },
+               .num_parents = 1,
+               .ops = &clk_pll_vote_ops,
+       },
+};
+
 static struct clk_pll pll8 = {
        .l_reg = 0x3144,
        .m_reg = 0x3148,
@@ -3023,6 +3034,7 @@ static struct clk_branch rpm_msg_ram_h_clk = {
 
 static struct clk_regmap *gcc_msm8960_clks[] = {
        [PLL3] = &pll3.clkr,
+       [PLL4_VOTE] = &pll4_vote,
        [PLL8] = &pll8.clkr,
        [PLL8_VOTE] = &pll8_vote,
        [PLL14] = &pll14.clkr,
@@ -3247,6 +3259,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = {
 
 static struct clk_regmap *gcc_apq8064_clks[] = {
        [PLL3] = &pll3.clkr,
+       [PLL4_VOTE] = &pll4_vote,
        [PLL8] = &pll8.clkr,
        [PLL8_VOTE] = &pll8_vote,
        [PLL14] = &pll14.clkr,
index 121ffde25dc3d6ec95d839699bc1f8829b0c003c..c9ff27b4648b56abc37499c1c8f284fc20da05d7 100644 (file)
@@ -462,7 +462,6 @@ static struct platform_driver lcc_ipq806x_driver = {
        .remove         = lcc_ipq806x_remove,
        .driver         = {
                .name   = "lcc-ipq806x",
-               .owner  = THIS_MODULE,
                .of_match_table = lcc_ipq806x_match_table,
        },
 };
index a75a408cfccddffe7e25486a4ca2c4e444c4e9c5..e2c863295f001fd5f99071dcf250ddd931967d09 100644 (file)
@@ -417,8 +417,8 @@ static struct clk_rcg slimbus_src = {
                .mnctr_en_bit = 8,
                .mnctr_reset_bit = 7,
                .mnctr_mode_shift = 5,
-               .n_val_shift = 16,
-               .m_val_shift = 16,
+               .n_val_shift = 24,
+               .m_val_shift = 8,
                .width = 8,
        },
        .p = {
@@ -547,7 +547,7 @@ static int lcc_msm8960_probe(struct platform_device *pdev)
                return PTR_ERR(regmap);
 
        /* Use the correct frequency plan depending on speed of PLL4 */
-       val = regmap_read(regmap, 0x4, &val);
+       regmap_read(regmap, 0x4, &val);
        if (val == 0x12) {
                slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
                mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
@@ -574,7 +574,6 @@ static struct platform_driver lcc_msm8960_driver = {
        .remove         = lcc_msm8960_remove,
        .driver         = {
                .name   = "lcc-msm8960",
-               .owner  = THIS_MODULE,
                .of_match_table = lcc_msm8960_match_table,
        },
 };
index 6ef89639a9f68bffd97990ee976cbd7b45826551..d21640634adf91e290537e28eb799aeea1042eed 100644 (file)
@@ -84,7 +84,7 @@ static int ti_fapll_enable(struct clk_hw *hw)
        struct fapll_data *fd = to_fapll(hw);
        u32 v = readl_relaxed(fd->base);
 
-       v |= (1 << FAPLL_MAIN_PLLEN);
+       v |= FAPLL_MAIN_PLLEN;
        writel_relaxed(v, fd->base);
 
        return 0;
@@ -95,7 +95,7 @@ static void ti_fapll_disable(struct clk_hw *hw)
        struct fapll_data *fd = to_fapll(hw);
        u32 v = readl_relaxed(fd->base);
 
-       v &= ~(1 << FAPLL_MAIN_PLLEN);
+       v &= ~FAPLL_MAIN_PLLEN;
        writel_relaxed(v, fd->base);
 }
 
@@ -104,7 +104,7 @@ static int ti_fapll_is_enabled(struct clk_hw *hw)
        struct fapll_data *fd = to_fapll(hw);
        u32 v = readl_relaxed(fd->base);
 
-       return v & (1 << FAPLL_MAIN_PLLEN);
+       return v & FAPLL_MAIN_PLLEN;
 }
 
 static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
index 1c2506f68122567df92d6197990ee1b015d0984f..a0b036ccb118b1fc23fa07907f17196c80a15a54 100644 (file)
@@ -63,6 +63,11 @@ config VT8500_TIMER
 config CADENCE_TTC_TIMER
        bool
 
+config ASM9260_TIMER
+       bool
+       select CLKSRC_MMIO
+       select CLKSRC_OF
+
 config CLKSRC_NOMADIK_MTU
        bool
        depends on (ARCH_NOMADIK || ARCH_U8500)
@@ -187,6 +192,7 @@ config SYS_SUPPORTS_EM_STI
 config SH_TIMER_CMT
        bool "Renesas CMT timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_CMT
        help
          This enables build of a clocksource and clockevent driver for
@@ -196,6 +202,7 @@ config SH_TIMER_CMT
 config SH_TIMER_MTU2
        bool "Renesas MTU2 timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_MTU2
        help
          This enables build of a clockevent driver for the Multi-Function
@@ -205,6 +212,7 @@ config SH_TIMER_MTU2
 config SH_TIMER_TMU
        bool "Renesas TMU timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_TMU
        help
          This enables build of a clocksource and clockevent driver for
@@ -245,15 +253,4 @@ config CLKSRC_PXA
        help
          This enables OST0 support available on PXA and SA-11x0
          platforms.
-
-config ASM9260_TIMER
-       bool "Alphascale ASM9260 timer driver"
-       depends on GENERIC_CLOCKEVENTS
-       select CLKSRC_MMIO
-       select CLKSRC_OF
-       default y if MACH_ASM9260
-       help
-         This enables build of a clocksource and clockevent driver for
-         the 32-bit System Timer hardware available on a Alphascale ASM9260.
-
 endmenu
index 32a3d25795d3a2b9303db120107d017c13c7165f..68ab42356d0e7a7cd4d97a453465633bba1c5e33 100644 (file)
@@ -224,6 +224,8 @@ static void __init mtk_timer_init(struct device_node *node)
        }
        rate = clk_get_rate(clk);
 
+       mtk_timer_global_reset(evt);
+
        if (request_irq(evt->dev.irq, mtk_timer_interrupt,
                        IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) {
                pr_warn("failed to setup irq %d\n", evt->dev.irq);
@@ -232,8 +234,6 @@ static void __init mtk_timer_init(struct device_node *node)
 
        evt->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 
-       mtk_timer_global_reset(evt);
-
        /* Configure clock source */
        mtk_timer_setup(evt, GPT_CLK_SRC, TIMER_CTRL_OP_FREERUN);
        clocksource_mmio_init(evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC),
@@ -241,10 +241,11 @@ static void __init mtk_timer_init(struct device_node *node)
 
        /* Configure clock event */
        mtk_timer_setup(evt, GPT_CLK_EVT, TIMER_CTRL_OP_REPEAT);
-       mtk_timer_enable_irq(evt, GPT_CLK_EVT);
-
        clockevents_config_and_register(&evt->dev, rate, 0x3,
                                        0xffffffff);
+
+       mtk_timer_enable_irq(evt, GPT_CLK_EVT);
+
        return;
 
 err_clk_disable:
index 941f3f344e08ab2ab552638f0e21ab41718a57ad..d9438af2bbd6b7d001bbdf524b7281a7a0c0816e 100644 (file)
@@ -163,7 +163,7 @@ static struct irqaction pxa_ost0_irq = {
        .dev_id         = &ckevt_pxa_osmr0,
 };
 
-static void pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
+static void __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
 {
        timer_writel(0, OIER);
        timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
index bba62f9deefbd0f71d59409daf85857cc2caa983..ec57ba2bbd87ac9f2a251e350598fa52019d7815 100644 (file)
@@ -225,12 +225,12 @@ static int __init efm32_clockevent_init(struct device_node *np)
        clock_event_ddata.base = base;
        clock_event_ddata.periodic_top = DIV_ROUND_CLOSEST(rate, 1024 * HZ);
 
-       setup_irq(irq, &efm32_clock_event_irq);
-
        clockevents_config_and_register(&clock_event_ddata.evtdev,
                                        DIV_ROUND_CLOSEST(rate, 1024),
                                        0xf, 0xffff);
 
+       setup_irq(irq, &efm32_clock_event_irq);
+
        return 0;
 
 err_get_irq:
index 02268448dc8540a9f53113f28c29e6a292209a5a..58597fbcc046f27f88238aa949730d6109a704b7 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/irq.h>
 #include <linux/irqreturn.h>
 #include <linux/reset.h>
-#include <linux/sched_clock.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -137,11 +136,6 @@ static struct irqaction sun5i_timer_irq = {
        .dev_id = &sun5i_clockevent,
 };
 
-static u64 sun5i_timer_sched_read(void)
-{
-       return ~readl(timer_base + TIMER_CNTVAL_LO_REG(1));
-}
-
 static void __init sun5i_timer_init(struct device_node *node)
 {
        struct reset_control *rstc;
@@ -172,16 +166,11 @@ static void __init sun5i_timer_init(struct device_node *node)
        writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
               timer_base + TIMER_CTL_REG(1));
 
-       sched_clock_register(sun5i_timer_sched_read, 32, rate);
        clocksource_mmio_init(timer_base + TIMER_CNTVAL_LO_REG(1), node->name,
                              rate, 340, 32, clocksource_mmio_readl_down);
 
        ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 
-       ret = setup_irq(irq, &sun5i_timer_irq);
-       if (ret)
-               pr_warn("failed to setup irq %d\n", irq);
-
        /* Enable timer0 interrupt */
        val = readl(timer_base + TIMER_IRQ_EN_REG);
        writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG);
@@ -191,6 +180,10 @@ static void __init sun5i_timer_init(struct device_node *node)
 
        clockevents_config_and_register(&sun5i_clockevent, rate,
                                        TIMER_SYNC_TICKS, 0xffffffff);
+
+       ret = setup_irq(irq, &sun5i_timer_irq);
+       if (ret)
+               pr_warn("failed to setup irq %d\n", irq);
 }
 CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer",
                       sun5i_timer_init);
index 5e98c6b1f284b651f0b74d3673c55f997e47f081..82d2fbb20f7eb70d94a9c9c6e1d6ec3708f53ee0 100644 (file)
@@ -159,7 +159,7 @@ static struct cpufreq_driver exynos_driver = {
 
 static int exynos_cpufreq_probe(struct platform_device *pdev)
 {
-       struct device_node *cpus, *np;
+       struct device_node *cpu0;
        int ret = -EINVAL;
 
        exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
@@ -206,28 +206,19 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
        if (ret)
                goto err_cpufreq_reg;
 
-       cpus = of_find_node_by_path("/cpus");
-       if (!cpus) {
-               pr_err("failed to find cpus node\n");
+       cpu0 = of_get_cpu_node(0, NULL);
+       if (!cpu0) {
+               pr_err("failed to find cpu0 node\n");
                return 0;
        }
 
-       np = of_get_next_child(cpus, NULL);
-       if (!np) {
-               pr_err("failed to find cpus child node\n");
-               of_node_put(cpus);
-               return 0;
-       }
-
-       if (of_find_property(np, "#cooling-cells", NULL)) {
-               cdev = of_cpufreq_cooling_register(np,
+       if (of_find_property(cpu0, "#cooling-cells", NULL)) {
+               cdev = of_cpufreq_cooling_register(cpu0,
                                                   cpu_present_mask);
                if (IS_ERR(cdev))
                        pr_err("running cpufreq without cooling device: %ld\n",
                               PTR_ERR(cdev));
        }
-       of_node_put(np);
-       of_node_put(cpus);
 
        return 0;
 
index bee5df7794d33d1078116c8ac2f3618075230c8c..7cb4b766cf948d3f3e4b813325eda0aa0f0129aa 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/smp.h>
 #include <sysdev/fsl_soc.h>
 
+#include <asm/smp.h>   /* for get_hard_smp_processor_id() in UP configs */
+
 /**
  * struct cpu_data - per CPU data struct
  * @parent: the parent node of cpu clock
index 38e68618513a4728fe637a46b6a6ce79edb54730..980151f34707b2560aab8b1dbe84457b07308949 100644 (file)
@@ -37,11 +37,11 @@ static int mvebu_v7_enter_idle(struct cpuidle_device *dev,
                deepidle = true;
 
        ret = mvebu_v7_cpu_suspend(deepidle);
+       cpu_pm_exit();
+
        if (ret)
                return ret;
 
-       cpu_pm_exit();
-
        return index;
 }
 
@@ -50,17 +50,17 @@ static struct cpuidle_driver armadaxp_idle_driver = {
        .states[0]              = ARM_CPUIDLE_WFI_STATE,
        .states[1]              = {
                .enter                  = mvebu_v7_enter_idle,
-               .exit_latency           = 10,
+               .exit_latency           = 100,
                .power_usage            = 50,
-               .target_residency       = 100,
+               .target_residency       = 1000,
                .name                   = "MV CPU IDLE",
                .desc                   = "CPU power down",
        },
        .states[2]              = {
                .enter                  = mvebu_v7_enter_idle,
-               .exit_latency           = 100,
+               .exit_latency           = 1000,
                .power_usage            = 5,
-               .target_residency       = 1000,
+               .target_residency       = 10000,
                .flags                  = MVEBU_V7_FLAG_DEEP_IDLE,
                .name                   = "MV CPU DEEP IDLE",
                .desc                   = "CPU and L2 Fabric power down",
index 4d534582514e014b5fdb3fc5e0b9db7e52c7b306..080bd2dbde4ba5408504a451e9454b51497202e3 100644 (file)
@@ -44,6 +44,12 @@ void disable_cpuidle(void)
        off = 1;
 }
 
+bool cpuidle_not_available(struct cpuidle_driver *drv,
+                          struct cpuidle_device *dev)
+{
+       return off || !initialized || !drv || !dev || !dev->enabled;
+}
+
 /**
  * cpuidle_play_dead - cpu off-lining
  *
@@ -66,14 +72,8 @@ int cpuidle_play_dead(void)
        return -ENODEV;
 }
 
-/**
- * cpuidle_find_deepest_state - Find deepest state meeting specific conditions.
- * @drv: cpuidle driver for the given CPU.
- * @dev: cpuidle device for the given CPU.
- * @freeze: Whether or not the state should be suitable for suspend-to-idle.
- */
-static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
-                                     struct cpuidle_device *dev, bool freeze)
+static int find_deepest_state(struct cpuidle_driver *drv,
+                             struct cpuidle_device *dev, bool freeze)
 {
        unsigned int latency_req = 0;
        int i, ret = freeze ? -1 : CPUIDLE_DRIVER_STATE_START - 1;
@@ -92,6 +92,17 @@ static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
        return ret;
 }
 
+/**
+ * cpuidle_find_deepest_state - Find the deepest available idle state.
+ * @drv: cpuidle driver for the given CPU.
+ * @dev: cpuidle device for the given CPU.
+ */
+int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
+                              struct cpuidle_device *dev)
+{
+       return find_deepest_state(drv, dev, false);
+}
+
 static void enter_freeze_proper(struct cpuidle_driver *drv,
                                struct cpuidle_device *dev, int index)
 {
@@ -113,15 +124,14 @@ static void enter_freeze_proper(struct cpuidle_driver *drv,
 
 /**
  * cpuidle_enter_freeze - Enter an idle state suitable for suspend-to-idle.
+ * @drv: cpuidle driver for the given CPU.
+ * @dev: cpuidle device for the given CPU.
  *
  * If there are states with the ->enter_freeze callback, find the deepest of
- * them and enter it with frozen tick.  Otherwise, find the deepest state
- * available and enter it normally.
+ * them and enter it with frozen tick.
  */
-void cpuidle_enter_freeze(void)
+int cpuidle_enter_freeze(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
-       struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
-       struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
        int index;
 
        /*
@@ -129,24 +139,11 @@ void cpuidle_enter_freeze(void)
         * that interrupts won't be enabled when it exits and allows the tick to
         * be frozen safely.
         */
-       index = cpuidle_find_deepest_state(drv, dev, true);
-       if (index >= 0) {
-               enter_freeze_proper(drv, dev, index);
-               return;
-       }
-
-       /*
-        * It is not safe to freeze the tick, find the deepest state available
-        * at all and try to enter it normally.
-        */
-       index = cpuidle_find_deepest_state(drv, dev, false);
+       index = find_deepest_state(drv, dev, true);
        if (index >= 0)
-               cpuidle_enter(drv, dev, index);
-       else
-               arch_cpu_idle();
+               enter_freeze_proper(drv, dev, index);
 
-       /* Interrupts are enabled again here. */
-       local_irq_disable();
+       return index;
 }
 
 /**
@@ -205,12 +202,6 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
  */
 int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
-       if (off || !initialized)
-               return -ENODEV;
-
-       if (!drv || !dev || !dev->enabled)
-               return -EBUSY;
-
        return cpuidle_curr_governor->select(drv, dev);
 }
 
index e5541117b3e915de7f08ecc38a58ec9f72bf2c12..50ef8bd8708ba69d93808510c9a8be473d377d7c 100644 (file)
@@ -159,6 +159,9 @@ fence_wait_timeout(struct fence *fence, bool intr, signed long timeout)
        if (WARN_ON(timeout < 0))
                return -EINVAL;
 
+       if (timeout == 0)
+               return fence_is_signaled(fence);
+
        trace_fence_wait_start(fence);
        ret = fence->ops->wait(fence, intr, timeout);
        trace_fence_wait_end(fence);
index 3c97c8fa8d02687290e7340f82666f3466fbda2e..39920d77f288d7802c054130acf72caa8f40465d 100644 (file)
@@ -327,6 +327,9 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
        unsigned seq, shared_count, i = 0;
        long ret = timeout;
 
+       if (!timeout)
+               return reservation_object_test_signaled_rcu(obj, wait_all);
+
 retry:
        fence = NULL;
        shared_count = 0;
@@ -402,8 +405,6 @@ reservation_object_test_signaled_single(struct fence *passed_fence)
        int ret = 1;
 
        if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) {
-               int ret;
-
                fence = fence_get_rcu(lfence);
                if (!fence)
                        return -1;
index 4a5fd245014e6666721c111b85515b2e1b05f74c..83aa55d6fa5d65e6243abc13e29c1d4766768eeb 100644 (file)
 
 #define DRIVER_NAME    "pl08xdmac"
 
+#define PL80X_DMA_BUSWIDTHS \
+       BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
+       BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)
+
 static struct amba_driver pl08x_amba_driver;
 struct pl08x_driver_data;
 
@@ -2070,6 +2076,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->memcpy.device_pause = pl08x_pause;
        pl08x->memcpy.device_resume = pl08x_resume;
        pl08x->memcpy.device_terminate_all = pl08x_terminate_all;
+       pl08x->memcpy.src_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->memcpy.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->memcpy.directions = BIT(DMA_MEM_TO_MEM);
+       pl08x->memcpy.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
        /* Initialize slave engine */
        dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
@@ -2086,6 +2096,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->slave.device_pause = pl08x_pause;
        pl08x->slave.device_resume = pl08x_resume;
        pl08x->slave.device_terminate_all = pl08x_terminate_all;
+       pl08x->slave.src_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->slave.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->slave.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       pl08x->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
        /* Get the platform data */
        pl08x->pd = dev_get_platdata(&adev->dev);
index 1e1a4c5675426048dcef03616c15d8e744db2c6e..0b4fc6fb48ce7c5cec62d9a1ef4291e0b175cfaf 100644 (file)
@@ -238,93 +238,126 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
 }
 
 /*
- * atc_get_current_descriptors -
- * locate the descriptor which equal to physical address in DSCR
- * @atchan: the channel we want to start
- * @dscr_addr: physical descriptor address in DSCR
+ * atc_get_desc_by_cookie - get the descriptor of a cookie
+ * @atchan: the DMA channel
+ * @cookie: the cookie to get the descriptor for
  */
-static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan,
-                                                       u32 dscr_addr)
+static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
+                                               dma_cookie_t cookie)
 {
-       struct at_desc  *desc, *_desc, *child, *desc_cur = NULL;
+       struct at_desc *desc, *_desc;
 
-       list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
-               if (desc->lli.dscr == dscr_addr) {
-                       desc_cur = desc;
-                       break;
-               }
+       list_for_each_entry_safe(desc, _desc, &atchan->queue, desc_node) {
+               if (desc->txd.cookie == cookie)
+                       return desc;
+       }
 
-               list_for_each_entry(child, &desc->tx_list, desc_node) {
-                       if (child->lli.dscr == dscr_addr) {
-                               desc_cur = child;
-                               break;
-                       }
-               }
+       list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
+               if (desc->txd.cookie == cookie)
+                       return desc;
        }
 
-       return desc_cur;
+       return NULL;
 }
 
-/*
- * atc_get_bytes_left -
- * Get the number of bytes residue in dma buffer,
- * @chan: the channel we want to start
+/**
+ * atc_calc_bytes_left - calculates the number of bytes left according to the
+ * value read from CTRLA.
+ *
+ * @current_len: the number of bytes left before reading CTRLA
+ * @ctrla: the value of CTRLA
+ * @desc: the descriptor containing the transfer width
+ */
+static inline int atc_calc_bytes_left(int current_len, u32 ctrla,
+                                       struct at_desc *desc)
+{
+       return current_len - ((ctrla & ATC_BTSIZE_MAX) << desc->tx_width);
+}
+
+/**
+ * atc_calc_bytes_left_from_reg - calculates the number of bytes left according
+ * to the current value of CTRLA.
+ *
+ * @current_len: the number of bytes left before reading CTRLA
+ * @atchan: the channel to read CTRLA for
+ * @desc: the descriptor containing the transfer width
+ */
+static inline int atc_calc_bytes_left_from_reg(int current_len,
+                       struct at_dma_chan *atchan, struct at_desc *desc)
+{
+       u32 ctrla = channel_readl(atchan, CTRLA);
+
+       return atc_calc_bytes_left(current_len, ctrla, desc);
+}
+
+/**
+ * atc_get_bytes_left - get the number of bytes residue for a cookie
+ * @chan: DMA channel
+ * @cookie: transaction identifier to check status of
  */
-static int atc_get_bytes_left(struct dma_chan *chan)
+static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
 {
        struct at_dma_chan      *atchan = to_at_dma_chan(chan);
-       struct at_dma           *atdma = to_at_dma(chan->device);
-       int     chan_id = atchan->chan_common.chan_id;
        struct at_desc *desc_first = atc_first_active(atchan);
-       struct at_desc *desc_cur;
-       int ret = 0, count = 0;
+       struct at_desc *desc;
+       int ret;
+       u32 ctrla, dscr;
 
        /*
-        * Initialize necessary values in the first time.
-        * remain_desc record remain desc length.
+        * If the cookie doesn't match to the currently running transfer then
+        * we can return the total length of the associated DMA transfer,
+        * because it is still queued.
         */
-       if (atchan->remain_desc == 0)
-               /* First descriptor embedds the transaction length */
-               atchan->remain_desc = desc_first->len;
+       desc = atc_get_desc_by_cookie(atchan, cookie);
+       if (desc == NULL)
+               return -EINVAL;
+       else if (desc != desc_first)
+               return desc->total_len;
 
-       /*
-        * This happens when current descriptor transfer complete.
-        * The residual buffer size should reduce current descriptor length.
-        */
-       if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) {
-               clear_bit(ATC_IS_BTC, &atchan->status);
-               desc_cur = atc_get_current_descriptors(atchan,
-                                               channel_readl(atchan, DSCR));
-               if (!desc_cur) {
-                       ret = -EINVAL;
-                       goto out;
-               }
+       /* cookie matches to the currently running transfer */
+       ret = desc_first->total_len;
 
-               count = (desc_cur->lli.ctrla & ATC_BTSIZE_MAX)
-                       << desc_first->tx_width;
-               if (atchan->remain_desc < count) {
-                       ret = -EINVAL;
-                       goto out;
+       if (desc_first->lli.dscr) {
+               /* hardware linked list transfer */
+
+               /*
+                * Calculate the residue by removing the length of the child
+                * descriptors already transferred from the total length.
+                * To get the current child descriptor we can use the value of
+                * the channel's DSCR register and compare it against the value
+                * of the hardware linked list structure of each child
+                * descriptor.
+                */
+
+               ctrla = channel_readl(atchan, CTRLA);
+               rmb(); /* ensure CTRLA is read before DSCR */
+               dscr = channel_readl(atchan, DSCR);
+
+               /* for the first descriptor we can be more accurate */
+               if (desc_first->lli.dscr == dscr)
+                       return atc_calc_bytes_left(ret, ctrla, desc_first);
+
+               ret -= desc_first->len;
+               list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
+                       if (desc->lli.dscr == dscr)
+                               break;
+
+                       ret -= desc->len;
                }
 
-               atchan->remain_desc -= count;
-               ret = atchan->remain_desc;
-       } else {
                /*
-                * Get residual bytes when current
-                * descriptor transfer in progress.
+                * For the last descriptor in the chain we can calculate
+                * the remaining bytes using the channel's register.
+                * Note that the transfer width of the first and last
+                * descriptor may differ.
                 */
-               count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX)
-                               << (desc_first->tx_width);
-               ret = atchan->remain_desc - count;
+               if (!desc->lli.dscr)
+                       ret = atc_calc_bytes_left_from_reg(ret, atchan, desc);
+       } else {
+               /* single transfer */
+               ret = atc_calc_bytes_left_from_reg(ret, atchan, desc_first);
        }
-       /*
-        * Check fifo empty.
-        */
-       if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id)))
-               atc_issue_pending(chan);
 
-out:
        return ret;
 }
 
@@ -539,8 +572,6 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
                                        /* Give information to tasklet */
                                        set_bit(ATC_IS_ERROR, &atchan->status);
                                }
-                               if (pending & AT_DMA_BTC(i))
-                                       set_bit(ATC_IS_BTC, &atchan->status);
                                tasklet_schedule(&atchan->tasklet);
                                ret = IRQ_HANDLED;
                        }
@@ -653,14 +684,18 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                desc->lli.ctrlb = ctrlb;
 
                desc->txd.cookie = 0;
+               desc->len = xfer_count << src_width;
 
                atc_desc_chain(&first, &prev, desc);
        }
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = len;
+       first->total_len = len;
+
+       /* set transfer width for the calculation of the residue */
        first->tx_width = src_width;
+       prev->tx_width = src_width;
 
        /* set end-of-link to the last link descriptor of list*/
        set_desc_eol(desc);
@@ -752,6 +787,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                        | ATC_SRC_WIDTH(mem_width)
                                        | len >> mem_width;
                        desc->lli.ctrlb = ctrlb;
+                       desc->len = len;
 
                        atc_desc_chain(&first, &prev, desc);
                        total_len += len;
@@ -792,6 +828,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                        | ATC_DST_WIDTH(mem_width)
                                        | len >> reg_width;
                        desc->lli.ctrlb = ctrlb;
+                       desc->len = len;
 
                        atc_desc_chain(&first, &prev, desc);
                        total_len += len;
@@ -806,8 +843,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = total_len;
+       first->total_len = total_len;
+
+       /* set transfer width for the calculation of the residue */
        first->tx_width = reg_width;
+       prev->tx_width = reg_width;
 
        /* first link descriptor of list is responsible of flags */
        first->txd.flags = flags; /* client is in control of this ack */
@@ -872,6 +912,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
                                | ATC_FC_MEM2PER
                                | ATC_SIF(atchan->mem_if)
                                | ATC_DIF(atchan->per_if);
+               desc->len = period_len;
                break;
 
        case DMA_DEV_TO_MEM:
@@ -883,6 +924,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
                                | ATC_FC_PER2MEM
                                | ATC_SIF(atchan->per_if)
                                | ATC_DIF(atchan->mem_if);
+               desc->len = period_len;
                break;
 
        default:
@@ -964,7 +1006,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = buf_len;
+       first->total_len = buf_len;
        first->tx_width = reg_width;
 
        return &first->txd;
@@ -1118,7 +1160,7 @@ atc_tx_status(struct dma_chan *chan,
        spin_lock_irqsave(&atchan->lock, flags);
 
        /*  Get number of bytes left in the active transactions */
-       bytes = atc_get_bytes_left(chan);
+       bytes = atc_get_bytes_left(chan, cookie);
 
        spin_unlock_irqrestore(&atchan->lock, flags);
 
@@ -1214,7 +1256,6 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
 
        spin_lock_irqsave(&atchan->lock, flags);
        atchan->descs_allocated = i;
-       atchan->remain_desc = 0;
        list_splice(&tmp_list, &atchan->free_list);
        dma_cookie_init(chan);
        spin_unlock_irqrestore(&atchan->lock, flags);
@@ -1257,7 +1298,6 @@ static void atc_free_chan_resources(struct dma_chan *chan)
        list_splice_init(&atchan->free_list, &list);
        atchan->descs_allocated = 0;
        atchan->status = 0;
-       atchan->remain_desc = 0;
 
        dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
 }
index d6bba6c636c2b9ab4f05331084e07f59b797f1aa..2727ca560572586482cb53a0f38522e0b66abfe3 100644 (file)
@@ -181,8 +181,9 @@ struct at_lli {
  * @at_lli: hardware lli structure
  * @txd: support for the async_tx api
  * @desc_node: node on the channed descriptors list
- * @len: total transaction bytecount
+ * @len: descriptor byte count
  * @tx_width: transfer width
+ * @total_len: total transaction byte count
  */
 struct at_desc {
        /* FIRST values the hardware uses */
@@ -194,6 +195,7 @@ struct at_desc {
        struct list_head                desc_node;
        size_t                          len;
        u32                             tx_width;
+       size_t                          total_len;
 };
 
 static inline struct at_desc *
@@ -213,7 +215,6 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
 enum atc_status {
        ATC_IS_ERROR = 0,
        ATC_IS_PAUSED = 1,
-       ATC_IS_BTC = 2,
        ATC_IS_CYCLIC = 24,
 };
 
@@ -231,7 +232,6 @@ enum atc_status {
  * @save_cfg: configuration register that is saved on suspend/resume cycle
  * @save_dscr: for cyclic operations, preserve next descriptor address in
  *             the cyclic list on suspend/resume cycle
- * @remain_desc: to save remain desc length
  * @dma_sconfig: configuration for slave transfers, passed via
  * .device_config
  * @lock: serializes enqueue/dequeue operations to descriptors lists
@@ -251,7 +251,6 @@ struct at_dma_chan {
        struct tasklet_struct   tasklet;
        u32                     save_cfg;
        u32                     save_dscr;
-       u32                     remain_desc;
        struct dma_slave_config dma_sconfig;
 
        spinlock_t              lock;
index 09e2825a547a2098cc28a0e3e20079c33c52fe09..d9891d3461f6fbd42f5cb85041147513ca07ba73 100644 (file)
@@ -664,7 +664,6 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
        struct at_xdmac_desc    *first = NULL, *prev = NULL;
        unsigned int            periods = buf_len / period_len;
        int                     i;
-       u32                     cfg;
 
        dev_dbg(chan2dev(chan), "%s: buf_addr=%pad, buf_len=%zd, period_len=%zd, dir=%s, flags=0x%lx\n",
                __func__, &buf_addr, buf_len, period_len,
@@ -700,17 +699,17 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
                if (direction == DMA_DEV_TO_MEM) {
                        desc->lld.mbr_sa = atchan->per_src_addr;
                        desc->lld.mbr_da = buf_addr + i * period_len;
-                       cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
+                       desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
                } else {
                        desc->lld.mbr_sa = buf_addr + i * period_len;
                        desc->lld.mbr_da = atchan->per_dst_addr;
-                       cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
+                       desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
                }
                desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1
                        | AT_XDMAC_MBR_UBC_NDEN
                        | AT_XDMAC_MBR_UBC_NSEN
                        | AT_XDMAC_MBR_UBC_NDE
-                       | period_len >> at_xdmac_get_dwidth(cfg);
+                       | period_len >> at_xdmac_get_dwidth(desc->lld.mbr_cfg);
 
                dev_dbg(chan2dev(chan),
                         "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
index 455b7a4f1e87fe890019eb6acd459e8d7c000667..a8ad05291b274498b55deef4bba88a2dbf1ffbd3 100644 (file)
@@ -626,7 +626,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
        dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__, status);
 
        /* Check if we have any interrupt from the DMAC */
-       if (!status)
+       if (!status || !dw->in_use)
                return IRQ_NONE;
 
        /*
index 6565a361e7e51c7e80bbbc6d920880b47aa71af8..b2c3ae07142910a39c90b7ed47f718af35821021 100644 (file)
@@ -26,6 +26,8 @@
 
 #include "internal.h"
 
+#define DRV_NAME       "dw_dmac"
+
 static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
                                        struct of_dma *ofdma)
 {
@@ -284,7 +286,7 @@ static struct platform_driver dw_driver = {
        .remove         = dw_remove,
        .shutdown       = dw_shutdown,
        .driver = {
-               .name   = "dw_dmac",
+               .name   = DRV_NAME,
                .pm     = &dw_dev_pm_ops,
                .of_match_table = of_match_ptr(dw_dma_of_id_table),
                .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
@@ -305,3 +307,4 @@ module_exit(dw_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
+MODULE_ALIAS("platform:" DRV_NAME);
index 18c0a131e4e41d21ec9ffab272f26258fb483011..66a0efb9651d3d8f3240701fafe2299b9abca598 100644 (file)
@@ -531,6 +531,10 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
                dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
        }
 
+       /* Set bits of CONFIG register with dynamic context switching */
+       if (readl(sdma->regs + SDMA_H_CONFIG) == 0)
+               writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
+
        return ret ? 0 : -ETIMEDOUT;
 }
 
@@ -1394,9 +1398,6 @@ static int sdma_init(struct sdma_engine *sdma)
 
        writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
 
-       /* Set bits of CONFIG register with given context switching mode */
-       writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
-
        /* Initializes channel's priorities */
        sdma_set_channel_priority(&sdma->channel[0], 7);
 
index 77a6dcf25b98b818b9d83ecbbf0d99edc3783056..194ec20c940841c9b0de473ac43417f4235c0482 100644 (file)
@@ -230,6 +230,10 @@ static bool is_bwd_noraid(struct pci_dev *pdev)
        switch (pdev->device) {
        case PCI_DEVICE_ID_INTEL_IOAT_BWD2:
        case PCI_DEVICE_ID_INTEL_IOAT_BWD3:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE0:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE1:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE2:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE3:
                return true;
        default:
                return false;
index 8926f271904e45dcf1f4ed7532afe6fc3cbdb323..eb410044e1af5415f4aa1aad48f7564588be1bb1 100644 (file)
@@ -219,6 +219,9 @@ static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id)
 
        while (dint) {
                i = __ffs(dint);
+               /* only handle interrupts belonging to pdma driver*/
+               if (i >= pdev->dma_channels)
+                       break;
                dint &= (dint - 1);
                phy = &pdev->phy[i];
                ret = mmp_pdma_chan_handler(irq, phy);
@@ -999,6 +1002,9 @@ static int mmp_pdma_probe(struct platform_device *op)
        struct resource *iores;
        int i, ret, irq = 0;
        int dma_channels = 0, irq_num = 0;
+       const enum dma_slave_buswidth widths =
+               DMA_SLAVE_BUSWIDTH_1_BYTE   | DMA_SLAVE_BUSWIDTH_2_BYTES |
+               DMA_SLAVE_BUSWIDTH_4_BYTES;
 
        pdev = devm_kzalloc(&op->dev, sizeof(*pdev), GFP_KERNEL);
        if (!pdev)
@@ -1066,6 +1072,10 @@ static int mmp_pdma_probe(struct platform_device *op)
        pdev->device.device_config = mmp_pdma_config;
        pdev->device.device_terminate_all = mmp_pdma_terminate_all;
        pdev->device.copy_align = PDMA_ALIGNMENT;
+       pdev->device.src_addr_widths = widths;
+       pdev->device.dst_addr_widths = widths;
+       pdev->device.directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
+       pdev->device.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
 
        if (pdev->dev->coherent_dma_mask)
                dma_set_mask(pdev->dev, pdev->dev->coherent_dma_mask);
index 70c2fa9963cd4d942afa0b8a99f42c4d2ede784b..b6f4e1fc9c784cc0a3fce3d76877774760cd8c59 100644 (file)
@@ -110,7 +110,7 @@ struct mmp_tdma_chan {
        struct tasklet_struct           tasklet;
 
        struct mmp_tdma_desc            *desc_arr;
-       phys_addr_t                     desc_arr_phys;
+       dma_addr_t                      desc_arr_phys;
        int                             desc_num;
        enum dma_transfer_direction     dir;
        dma_addr_t                      dev_addr;
@@ -166,9 +166,12 @@ static void mmp_tdma_enable_chan(struct mmp_tdma_chan *tdmac)
 static int mmp_tdma_disable_chan(struct dma_chan *chan)
 {
        struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+       u32 tdcr;
 
-       writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN,
-                                       tdmac->reg_base + TDCR);
+       tdcr = readl(tdmac->reg_base + TDCR);
+       tdcr |= TDCR_ABR;
+       tdcr &= ~TDCR_CHANEN;
+       writel(tdcr, tdmac->reg_base + TDCR);
 
        tdmac->status = DMA_COMPLETE;
 
@@ -296,12 +299,27 @@ static int mmp_tdma_clear_chan_irq(struct mmp_tdma_chan *tdmac)
        return -EAGAIN;
 }
 
+static size_t mmp_tdma_get_pos(struct mmp_tdma_chan *tdmac)
+{
+       size_t reg;
+
+       if (tdmac->idx == 0) {
+               reg = __raw_readl(tdmac->reg_base + TDSAR);
+               reg -= tdmac->desc_arr[0].src_addr;
+       } else if (tdmac->idx == 1) {
+               reg = __raw_readl(tdmac->reg_base + TDDAR);
+               reg -= tdmac->desc_arr[0].dst_addr;
+       } else
+               return -EINVAL;
+
+       return reg;
+}
+
 static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id)
 {
        struct mmp_tdma_chan *tdmac = dev_id;
 
        if (mmp_tdma_clear_chan_irq(tdmac) == 0) {
-               tdmac->pos = (tdmac->pos + tdmac->period_len) % tdmac->buf_len;
                tasklet_schedule(&tdmac->tasklet);
                return IRQ_HANDLED;
        } else
@@ -343,7 +361,7 @@ static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
        int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
 
        gpool = tdmac->pool;
-       if (tdmac->desc_arr)
+       if (gpool && tdmac->desc_arr)
                gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
                                size);
        tdmac->desc_arr = NULL;
@@ -499,6 +517,7 @@ static enum dma_status mmp_tdma_tx_status(struct dma_chan *chan,
 {
        struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
 
+       tdmac->pos = mmp_tdma_get_pos(tdmac);
        dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
                         tdmac->buf_len - tdmac->pos);
 
@@ -610,7 +629,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
        int i, ret;
        int irq = 0, irq_num = 0;
        int chan_num = TDMA_CHANNEL_NUM;
-       struct gen_pool *pool;
+       struct gen_pool *pool = NULL;
 
        of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev);
        if (of_id)
index d7a33b3ac46603883e61577f80e29076c0b71221..9c914d62590626fb8f407d7f0bed63b27c37a4f1 100644 (file)
@@ -162,9 +162,9 @@ static const struct reg_offset_data bam_v1_4_reg_info[] = {
        [BAM_P_IRQ_STTS]        = { 0x1010, 0x1000, 0x00, 0x00 },
        [BAM_P_IRQ_CLR]         = { 0x1014, 0x1000, 0x00, 0x00 },
        [BAM_P_IRQ_EN]          = { 0x1018, 0x1000, 0x00, 0x00 },
-       [BAM_P_EVNT_DEST_ADDR]  = { 0x102C, 0x00, 0x1000, 0x00 },
-       [BAM_P_EVNT_REG]        = { 0x1018, 0x00, 0x1000, 0x00 },
-       [BAM_P_SW_OFSTS]        = { 0x1000, 0x00, 0x1000, 0x00 },
+       [BAM_P_EVNT_DEST_ADDR]  = { 0x182C, 0x00, 0x1000, 0x00 },
+       [BAM_P_EVNT_REG]        = { 0x1818, 0x00, 0x1000, 0x00 },
+       [BAM_P_SW_OFSTS]        = { 0x1800, 0x00, 0x1000, 0x00 },
        [BAM_P_DATA_FIFO_ADDR]  = { 0x1824, 0x00, 0x1000, 0x00 },
        [BAM_P_DESC_FIFO_ADDR]  = { 0x181C, 0x00, 0x1000, 0x00 },
        [BAM_P_EVNT_GEN_TRSHLD] = { 0x1828, 0x00, 0x1000, 0x00 },
@@ -1143,6 +1143,10 @@ static int bam_dma_probe(struct platform_device *pdev)
        dma_cap_set(DMA_SLAVE, bdev->common.cap_mask);
 
        /* initialize dmaengine apis */
+       bdev->common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       bdev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+       bdev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       bdev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
        bdev->common.device_alloc_chan_resources = bam_alloc_chan;
        bdev->common.device_free_chan_resources = bam_free_chan;
        bdev->common.device_prep_slave_sg = bam_prep_slave_sg;
index b2431aa300331270fa949ea5c14c41602a6c8e69..9f1d4c7dbab8389039e4ae1da636ca13521314ee 100644 (file)
@@ -582,15 +582,12 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
        }
 }
 
-static void sh_dmae_shutdown(struct platform_device *pdev)
-{
-       struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
-       sh_dmae_ctl_stop(shdev);
-}
-
 #ifdef CONFIG_PM
 static int sh_dmae_runtime_suspend(struct device *dev)
 {
+       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+
+       sh_dmae_ctl_stop(shdev);
        return 0;
 }
 
@@ -605,6 +602,9 @@ static int sh_dmae_runtime_resume(struct device *dev)
 #ifdef CONFIG_PM_SLEEP
 static int sh_dmae_suspend(struct device *dev)
 {
+       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+
+       sh_dmae_ctl_stop(shdev);
        return 0;
 }
 
@@ -929,13 +929,12 @@ static int sh_dmae_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver sh_dmae_driver = {
-       .driver         = {
+       .driver         = {
                .pm     = &sh_dmae_pm,
                .name   = SH_DMAE_DRV_NAME,
                .of_match_table = sh_dmae_of_match,
        },
        .remove         = sh_dmae_remove,
-       .shutdown       = sh_dmae_shutdown,
 };
 
 static int __init sh_dmae_init(void)
index c5f7b4e9eb6c6e490454958473893820bccaeb10..69fac068669fde566f41013cefbdf48db023466c 100644 (file)
@@ -78,7 +78,7 @@ static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
  *     We have to be cautious here. We have seen BIOSes with DMI pointers
  *     pointing to completely the wrong place for example
  */
-static void dmi_table(u8 *buf, int len, int num,
+static void dmi_table(u8 *buf, u32 len, int num,
                      void (*decode)(const struct dmi_header *, void *),
                      void *private_data)
 {
@@ -92,12 +92,6 @@ static void dmi_table(u8 *buf, int len, int num,
        while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
                const struct dmi_header *dm = (const struct dmi_header *)data;
 
-               /*
-                * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
-                */
-               if (dm->type == DMI_ENTRY_END_OF_TABLE)
-                       break;
-
                /*
                 *  We want to know the total length (formatted area and
                 *  strings) before decoding to make sure we won't run off the
@@ -108,13 +102,20 @@ static void dmi_table(u8 *buf, int len, int num,
                        data++;
                if (data - buf < len - 1)
                        decode(dm, private_data);
+
+               /*
+                * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
+                */
+               if (dm->type == DMI_ENTRY_END_OF_TABLE)
+                       break;
+
                data += 2;
                i++;
        }
 }
 
 static phys_addr_t dmi_base;
-static u16 dmi_len;
+static u32 dmi_len;
 static u16 dmi_num;
 
 static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
index 2fe195002021d079ec36515a7ebba4385c1f3600..f07d4a67fa76b3a3cb542e31a24a093c6f7aff97 100644 (file)
@@ -179,12 +179,12 @@ again:
                start = desc->phys_addr;
                end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
 
-               if ((start + size) > end || (start + size) > max)
-                       continue;
-
-               if (end - size > max)
+               if (end > max)
                        end = max;
 
+               if ((start + size) > end)
+                       continue;
+
                if (round_down(end - size, align) < start)
                        continue;
 
index 472fb5b8779f3723f969998b54716b3081901649..9cdbc0c9cb2da87abc65dda442fc75a1612cc51e 100644 (file)
@@ -26,9 +26,12 @@ struct tps65912_gpio_data {
        struct gpio_chip gpio_chip;
 };
 
+#define to_tgd(gc) container_of(gc, struct tps65912_gpio_data, gpio_chip)
+
 static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
        int val;
 
        val = tps65912_reg_read(tps65912, TPS65912_GPIO1 + offset);
@@ -42,7 +45,8 @@ static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
 static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
                              int value)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
        if (value)
                tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
@@ -55,7 +59,8 @@ static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
 static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
                                int value)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
        /* Set the initial value */
        tps65912_gpio_set(gc, offset, value);
@@ -66,7 +71,8 @@ static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
 
 static int tps65912_gpio_input(struct gpio_chip *gc, unsigned offset)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
        return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
                                                                GPIO_CFG_MASK);
index 8cad8e400b44d674ad144e817daa7b63139f2041..4650bf830d6b6306f96e309d4f2782da8a859575 100644 (file)
@@ -46,12 +46,13 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
 
        ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags);
        if (ret < 0) {
-               /* We've found the gpio chip, but the translation failed.
-                * Return true to stop looking and return the translation
-                * error via out_gpio
+               /* We've found a gpio chip, but the translation failed.
+                * Store translation error in out_gpio.
+                * Return false to keep looking, as more than one gpio chip
+                * could be registered per of-node.
                 */
                gg_data->out_gpio = ERR_PTR(ret);
-               return true;
+               return false;
         }
 
        gg_data->out_gpio = gpiochip_get_desc(gc, ret);
index 151a050129e761ce5b10700020dcc47626196918..47f2ce81b4120d64c7c0dcff8d3541a0eeacc7be 100644 (file)
@@ -165,6 +165,15 @@ config DRM_SAVAGE
          Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
          chipset. If M is selected the module will be called savage.
 
+config DRM_VGEM
+       tristate "Virtual GEM provider"
+       depends on DRM
+       help
+         Choose this option to get a virtual graphics memory manager,
+         as used by Mesa's software renderer for enhanced performance.
+         If M is selected the module will be called vgem.
+
+
 source "drivers/gpu/drm/exynos/Kconfig"
 
 source "drivers/gpu/drm/rockchip/Kconfig"
index 2c239b99de64256c588dc94a457adaf6e1d3eded..7d4944e1a60c740abf718cf5ea68eaab48aa084c 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_DRM_SIS)   += sis/
 obj-$(CONFIG_DRM_SAVAGE)+= savage/
 obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
 obj-$(CONFIG_DRM_VIA)  +=via/
+obj-$(CONFIG_DRM_VGEM) += vgem/
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
 obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
index 5c50aa8a8908379980b299ad12fd3868c23fb70c..19a4fba46e4e26ea4e31044b597e0f50f45fb9fd 100644 (file)
@@ -435,21 +435,22 @@ static int kfd_ioctl_get_clock_counters(struct file *filep,
 {
        struct kfd_ioctl_get_clock_counters_args *args = data;
        struct kfd_dev *dev;
-       struct timespec time;
+       struct timespec64 time;
 
        dev = kfd_device_by_id(args->gpu_id);
        if (dev == NULL)
                return -EINVAL;
 
        /* Reading GPU clock counter from KGD */
-       args->gpu_clock_counter = kfd2kgd->get_gpu_clock_counter(dev->kgd);
+       args->gpu_clock_counter =
+               dev->kfd2kgd->get_gpu_clock_counter(dev->kgd);
 
        /* No access to rdtsc. Using raw monotonic time */
-       getrawmonotonic(&time);
-       args->cpu_clock_counter = (uint64_t)timespec_to_ns(&time);
+       getrawmonotonic64(&time);
+       args->cpu_clock_counter = (uint64_t)timespec64_to_ns(&time);
 
-       get_monotonic_boottime(&time);
-       args->system_clock_counter = (uint64_t)timespec_to_ns(&time);
+       get_monotonic_boottime64(&time);
+       args->system_clock_counter = (uint64_t)timespec64_to_ns(&time);
 
        /* Since the counter is in nano-seconds we use 1GHz frequency */
        args->system_clock_freq = 1000000000;
index 5bc32c26b9890eb1f1bf2cf70b1d7e7822bf64fc..ca7f2d3af2ff048301864158b4df492b5e43eb1e 100644 (file)
@@ -94,7 +94,8 @@ static const struct kfd_device_info *lookup_device_info(unsigned short did)
        return NULL;
 }
 
-struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev)
+struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd,
+       struct pci_dev *pdev, const struct kfd2kgd_calls *f2g)
 {
        struct kfd_dev *kfd;
 
@@ -112,6 +113,11 @@ struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev)
        kfd->device_info = device_info;
        kfd->pdev = pdev;
        kfd->init_complete = false;
+       kfd->kfd2kgd = f2g;
+
+       mutex_init(&kfd->doorbell_mutex);
+       memset(&kfd->doorbell_available_index, 0,
+               sizeof(kfd->doorbell_available_index));
 
        return kfd;
 }
@@ -200,8 +206,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
        /* add another 512KB for all other allocations on gart (HPD, fences) */
        size += 512 * 1024;
 
-       if (kfd2kgd->init_gtt_mem_allocation(kfd->kgd, size, &kfd->gtt_mem,
-                       &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)) {
+       if (kfd->kfd2kgd->init_gtt_mem_allocation(
+                       kfd->kgd, size, &kfd->gtt_mem,
+                       &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)){
                dev_err(kfd_device,
                        "Could not allocate %d bytes for device (%x:%x)\n",
                        size, kfd->pdev->vendor, kfd->pdev->device);
@@ -270,7 +277,7 @@ device_iommu_pasid_error:
 kfd_topology_add_device_error:
        kfd_gtt_sa_fini(kfd);
 kfd_gtt_sa_init_error:
-       kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
+       kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
        dev_err(kfd_device,
                "device (%x:%x) NOT added due to errors\n",
                kfd->pdev->vendor, kfd->pdev->device);
@@ -285,7 +292,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
                amd_iommu_free_device(kfd->pdev);
                kfd_topology_remove_device(kfd);
                kfd_gtt_sa_fini(kfd);
-               kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
+               kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
        }
 
        kfree(kfd);
index b3589d0e39b9c2027a4e680625663dfdcbe3cc63..69af73f153103075f00c9344f836bd7eb3b24668 100644 (file)
@@ -62,12 +62,18 @@ enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type)
        return KFD_MQD_TYPE_CP;
 }
 
-static inline unsigned int get_first_pipe(struct device_queue_manager *dqm)
+unsigned int get_first_pipe(struct device_queue_manager *dqm)
 {
-       BUG_ON(!dqm);
+       BUG_ON(!dqm || !dqm->dev);
        return dqm->dev->shared_resources.first_compute_pipe;
 }
 
+unsigned int get_pipes_num(struct device_queue_manager *dqm)
+{
+       BUG_ON(!dqm || !dqm->dev);
+       return dqm->dev->shared_resources.compute_pipe_count;
+}
+
 static inline unsigned int get_pipes_num_cpsch(void)
 {
        return PIPE_PER_ME_CP_SCHEDULING;
@@ -76,7 +82,8 @@ static inline unsigned int get_pipes_num_cpsch(void)
 void program_sh_mem_settings(struct device_queue_manager *dqm,
                                        struct qcm_process_device *qpd)
 {
-       return kfd2kgd->program_sh_mem_settings(dqm->dev->kgd, qpd->vmid,
+       return dqm->dev->kfd2kgd->program_sh_mem_settings(
+                                               dqm->dev->kgd, qpd->vmid,
                                                qpd->sh_mem_config,
                                                qpd->sh_mem_ape1_base,
                                                qpd->sh_mem_ape1_limit,
@@ -451,9 +458,12 @@ set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid,
 {
        uint32_t pasid_mapping;
 
-       pasid_mapping = (pasid == 0) ? 0 : (uint32_t)pasid |
-                                               ATC_VMID_PASID_MAPPING_VALID;
-       return kfd2kgd->set_pasid_vmid_mapping(dqm->dev->kgd, pasid_mapping,
+       pasid_mapping = (pasid == 0) ? 0 :
+               (uint32_t)pasid |
+               ATC_VMID_PASID_MAPPING_VALID;
+
+       return dqm->dev->kfd2kgd->set_pasid_vmid_mapping(
+                                               dqm->dev->kgd, pasid_mapping,
                                                vmid);
 }
 
@@ -505,7 +515,7 @@ int init_pipelines(struct device_queue_manager *dqm,
                pipe_hpd_addr = dqm->pipelines_addr + i * CIK_HPD_EOP_BYTES;
                pr_debug("kfd: pipeline address %llX\n", pipe_hpd_addr);
                /* = log2(bytes/4)-1 */
-               kfd2kgd->init_pipeline(dqm->dev->kgd, inx,
+               dqm->dev->kfd2kgd->init_pipeline(dqm->dev->kgd, inx,
                                CIK_HPD_EOP_BYTES_LOG2 - 3, pipe_hpd_addr);
        }
 
@@ -639,6 +649,7 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
        pr_debug("     sdma queue id: %d\n", q->properties.sdma_queue_id);
        pr_debug("     sdma engine id: %d\n", q->properties.sdma_engine_id);
 
+       init_sdma_vm(dqm, q, qpd);
        retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
                                &q->gart_mqd_addr, &q->properties);
        if (retval != 0) {
@@ -646,7 +657,14 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
                return retval;
        }
 
-       init_sdma_vm(dqm, q, qpd);
+       retval = mqd->load_mqd(mqd, q->mqd, 0,
+                               0, NULL);
+       if (retval != 0) {
+               deallocate_sdma_queue(dqm, q->sdma_id);
+               mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
+               return retval;
+       }
+
        return 0;
 }
 
@@ -891,7 +909,7 @@ out:
        return retval;
 }
 
-static int fence_wait_timeout(unsigned int *fence_addr,
+static int amdkfd_fence_wait_timeout(unsigned int *fence_addr,
                                unsigned int fence_value,
                                unsigned long timeout)
 {
@@ -947,7 +965,7 @@ static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock)
        pm_send_query_status(&dqm->packets, dqm->fence_gpu_addr,
                                KFD_FENCE_COMPLETED);
        /* should be timed out */
-       fence_wait_timeout(dqm->fence_addr, KFD_FENCE_COMPLETED,
+       amdkfd_fence_wait_timeout(dqm->fence_addr, KFD_FENCE_COMPLETED,
                                QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS);
        pm_release_ib(&dqm->packets);
        dqm->active_runlist = false;
index d64f86cda34f5a155e176526d5f3a3463b96c826..488f51d19427a8273b672df18962a4dafe9feaf5 100644 (file)
@@ -163,6 +163,8 @@ void program_sh_mem_settings(struct device_queue_manager *dqm,
                                        struct qcm_process_device *qpd);
 int init_pipelines(struct device_queue_manager *dqm,
                unsigned int pipes_num, unsigned int first_pipe);
+unsigned int get_first_pipe(struct device_queue_manager *dqm);
+unsigned int get_pipes_num(struct device_queue_manager *dqm);
 
 extern inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
 {
@@ -175,10 +177,4 @@ get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
        return (pdd->lds_base >> 60) & 0x0E;
 }
 
-extern inline unsigned int get_pipes_num(struct device_queue_manager *dqm)
-{
-       BUG_ON(!dqm || !dqm->dev);
-       return dqm->dev->shared_resources.compute_pipe_count;
-}
-
 #endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */
index 6b072466e2a6f628c8a1ff4a026cf5788af65c43..5469efe0523e8d85b11ad33729bfed9036051dfa 100644 (file)
@@ -131,5 +131,5 @@ static int register_process_cik(struct device_queue_manager *dqm,
 
 static int initialize_cpsch_cik(struct device_queue_manager *dqm)
 {
-       return init_pipelines(dqm, get_pipes_num(dqm), 0);
+       return init_pipelines(dqm, get_pipes_num(dqm), get_first_pipe(dqm));
 }
index 1a9b355dd114595f8bcf156907e486ebe2bbbdb4..17e56dcc8540ff8bbb8e18599094dd49405c9ccf 100644 (file)
@@ -32,9 +32,6 @@
  * and that's assures that any user process won't get access to the
  * kernel doorbells page
  */
-static DEFINE_MUTEX(doorbell_mutex);
-static unsigned long doorbell_available_index[
-       DIV_ROUND_UP(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, BITS_PER_LONG)] = { 0 };
 
 #define KERNEL_DOORBELL_PASID 1
 #define KFD_SIZE_OF_DOORBELL_IN_BYTES 4
@@ -170,12 +167,12 @@ u32 __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd,
 
        BUG_ON(!kfd || !doorbell_off);
 
-       mutex_lock(&doorbell_mutex);
-       inx = find_first_zero_bit(doorbell_available_index,
+       mutex_lock(&kfd->doorbell_mutex);
+       inx = find_first_zero_bit(kfd->doorbell_available_index,
                                        KFD_MAX_NUM_OF_QUEUES_PER_PROCESS);
 
-       __set_bit(inx, doorbell_available_index);
-       mutex_unlock(&doorbell_mutex);
+       __set_bit(inx, kfd->doorbell_available_index);
+       mutex_unlock(&kfd->doorbell_mutex);
 
        if (inx >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
                return NULL;
@@ -203,9 +200,9 @@ void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *db_addr)
 
        inx = (unsigned int)(db_addr - kfd->doorbell_kernel_ptr);
 
-       mutex_lock(&doorbell_mutex);
-       __clear_bit(inx, doorbell_available_index);
-       mutex_unlock(&doorbell_mutex);
+       mutex_lock(&kfd->doorbell_mutex);
+       __clear_bit(inx, kfd->doorbell_available_index);
+       mutex_unlock(&kfd->doorbell_mutex);
 }
 
 inline void write_kernel_doorbell(u32 __iomem *db, u32 value)
index e415a2a9207eb4605632f91e97e2a271809c04d1..c7d298e62c96bc026154fbe48c4cc7a3828abdb9 100644 (file)
@@ -44,7 +44,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
        BUG_ON(!kq || !dev);
        BUG_ON(type != KFD_QUEUE_TYPE_DIQ && type != KFD_QUEUE_TYPE_HIQ);
 
-       pr_debug("kfd: In func %s initializing queue type %d size %d\n",
+       pr_debug("amdkfd: In func %s initializing queue type %d size %d\n",
                        __func__, KFD_QUEUE_TYPE_HIQ, queue_size);
 
        nop.opcode = IT_NOP;
@@ -69,12 +69,16 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
 
        prop.doorbell_ptr = kfd_get_kernel_doorbell(dev, &prop.doorbell_off);
 
-       if (prop.doorbell_ptr == NULL)
+       if (prop.doorbell_ptr == NULL) {
+               pr_err("amdkfd: error init doorbell");
                goto err_get_kernel_doorbell;
+       }
 
        retval = kfd_gtt_sa_allocate(dev, queue_size, &kq->pq);
-       if (retval != 0)
+       if (retval != 0) {
+               pr_err("amdkfd: error init pq queues size (%d)\n", queue_size);
                goto err_pq_allocate_vidmem;
+       }
 
        kq->pq_kernel_addr = kq->pq->cpu_ptr;
        kq->pq_gpu_addr = kq->pq->gpu_addr;
@@ -165,10 +169,8 @@ err_rptr_allocate_vidmem:
 err_eop_allocate_vidmem:
        kfd_gtt_sa_free(dev, kq->pq);
 err_pq_allocate_vidmem:
-       pr_err("kfd: error init pq\n");
        kfd_release_kernel_doorbell(dev, prop.doorbell_ptr);
 err_get_kernel_doorbell:
-       pr_err("kfd: error init doorbell");
        return false;
 
 }
@@ -187,6 +189,8 @@ static void uninitialize(struct kernel_queue *kq)
        else if (kq->queue->properties.type == KFD_QUEUE_TYPE_DIQ)
                kfd_gtt_sa_free(kq->dev, kq->fence_mem_obj);
 
+       kq->mqd->uninit_mqd(kq->mqd, kq->queue->mqd, kq->queue->mqd_mem_obj);
+
        kfd_gtt_sa_free(kq->dev, kq->rptr_mem);
        kfd_gtt_sa_free(kq->dev, kq->wptr_mem);
        kq->ops_asic_specific.uninitialize(kq);
@@ -211,7 +215,7 @@ static int acquire_packet_buffer(struct kernel_queue *kq,
        queue_address = (unsigned int *)kq->pq_kernel_addr;
        queue_size_dwords = kq->queue->properties.queue_size / sizeof(uint32_t);
 
-       pr_debug("kfd: In func %s\nrptr: %d\nwptr: %d\nqueue_address 0x%p\n",
+       pr_debug("amdkfd: In func %s\nrptr: %d\nwptr: %d\nqueue_address 0x%p\n",
                        __func__, rptr, wptr, queue_address);
 
        available_size = (rptr - 1 - wptr + queue_size_dwords) %
@@ -296,7 +300,7 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
        }
 
        if (kq->ops.initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) {
-               pr_err("kfd: failed to init kernel queue\n");
+               pr_err("amdkfd: failed to init kernel queue\n");
                kfree(kq);
                return NULL;
        }
@@ -319,7 +323,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
 
        BUG_ON(!dev);
 
-       pr_err("kfd: starting kernel queue test\n");
+       pr_err("amdkfd: starting kernel queue test\n");
 
        kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ);
        BUG_ON(!kq);
@@ -330,7 +334,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
                buffer[i] = kq->nop_packet;
        kq->ops.submit_packet(kq);
 
-       pr_err("kfd: ending kernel queue test\n");
+       pr_err("amdkfd: ending kernel queue test\n");
 }
 
 
index 3f34ae16f0750a04365c75cf448d66574e16e9b6..4e0a68f13a77bc4153256161224c0ab4fc3cf5bc 100644 (file)
@@ -34,7 +34,6 @@
 #define KFD_DRIVER_MINOR       7
 #define KFD_DRIVER_PATCHLEVEL  1
 
-const struct kfd2kgd_calls *kfd2kgd;
 static const struct kgd2kfd_calls kgd2kfd = {
        .exit           = kgd2kfd_exit,
        .probe          = kgd2kfd_probe,
@@ -55,9 +54,7 @@ module_param(max_num_of_queues_per_device, int, 0444);
 MODULE_PARM_DESC(max_num_of_queues_per_device,
        "Maximum number of supported queues per device (1 = Minimum, 4096 = default)");
 
-bool kgd2kfd_init(unsigned interface_version,
-                 const struct kfd2kgd_calls *f2g,
-                 const struct kgd2kfd_calls **g2f)
+bool kgd2kfd_init(unsigned interface_version, const struct kgd2kfd_calls **g2f)
 {
        /*
         * Only one interface version is supported,
@@ -66,11 +63,6 @@ bool kgd2kfd_init(unsigned interface_version,
        if (interface_version != KFD_INTERFACE_VERSION)
                return false;
 
-       /* Protection against multiple amd kgd loads */
-       if (kfd2kgd)
-               return true;
-
-       kfd2kgd = f2g;
        *g2f = &kgd2kfd;
 
        return true;
@@ -85,8 +77,6 @@ static int __init kfd_module_init(void)
 {
        int err;
 
-       kfd2kgd = NULL;
-
        /* Verify module parameters */
        if ((sched_policy < KFD_SCHED_POLICY_HWS) ||
                (sched_policy > KFD_SCHED_POLICY_NO_HWS)) {
index a09e18a339f34ef1268ce9ccd8c6ef0804c9ff76..434979428fc01264647b6189d41aea235d4fda4b 100644 (file)
@@ -151,14 +151,15 @@ static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd,
 static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
                        uint32_t queue_id, uint32_t __user *wptr)
 {
-       return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
+       return mm->dev->kfd2kgd->hqd_load
+               (mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
 }
 
 static int load_mqd_sdma(struct mqd_manager *mm, void *mqd,
                        uint32_t pipe_id, uint32_t queue_id,
                        uint32_t __user *wptr)
 {
-       return kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
+       return mm->dev->kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
 }
 
 static int update_mqd(struct mqd_manager *mm, void *mqd,
@@ -245,7 +246,7 @@ static int destroy_mqd(struct mqd_manager *mm, void *mqd,
                        unsigned int timeout, uint32_t pipe_id,
                        uint32_t queue_id)
 {
-       return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
+       return mm->dev->kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
                                        pipe_id, queue_id);
 }
 
@@ -258,7 +259,7 @@ static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd,
                                unsigned int timeout, uint32_t pipe_id,
                                uint32_t queue_id)
 {
-       return kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
+       return mm->dev->kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
 }
 
 static bool is_occupied(struct mqd_manager *mm, void *mqd,
@@ -266,7 +267,7 @@ static bool is_occupied(struct mqd_manager *mm, void *mqd,
                        uint32_t queue_id)
 {
 
-       return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
+       return mm->dev->kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
                                        pipe_id, queue_id);
 
 }
@@ -275,7 +276,7 @@ static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd,
                        uint64_t queue_address, uint32_t pipe_id,
                        uint32_t queue_id)
 {
-       return kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
+       return mm->dev->kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
 }
 
 /*
index 5a44f2fecf3826b7b90e18cf3d22b7f64c113a26..f21fccebd75b2bd082a6b3c6c45aa6cd7353ef5d 100644 (file)
@@ -148,6 +148,11 @@ struct kfd_dev {
 
        struct kgd2kfd_shared_resources shared_resources;
 
+       const struct kfd2kgd_calls *kfd2kgd;
+       struct mutex doorbell_mutex;
+       unsigned long doorbell_available_index[DIV_ROUND_UP(
+               KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, BITS_PER_LONG)];
+
        void *gtt_mem;
        uint64_t gtt_start_gpu_addr;
        void *gtt_start_cpu_ptr;
@@ -164,13 +169,12 @@ struct kfd_dev {
 
 /* KGD2KFD callbacks */
 void kgd2kfd_exit(void);
-struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev);
+struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd,
+                       struct pci_dev *pdev, const struct kfd2kgd_calls *f2g);
 bool kgd2kfd_device_init(struct kfd_dev *kfd,
-                        const struct kgd2kfd_shared_resources *gpu_resources);
+                       const struct kgd2kfd_shared_resources *gpu_resources);
 void kgd2kfd_device_exit(struct kfd_dev *kfd);
 
-extern const struct kfd2kgd_calls *kfd2kgd;
-
 enum kfd_mempool {
        KFD_MEMPOOL_SYSTEM_CACHEABLE = 1,
        KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2,
@@ -378,8 +382,6 @@ struct qcm_process_device {
        /* The Device Queue Manager that owns this data */
        struct device_queue_manager *dqm;
        struct process_queue_manager *pqm;
-       /* Device Queue Manager lock */
-       struct mutex *lock;
        /* Queues list */
        struct list_head queues_list;
        struct list_head priv_queue_list;
index a369c149d1727e78cb67413578e6fe7ddd11d614..945d6226dc51d5b9b55e6af19229a5a9e872f802 100644 (file)
@@ -162,10 +162,16 @@ static void kfd_process_wq_release(struct work_struct *work)
 
        p = my_work->p;
 
+       pr_debug("Releasing process (pasid %d) in workqueue\n",
+                       p->pasid);
+
        mutex_lock(&p->mutex);
 
        list_for_each_entry_safe(pdd, temp, &p->per_device_data,
                                                        per_device_list) {
+               pr_debug("Releasing pdd (topology id %d) for process (pasid %d) in workqueue\n",
+                               pdd->dev->id, p->pasid);
+
                amd_iommu_unbind_pasid(pdd->dev->pdev, p->pasid);
                list_del(&pdd->per_device_list);
 
index 498399323a8cd503f35fb3e828abf08c2368cad8..661c6605d31b39033a42a5d4297e1684ed734011 100644 (file)
@@ -726,13 +726,14 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
                }
 
                sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
-                               kfd2kgd->get_max_engine_clock_in_mhz(
+                       dev->gpu->kfd2kgd->get_max_engine_clock_in_mhz(
                                        dev->gpu->kgd));
                sysfs_show_64bit_prop(buffer, "local_mem_size",
-                               kfd2kgd->get_vmem_size(dev->gpu->kgd));
+                       dev->gpu->kfd2kgd->get_vmem_size(
+                                       dev->gpu->kgd));
 
                sysfs_show_32bit_prop(buffer, "fw_version",
-                               kfd2kgd->get_fw_version(
+                       dev->gpu->kfd2kgd->get_fw_version(
                                                dev->gpu->kgd,
                                                KGD_ENGINE_MEC1));
        }
@@ -1099,8 +1100,9 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu)
        buf[2] = gpu->pdev->subsystem_device;
        buf[3] = gpu->pdev->device;
        buf[4] = gpu->pdev->bus->number;
-       buf[5] = (uint32_t)(kfd2kgd->get_vmem_size(gpu->kgd) & 0xffffffff);
-       buf[6] = (uint32_t)(kfd2kgd->get_vmem_size(gpu->kgd) >> 32);
+       buf[5] = (uint32_t)(gpu->kfd2kgd->get_vmem_size(gpu->kgd)
+                       & 0xffffffff);
+       buf[6] = (uint32_t)(gpu->kfd2kgd->get_vmem_size(gpu->kgd) >> 32);
 
        for (i = 0, hashout = 0; i < 7; i++)
                hashout ^= hash_32(buf[i], KFD_GPU_ID_HASH_WIDTH);
index 239bc16a1ddd61c9fd65d3d1f1284025fd69df2c..dabd94446b7b2a5d771cd7a2cc704d73cddff087 100644 (file)
@@ -76,37 +76,6 @@ struct kgd2kfd_shared_resources {
        size_t doorbell_start_offset;
 };
 
-/**
- * struct kgd2kfd_calls
- *
- * @exit: Notifies amdkfd that kgd module is unloaded
- *
- * @probe: Notifies amdkfd about a probe done on a device in the kgd driver.
- *
- * @device_init: Initialize the newly probed device (if it is a device that
- * amdkfd supports)
- *
- * @device_exit: Notifies amdkfd about a removal of a kgd device
- *
- * @suspend: Notifies amdkfd about a suspend action done to a kgd device
- *
- * @resume: Notifies amdkfd about a resume action done to a kgd device
- *
- * This structure contains function callback pointers so the kgd driver
- * will notify to the amdkfd about certain status changes.
- *
- */
-struct kgd2kfd_calls {
-       void (*exit)(void);
-       struct kfd_dev* (*probe)(struct kgd_dev *kgd, struct pci_dev *pdev);
-       bool (*device_init)(struct kfd_dev *kfd,
-                       const struct kgd2kfd_shared_resources *gpu_resources);
-       void (*device_exit)(struct kfd_dev *kfd);
-       void (*interrupt)(struct kfd_dev *kfd, const void *ih_ring_entry);
-       void (*suspend)(struct kfd_dev *kfd);
-       int (*resume)(struct kfd_dev *kfd);
-};
-
 /**
  * struct kfd2kgd_calls
  *
@@ -196,8 +165,39 @@ struct kfd2kgd_calls {
                                enum kgd_engine_type type);
 };
 
+/**
+ * struct kgd2kfd_calls
+ *
+ * @exit: Notifies amdkfd that kgd module is unloaded
+ *
+ * @probe: Notifies amdkfd about a probe done on a device in the kgd driver.
+ *
+ * @device_init: Initialize the newly probed device (if it is a device that
+ * amdkfd supports)
+ *
+ * @device_exit: Notifies amdkfd about a removal of a kgd device
+ *
+ * @suspend: Notifies amdkfd about a suspend action done to a kgd device
+ *
+ * @resume: Notifies amdkfd about a resume action done to a kgd device
+ *
+ * This structure contains function callback pointers so the kgd driver
+ * will notify to the amdkfd about certain status changes.
+ *
+ */
+struct kgd2kfd_calls {
+       void (*exit)(void);
+       struct kfd_dev* (*probe)(struct kgd_dev *kgd, struct pci_dev *pdev,
+               const struct kfd2kgd_calls *f2g);
+       bool (*device_init)(struct kfd_dev *kfd,
+                       const struct kgd2kfd_shared_resources *gpu_resources);
+       void (*device_exit)(struct kfd_dev *kfd);
+       void (*interrupt)(struct kfd_dev *kfd, const void *ih_ring_entry);
+       void (*suspend)(struct kfd_dev *kfd);
+       int (*resume)(struct kfd_dev *kfd);
+};
+
 bool kgd2kfd_init(unsigned interface_version,
-               const struct kfd2kgd_calls *f2g,
                const struct kgd2kfd_calls **g2f);
 
 #endif /* KGD_KFD_INTERFACE_H_INCLUDED */
index 0409b907de5d5cc771543d17cc50ed20bad3e3ba..f69b92535505b5ae1c899d6f9b08f76501851fa7 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/clk.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
  * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
  * @event: pointer to the current page flip event
  * @id: CRTC id (returned by drm_crtc_index)
- * @dpms: DPMS mode
+ * @enabled: CRTC state
  */
 struct atmel_hlcdc_crtc {
        struct drm_crtc base;
        struct atmel_hlcdc_dc *dc;
        struct drm_pending_vblank_event *event;
        int id;
-       int dpms;
+       bool enabled;
 };
 
 static inline struct atmel_hlcdc_crtc *
@@ -53,86 +54,17 @@ drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
        return container_of(crtc, struct atmel_hlcdc_crtc, base);
 }
 
-static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode)
+static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
 {
-       struct drm_device *dev = c->dev;
        struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
        struct regmap *regmap = crtc->dc->hlcdc->regmap;
-       unsigned int status;
-
-       if (mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
-
-       if (crtc->dpms == mode)
-               return;
-
-       pm_runtime_get_sync(dev->dev);
-
-       if (mode != DRM_MODE_DPMS_ON) {
-               regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
-               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
-                      (status & ATMEL_HLCDC_DISP))
-                       cpu_relax();
-
-               regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
-               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
-                      (status & ATMEL_HLCDC_SYNC))
-                       cpu_relax();
-
-               regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
-               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
-                      (status & ATMEL_HLCDC_PIXEL_CLK))
-                       cpu_relax();
-
-               clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
-
-               pm_runtime_allow(dev->dev);
-       } else {
-               pm_runtime_forbid(dev->dev);
-
-               clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
-
-               regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
-               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
-                      !(status & ATMEL_HLCDC_PIXEL_CLK))
-                       cpu_relax();
-
-
-               regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
-               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
-                      !(status & ATMEL_HLCDC_SYNC))
-                       cpu_relax();
-
-               regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
-               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
-                      !(status & ATMEL_HLCDC_DISP))
-                       cpu_relax();
-       }
-
-       pm_runtime_put_sync(dev->dev);
-
-       crtc->dpms = mode;
-}
-
-static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
-                                    struct drm_display_mode *mode,
-                                    struct drm_display_mode *adj,
-                                    int x, int y,
-                                    struct drm_framebuffer *old_fb)
-{
-       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
-       struct regmap *regmap = crtc->dc->hlcdc->regmap;
-       struct drm_plane *plane = c->primary;
-       struct drm_framebuffer *fb;
+       struct drm_display_mode *adj = &c->state->adjusted_mode;
        unsigned long mode_rate;
        struct videomode vm;
        unsigned long prate;
        unsigned int cfg;
        int div;
 
-       if (atmel_hlcdc_dc_mode_valid(crtc->dc, adj) != MODE_OK)
-               return -EINVAL;
-
        vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
        vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
        vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start;
@@ -153,10 +85,10 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
                     (adj->crtc_hdisplay - 1) |
                     ((adj->crtc_vdisplay - 1) << 16));
 
-       cfg = ATMEL_HLCDC_CLKPOL;
+       cfg = 0;
 
        prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
-       mode_rate = mode->crtc_clock * 1000;
+       mode_rate = adj->crtc_clock * 1000;
        if ((prate / 2) < mode_rate) {
                prate *= 2;
                cfg |= ATMEL_HLCDC_CLKSEL;
@@ -174,10 +106,10 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
 
        cfg = 0;
 
-       if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+       if (adj->flags & DRM_MODE_FLAG_NVSYNC)
                cfg |= ATMEL_HLCDC_VSPOL;
 
-       if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+       if (adj->flags & DRM_MODE_FLAG_NHSYNC)
                cfg |= ATMEL_HLCDC_HSPOL;
 
        regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
@@ -187,77 +119,155 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
                           ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
                           ATMEL_HLCDC_GUARDTIME_MASK,
                           cfg);
+}
+
+static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
+                                       const struct drm_display_mode *mode,
+                                       struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void atmel_hlcdc_crtc_disable(struct drm_crtc *c)
+{
+       struct drm_device *dev = c->dev;
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+       struct regmap *regmap = crtc->dc->hlcdc->regmap;
+       unsigned int status;
 
-       fb = plane->fb;
-       plane->fb = old_fb;
+       if (!crtc->enabled)
+               return;
+
+       drm_crtc_vblank_off(c);
+
+       pm_runtime_get_sync(dev->dev);
 
-       return atmel_hlcdc_plane_update_with_mode(plane, c, fb, 0, 0,
-                                                 adj->hdisplay, adj->vdisplay,
-                                                 x << 16, y << 16,
-                                                 adj->hdisplay << 16,
-                                                 adj->vdisplay << 16,
-                                                 adj);
+       regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
+       while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+              (status & ATMEL_HLCDC_DISP))
+               cpu_relax();
+
+       regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
+       while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+              (status & ATMEL_HLCDC_SYNC))
+               cpu_relax();
+
+       regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
+       while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+              (status & ATMEL_HLCDC_PIXEL_CLK))
+               cpu_relax();
+
+       clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
+       pinctrl_pm_select_sleep_state(dev->dev);
+
+       pm_runtime_allow(dev->dev);
+
+       pm_runtime_put_sync(dev->dev);
+
+       crtc->enabled = false;
 }
 
-int atmel_hlcdc_crtc_mode_set_base(struct drm_crtc *c, int x, int y,
-                                  struct drm_framebuffer *old_fb)
+static void atmel_hlcdc_crtc_enable(struct drm_crtc *c)
 {
-       struct drm_plane *plane = c->primary;
-       struct drm_framebuffer *fb = plane->fb;
-       struct drm_display_mode *mode = &c->hwmode;
-
-       plane->fb = old_fb;
-
-       return plane->funcs->update_plane(plane, c, fb,
-                                         0, 0,
-                                         mode->hdisplay,
-                                         mode->vdisplay,
-                                         x << 16, y << 16,
-                                         mode->hdisplay << 16,
-                                         mode->vdisplay << 16);
+       struct drm_device *dev = c->dev;
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+       struct regmap *regmap = crtc->dc->hlcdc->regmap;
+       unsigned int status;
+
+       if (crtc->enabled)
+               return;
+
+       pm_runtime_get_sync(dev->dev);
+
+       pm_runtime_forbid(dev->dev);
+
+       pinctrl_pm_select_default_state(dev->dev);
+       clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
+
+       regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
+       while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+              !(status & ATMEL_HLCDC_PIXEL_CLK))
+               cpu_relax();
+
+
+       regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
+       while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+              !(status & ATMEL_HLCDC_SYNC))
+               cpu_relax();
+
+       regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
+       while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+              !(status & ATMEL_HLCDC_DISP))
+               cpu_relax();
+
+       pm_runtime_put_sync(dev->dev);
+
+       drm_crtc_vblank_on(c);
+
+       crtc->enabled = true;
 }
 
-static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc)
+void atmel_hlcdc_crtc_suspend(struct drm_crtc *c)
 {
-       atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+       if (crtc->enabled) {
+               atmel_hlcdc_crtc_disable(c);
+               /* save enable state for resume */
+               crtc->enabled = true;
+       }
 }
 
-static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc)
+void atmel_hlcdc_crtc_resume(struct drm_crtc *c)
 {
-       atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+       if (crtc->enabled) {
+               crtc->enabled = false;
+               atmel_hlcdc_crtc_enable(c);
+       }
 }
 
-static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
-                                       const struct drm_display_mode *mode,
-                                       struct drm_display_mode *adjusted_mode)
+static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
+                                        struct drm_crtc_state *s)
 {
-       return true;
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+       if (atmel_hlcdc_dc_mode_valid(crtc->dc, &s->adjusted_mode) != MODE_OK)
+               return -EINVAL;
+
+       return atmel_hlcdc_plane_prepare_disc_area(s);
 }
 
-static void atmel_hlcdc_crtc_disable(struct drm_crtc *crtc)
+static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c)
 {
-       struct drm_plane *plane;
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
 
-       atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-       crtc->primary->funcs->disable_plane(crtc->primary);
+       if (c->state->event) {
+               c->state->event->pipe = drm_crtc_index(c);
 
-       drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) {
-               if (plane->crtc != crtc)
-                       continue;
+               WARN_ON(drm_crtc_vblank_get(c) != 0);
 
-               plane->funcs->disable_plane(crtc->primary);
-               plane->crtc = NULL;
+               crtc->event = c->state->event;
+               c->state->event = NULL;
        }
 }
 
+static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc)
+{
+       /* TODO: write common plane control register if available */
+}
+
 static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
        .mode_fixup = atmel_hlcdc_crtc_mode_fixup,
-       .dpms = atmel_hlcdc_crtc_dpms,
-       .mode_set = atmel_hlcdc_crtc_mode_set,
-       .mode_set_base = atmel_hlcdc_crtc_mode_set_base,
-       .prepare = atmel_hlcdc_crtc_prepare,
-       .commit = atmel_hlcdc_crtc_commit,
+       .mode_set = drm_helper_crtc_mode_set,
+       .mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb,
+       .mode_set_base = drm_helper_crtc_mode_set_base,
        .disable = atmel_hlcdc_crtc_disable,
+       .enable = atmel_hlcdc_crtc_enable,
+       .atomic_check = atmel_hlcdc_crtc_atomic_check,
+       .atomic_begin = atmel_hlcdc_crtc_atomic_begin,
+       .atomic_flush = atmel_hlcdc_crtc_atomic_flush,
 };
 
 static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
@@ -306,61 +316,13 @@ void atmel_hlcdc_crtc_irq(struct drm_crtc *c)
        atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c));
 }
 
-static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c,
-                                     struct drm_framebuffer *fb,
-                                     struct drm_pending_vblank_event *event,
-                                     uint32_t page_flip_flags)
-{
-       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
-       struct atmel_hlcdc_plane_update_req req;
-       struct drm_plane *plane = c->primary;
-       struct drm_device *dev = c->dev;
-       unsigned long flags;
-       int ret = 0;
-
-       spin_lock_irqsave(&dev->event_lock, flags);
-       if (crtc->event)
-               ret = -EBUSY;
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-
-       if (ret)
-               return ret;
-
-       memset(&req, 0, sizeof(req));
-       req.crtc_x = 0;
-       req.crtc_y = 0;
-       req.crtc_h = c->mode.crtc_vdisplay;
-       req.crtc_w = c->mode.crtc_hdisplay;
-       req.src_x = c->x << 16;
-       req.src_y = c->y << 16;
-       req.src_w = req.crtc_w << 16;
-       req.src_h = req.crtc_h << 16;
-       req.fb = fb;
-
-       ret = atmel_hlcdc_plane_prepare_update_req(plane, &req, &c->hwmode);
-       if (ret)
-               return ret;
-
-       if (event) {
-               drm_vblank_get(c->dev, crtc->id);
-               spin_lock_irqsave(&dev->event_lock, flags);
-               crtc->event = event;
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-       }
-
-       ret = atmel_hlcdc_plane_apply_update_req(plane, &req);
-       if (ret)
-               crtc->event = NULL;
-       else
-               plane->fb = fb;
-
-       return ret;
-}
-
 static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
-       .page_flip = atmel_hlcdc_crtc_page_flip,
-       .set_config = drm_crtc_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
+       .set_config = drm_atomic_helper_set_config,
        .destroy = atmel_hlcdc_crtc_destroy,
+       .reset = drm_atomic_helper_crtc_reset,
+       .atomic_duplicate_state =  drm_atomic_helper_crtc_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 };
 
 int atmel_hlcdc_crtc_create(struct drm_device *dev)
@@ -375,7 +337,6 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
        if (!crtc)
                return -ENOMEM;
 
-       crtc->dpms = DRM_MODE_DPMS_OFF;
        crtc->dc = dc;
 
        ret = drm_crtc_init_with_planes(dev, &crtc->base,
index 7320a6c6613f174c1776f75c6dcc832cf91f1ad8..60b0c13d7ff5cc6f4c338c9ed3d7f423d684c84e 100644 (file)
@@ -222,6 +222,8 @@ static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev)
 static const struct drm_mode_config_funcs mode_config_funcs = {
        .fb_create = atmel_hlcdc_fb_create,
        .output_poll_changed = atmel_hlcdc_fb_output_poll_changed,
+       .atomic_check = drm_atomic_helper_check,
+       .atomic_commit = drm_atomic_helper_commit,
 };
 
 static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
@@ -311,14 +313,14 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
 
        pm_runtime_enable(dev->dev);
 
-       pm_runtime_put_sync(dev->dev);
-
        ret = atmel_hlcdc_dc_modeset_init(dev);
        if (ret < 0) {
                dev_err(dev->dev, "failed to initialize mode setting\n");
                goto err_periph_clk_disable;
        }
 
+       drm_mode_config_reset(dev);
+
        ret = drm_vblank_init(dev, 1);
        if (ret < 0) {
                dev_err(dev->dev, "failed to initialize vblank\n");
@@ -557,6 +559,41 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+       struct drm_crtc *crtc;
+
+       if (pm_runtime_suspended(dev))
+               return 0;
+
+       drm_modeset_lock_all(drm_dev);
+       list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head)
+               atmel_hlcdc_crtc_suspend(crtc);
+       drm_modeset_unlock_all(drm_dev);
+       return 0;
+}
+
+static int atmel_hlcdc_dc_drm_resume(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+       struct drm_crtc *crtc;
+
+       if (pm_runtime_suspended(dev))
+               return 0;
+
+       drm_modeset_lock_all(drm_dev);
+       list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head)
+               atmel_hlcdc_crtc_resume(crtc);
+       drm_modeset_unlock_all(drm_dev);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(atmel_hlcdc_dc_drm_pm_ops,
+               atmel_hlcdc_dc_drm_suspend, atmel_hlcdc_dc_drm_resume);
+
 static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
        { .compatible = "atmel,hlcdc-display-controller" },
        { },
@@ -567,6 +604,7 @@ static struct platform_driver atmel_hlcdc_dc_platform_driver = {
        .remove = atmel_hlcdc_dc_drm_remove,
        .driver = {
                .name   = "atmel-hlcdc-display-controller",
+               .pm     = &atmel_hlcdc_dc_drm_pm_ops,
                .of_match_table = atmel_hlcdc_dc_of_match,
        },
 };
index 7bc96af3397a2d51e2c157d6a5254157fc7bf3a5..cf6b375bc38d1430c892ea2bf69cdf144047efd8 100644 (file)
 #include <linux/irqdomain.h>
 #include <linux/pwm.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_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_panel.h>
+#include <drm/drm_plane_helper.h>
 #include <drm/drmP.h>
 
 #include "atmel_hlcdc_layer.h"
@@ -69,7 +72,6 @@ struct atmel_hlcdc_dc_desc {
  */
 struct atmel_hlcdc_plane_properties {
        struct drm_property *alpha;
-       struct drm_property *rotation;
 };
 
 /**
@@ -84,7 +86,6 @@ struct atmel_hlcdc_plane {
        struct drm_plane base;
        struct atmel_hlcdc_layer layer;
        struct atmel_hlcdc_plane_properties *properties;
-       unsigned int rotation;
 };
 
 static inline struct atmel_hlcdc_plane *
@@ -99,43 +100,6 @@ atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
        return container_of(l, struct atmel_hlcdc_plane, layer);
 }
 
-/**
- * Atmel HLCDC Plane update request structure.
- *
- * @crtc_x: x position of the plane relative to the CRTC
- * @crtc_y: y position of the plane relative to the CRTC
- * @crtc_w: visible width of the plane
- * @crtc_h: visible height of the plane
- * @src_x: x buffer position
- * @src_y: y buffer position
- * @src_w: buffer width
- * @src_h: buffer height
- * @fb: framebuffer object object
- * @bpp: bytes per pixel deduced from pixel_format
- * @offsets: offsets to apply to the GEM buffers
- * @xstride: value to add to the pixel pointer between each line
- * @pstride: value to add to the pixel pointer between each pixel
- * @nplanes: number of planes (deduced from pixel_format)
- */
-struct atmel_hlcdc_plane_update_req {
-       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 drm_framebuffer *fb;
-
-       /* These fields are private and should not be touched */
-       int bpp[ATMEL_HLCDC_MAX_PLANES];
-       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
-       int xstride[ATMEL_HLCDC_MAX_PLANES];
-       int pstride[ATMEL_HLCDC_MAX_PLANES];
-       int nplanes;
-};
-
 /**
  * Atmel HLCDC Planes.
  *
@@ -184,28 +148,16 @@ int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
 struct atmel_hlcdc_planes *
 atmel_hlcdc_create_planes(struct drm_device *dev);
 
-int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
-                               struct atmel_hlcdc_plane_update_req *req,
-                               const struct drm_display_mode *mode);
-
-int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
-                               struct atmel_hlcdc_plane_update_req *req);
-
-int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p,
-                                      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,
-                                      const struct drm_display_mode *mode);
+int atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state);
 
 void atmel_hlcdc_crtc_irq(struct drm_crtc *c);
 
 void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc,
                                       struct drm_file *file);
 
+void atmel_hlcdc_crtc_suspend(struct drm_crtc *crtc);
+void atmel_hlcdc_crtc_resume(struct drm_crtc *crtc);
+
 int atmel_hlcdc_crtc_create(struct drm_device *dev);
 
 int atmel_hlcdc_create_outputs(struct drm_device *dev);
index 063d2a7b941fcaa4f5b527afd41a193fd382d64d..377e43cea9ddd1a489b29db56d70ae873d3f244d 100644 (file)
@@ -298,7 +298,7 @@ void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
        spin_unlock_irqrestore(&layer->lock, flags);
 }
 
-int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
+void atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
 {
        struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
        struct atmel_hlcdc_layer_update *upd = &layer->update;
@@ -311,7 +311,8 @@ int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
 
        /* Disable the layer */
        regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
-                    ATMEL_HLCDC_LAYER_RST);
+                    ATMEL_HLCDC_LAYER_RST | ATMEL_HLCDC_LAYER_A2Q |
+                    ATMEL_HLCDC_LAYER_UPDATE);
 
        /* Clear all pending interrupts */
        regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
@@ -340,8 +341,6 @@ int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
        dma->status = ATMEL_HLCDC_LAYER_DISABLED;
 
        spin_unlock_irqrestore(&layer->lock, flags);
-
-       return 0;
 }
 
 int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer)
index 27e56c0862ec13602a3ee840b30af7ba547c5a8f..9beabc940bce58e9b965533827f4247f230a435d 100644 (file)
 #define ATMEL_HLCDC_LAYER_DISCEN               BIT(11)
 #define ATMEL_HLCDC_LAYER_GA_SHIFT             16
 #define ATMEL_HLCDC_LAYER_GA_MASK              GENMASK(23, ATMEL_HLCDC_LAYER_GA_SHIFT)
+#define ATMEL_HLCDC_LAYER_GA(x)                        ((x) << ATMEL_HLCDC_LAYER_GA_SHIFT)
 
 #define ATMEL_HLCDC_LAYER_CSC_CFG(p, o)                ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o)
 
@@ -376,7 +377,7 @@ int atmel_hlcdc_layer_init(struct drm_device *dev,
 void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
                               struct atmel_hlcdc_layer *layer);
 
-int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
+void atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
 
 int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer);
 
index c402192362c572c03feda8f70ae18d4cee9f2ae6..9c45130053106808c35b8dc9173942c5b5297bfc 100644 (file)
@@ -86,25 +86,22 @@ atmel_hlcdc_rgb_output_to_panel(struct atmel_hlcdc_rgb_output *output)
        return container_of(output, struct atmel_hlcdc_panel, base);
 }
 
-static void atmel_hlcdc_panel_encoder_dpms(struct drm_encoder *encoder,
-                                          int mode)
+static void atmel_hlcdc_panel_encoder_enable(struct drm_encoder *encoder)
 {
        struct atmel_hlcdc_rgb_output *rgb =
                        drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
        struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
 
-       if (mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
-
-       if (mode == rgb->dpms)
-               return;
+       drm_panel_enable(panel->panel);
+}
 
-       if (mode != DRM_MODE_DPMS_ON)
-               drm_panel_disable(panel->panel);
-       else
-               drm_panel_enable(panel->panel);
+static void atmel_hlcdc_panel_encoder_disable(struct drm_encoder *encoder)
+{
+       struct atmel_hlcdc_rgb_output *rgb =
+                       drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
+       struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
 
-       rgb->dpms = mode;
+       drm_panel_disable(panel->panel);
 }
 
 static bool
@@ -115,16 +112,6 @@ atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder,
        return true;
 }
 
-static void atmel_hlcdc_panel_encoder_prepare(struct drm_encoder *encoder)
-{
-       atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-static void atmel_hlcdc_panel_encoder_commit(struct drm_encoder *encoder)
-{
-       atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
-}
-
 static void
 atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder,
                                 struct drm_display_mode *mode,
@@ -156,11 +143,10 @@ atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder,
 }
 
 static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = {
-       .dpms = atmel_hlcdc_panel_encoder_dpms,
        .mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup,
-       .prepare = atmel_hlcdc_panel_encoder_prepare,
-       .commit = atmel_hlcdc_panel_encoder_commit,
        .mode_set = atmel_hlcdc_rgb_encoder_mode_set,
+       .disable = atmel_hlcdc_panel_encoder_disable,
+       .enable = atmel_hlcdc_panel_encoder_enable,
 };
 
 static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder *encoder)
@@ -226,10 +212,13 @@ atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector)
 }
 
 static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .detect = atmel_hlcdc_panel_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = atmel_hlcdc_panel_connector_destroy,
+       .reset = drm_atomic_helper_connector_reset,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static int atmel_hlcdc_create_panel_output(struct drm_device *dev,
index c5892dcfd745cc29dc638e00aa55515d95ed209f..be9fa8220499cf786e27a7ddfb449f2e94b322f2 100644 (file)
 
 #include "atmel_hlcdc_dc.h"
 
+/**
+ * Atmel HLCDC Plane state structure.
+ *
+ * @base: DRM plane state
+ * @crtc_x: x position of the plane relative to the CRTC
+ * @crtc_y: y position of the plane relative to the CRTC
+ * @crtc_w: visible width of the plane
+ * @crtc_h: visible height of the plane
+ * @src_x: x buffer position
+ * @src_y: y buffer position
+ * @src_w: buffer width
+ * @src_h: buffer height
+ * @alpha: alpha blending of the plane
+ * @bpp: bytes per pixel deduced from pixel_format
+ * @offsets: offsets to apply to the GEM buffers
+ * @xstride: value to add to the pixel pointer between each line
+ * @pstride: value to add to the pixel pointer between each pixel
+ * @nplanes: number of planes (deduced from pixel_format)
+ */
+struct atmel_hlcdc_plane_state {
+       struct drm_plane_state base;
+       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;
+
+       u8 alpha;
+
+       bool disc_updated;
+
+       int disc_x;
+       int disc_y;
+       int disc_w;
+       int disc_h;
+
+       /* These fields are private and should not be touched */
+       int bpp[ATMEL_HLCDC_MAX_PLANES];
+       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
+       int xstride[ATMEL_HLCDC_MAX_PLANES];
+       int pstride[ATMEL_HLCDC_MAX_PLANES];
+       int nplanes;
+};
+
+static inline struct atmel_hlcdc_plane_state *
+drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
+{
+       return container_of(s, struct atmel_hlcdc_plane_state, base);
+}
+
 #define SUBPIXEL_MASK                  0xffff
 
 static uint32_t rgb_formats[] = {
@@ -128,7 +181,7 @@ static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
        return 0;
 }
 
-static bool atmel_hlcdc_format_embedds_alpha(u32 format)
+static bool atmel_hlcdc_format_embeds_alpha(u32 format)
 {
        int i;
 
@@ -204,7 +257,7 @@ static u32 heo_upscaling_ycoef[] = {
 
 static void
 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
-                               struct atmel_hlcdc_plane_update_req *req)
+                                     struct atmel_hlcdc_plane_state *state)
 {
        const struct atmel_hlcdc_layer_cfg_layout *layout =
                                                &plane->layer.desc->layout;
@@ -213,69 +266,69 @@ atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
                atmel_hlcdc_layer_update_cfg(&plane->layer,
                                             layout->size,
                                             0xffffffff,
-                                            (req->crtc_w - 1) |
-                                            ((req->crtc_h - 1) << 16));
+                                            (state->crtc_w - 1) |
+                                            ((state->crtc_h - 1) << 16));
 
        if (layout->memsize)
                atmel_hlcdc_layer_update_cfg(&plane->layer,
                                             layout->memsize,
                                             0xffffffff,
-                                            (req->src_w - 1) |
-                                            ((req->src_h - 1) << 16));
+                                            (state->src_w - 1) |
+                                            ((state->src_h - 1) << 16));
 
        if (layout->pos)
                atmel_hlcdc_layer_update_cfg(&plane->layer,
                                             layout->pos,
                                             0xffffffff,
-                                            req->crtc_x |
-                                            (req->crtc_y  << 16));
+                                            state->crtc_x |
+                                            (state->crtc_y  << 16));
 
        /* TODO: rework the rescaling part */
-       if (req->crtc_w != req->src_w || req->crtc_h != req->src_h) {
+       if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
                u32 factor_reg = 0;
 
-               if (req->crtc_w != req->src_w) {
+               if (state->crtc_w != state->src_w) {
                        int i;
                        u32 factor;
                        u32 *coeff_tab = heo_upscaling_xcoef;
                        u32 max_memsize;
 
-                       if (req->crtc_w < req->src_w)
+                       if (state->crtc_w < state->src_w)
                                coeff_tab = heo_downscaling_xcoef;
                        for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
                                atmel_hlcdc_layer_update_cfg(&plane->layer,
                                                             17 + i,
                                                             0xffffffff,
                                                             coeff_tab[i]);
-                       factor = ((8 * 256 * req->src_w) - (256 * 4)) /
-                                req->crtc_w;
+                       factor = ((8 * 256 * state->src_w) - (256 * 4)) /
+                                state->crtc_w;
                        factor++;
-                       max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
+                       max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
                                      2048;
-                       if (max_memsize > req->src_w)
+                       if (max_memsize > state->src_w)
                                factor--;
                        factor_reg |= factor | 0x80000000;
                }
 
-               if (req->crtc_h != req->src_h) {
+               if (state->crtc_h != state->src_h) {
                        int i;
                        u32 factor;
                        u32 *coeff_tab = heo_upscaling_ycoef;
                        u32 max_memsize;
 
-                       if (req->crtc_w < req->src_w)
+                       if (state->crtc_w < state->src_w)
                                coeff_tab = heo_downscaling_ycoef;
                        for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
                                atmel_hlcdc_layer_update_cfg(&plane->layer,
                                                             33 + i,
                                                             0xffffffff,
                                                             coeff_tab[i]);
-                       factor = ((8 * 256 * req->src_w) - (256 * 4)) /
-                                req->crtc_w;
+                       factor = ((8 * 256 * state->src_w) - (256 * 4)) /
+                                state->crtc_w;
                        factor++;
-                       max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
+                       max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
                                      2048;
-                       if (max_memsize > req->src_w)
+                       if (max_memsize > state->src_w)
                                factor--;
                        factor_reg |= (factor << 16) | 0x80000000;
                }
@@ -287,7 +340,7 @@ atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
 
 static void
 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
-                               struct atmel_hlcdc_plane_update_req *req)
+                                       struct atmel_hlcdc_plane_state *state)
 {
        const struct atmel_hlcdc_layer_cfg_layout *layout =
                                                &plane->layer.desc->layout;
@@ -297,10 +350,11 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
                cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
                       ATMEL_HLCDC_LAYER_ITER;
 
-               if (atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format))
+               if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
                        cfg |= ATMEL_HLCDC_LAYER_LAEN;
                else
-                       cfg |= ATMEL_HLCDC_LAYER_GAEN;
+                       cfg |= ATMEL_HLCDC_LAYER_GAEN |
+                              ATMEL_HLCDC_LAYER_GA(state->alpha);
        }
 
        atmel_hlcdc_layer_update_cfg(&plane->layer,
@@ -312,24 +366,26 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
                                     ATMEL_HLCDC_LAYER_ITER2BL |
                                     ATMEL_HLCDC_LAYER_ITER |
                                     ATMEL_HLCDC_LAYER_GAEN |
+                                    ATMEL_HLCDC_LAYER_GA_MASK |
                                     ATMEL_HLCDC_LAYER_LAEN |
                                     ATMEL_HLCDC_LAYER_OVR |
                                     ATMEL_HLCDC_LAYER_DMA, cfg);
 }
 
 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
-                               struct atmel_hlcdc_plane_update_req *req)
+                                       struct atmel_hlcdc_plane_state *state)
 {
        u32 cfg;
        int ret;
 
-       ret = atmel_hlcdc_format_to_plane_mode(req->fb->pixel_format, &cfg);
+       ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
+                                              &cfg);
        if (ret)
                return;
 
-       if ((req->fb->pixel_format == DRM_FORMAT_YUV422 ||
-            req->fb->pixel_format == DRM_FORMAT_NV61) &&
-           (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
+       if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
+            state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
+           (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
                cfg |= ATMEL_HLCDC_YUV422ROT;
 
        atmel_hlcdc_layer_update_cfg(&plane->layer,
@@ -341,7 +397,7 @@ static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
         * Rotation optimization is not working on RGB888 (rotation is still
         * working but without any optimization).
         */
-       if (req->fb->pixel_format == DRM_FORMAT_RGB888)
+       if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
                cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
        else
                cfg = 0;
@@ -352,73 +408,142 @@ static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
 }
 
 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
-                               struct atmel_hlcdc_plane_update_req *req)
+                                       struct atmel_hlcdc_plane_state *state)
 {
        struct atmel_hlcdc_layer *layer = &plane->layer;
        const struct atmel_hlcdc_layer_cfg_layout *layout =
                                                        &layer->desc->layout;
        int i;
 
-       atmel_hlcdc_layer_update_set_fb(&plane->layer, req->fb, req->offsets);
+       atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
+                                       state->offsets);
 
-       for (i = 0; i < req->nplanes; i++) {
+       for (i = 0; i < state->nplanes; i++) {
                if (layout->xstride[i]) {
                        atmel_hlcdc_layer_update_cfg(&plane->layer,
                                                layout->xstride[i],
                                                0xffffffff,
-                                               req->xstride[i]);
+                                               state->xstride[i]);
                }
 
                if (layout->pstride[i]) {
                        atmel_hlcdc_layer_update_cfg(&plane->layer,
                                                layout->pstride[i],
                                                0xffffffff,
-                                               req->pstride[i]);
+                                               state->pstride[i]);
                }
        }
 }
 
-static int atmel_hlcdc_plane_check_update_req(struct drm_plane *p,
-                               struct atmel_hlcdc_plane_update_req *req,
-                               const struct drm_display_mode *mode)
+int
+atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
 {
-       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
-       const struct atmel_hlcdc_layer_cfg_layout *layout =
-                                               &plane->layer.desc->layout;
+       int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
+       const struct atmel_hlcdc_layer_cfg_layout *layout;
+       struct atmel_hlcdc_plane_state *primary_state;
+       struct drm_plane_state *primary_s;
+       struct atmel_hlcdc_plane *primary;
+       struct drm_plane *ovl;
+
+       primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
+       layout = &primary->layer.desc->layout;
+       if (!layout->disc_pos || !layout->disc_size)
+               return 0;
+
+       primary_s = drm_atomic_get_plane_state(c_state->state,
+                                              &primary->base);
+       if (IS_ERR(primary_s))
+               return PTR_ERR(primary_s);
+
+       primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
+
+       drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
+               struct atmel_hlcdc_plane_state *ovl_state;
+               struct drm_plane_state *ovl_s;
+
+               if (ovl == c_state->crtc->primary)
+                       continue;
 
-       if (!layout->size &&
-           (mode->hdisplay != req->crtc_w ||
-            mode->vdisplay != req->crtc_h))
-               return -EINVAL;
+               ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
+               if (IS_ERR(ovl_s))
+                       return PTR_ERR(ovl_s);
 
-       if (plane->layer.desc->max_height &&
-           req->crtc_h > plane->layer.desc->max_height)
-               return -EINVAL;
+               ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
 
-       if (plane->layer.desc->max_width &&
-           req->crtc_w > plane->layer.desc->max_width)
-               return -EINVAL;
+               if (!ovl_s->fb ||
+                   atmel_hlcdc_format_embeds_alpha(ovl_s->fb->pixel_format) ||
+                   ovl_state->alpha != 255)
+                       continue;
 
-       if ((req->crtc_h != req->src_h || req->crtc_w != req->src_w) &&
-           (!layout->memsize ||
-            atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format)))
-               return -EINVAL;
+               /* TODO: implement a smarter hidden area detection */
+               if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
+                       continue;
 
-       if (req->crtc_x < 0 || req->crtc_y < 0)
-               return -EINVAL;
+               disc_x = ovl_state->crtc_x;
+               disc_y = ovl_state->crtc_y;
+               disc_h = ovl_state->crtc_h;
+               disc_w = ovl_state->crtc_w;
+       }
 
-       if (req->crtc_w + req->crtc_x > mode->hdisplay ||
-           req->crtc_h + req->crtc_y > mode->vdisplay)
-               return -EINVAL;
+       if (disc_x == primary_state->disc_x &&
+           disc_y == primary_state->disc_y &&
+           disc_w == primary_state->disc_w &&
+           disc_h == primary_state->disc_h)
+               return 0;
+
+
+       primary_state->disc_x = disc_x;
+       primary_state->disc_y = disc_y;
+       primary_state->disc_w = disc_w;
+       primary_state->disc_h = disc_h;
+       primary_state->disc_updated = true;
 
        return 0;
 }
 
-int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
-                               struct atmel_hlcdc_plane_update_req *req,
-                               const struct drm_display_mode *mode)
+static void
+atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
+                                  struct atmel_hlcdc_plane_state *state)
+{
+       const struct atmel_hlcdc_layer_cfg_layout *layout =
+                                               &plane->layer.desc->layout;
+       int disc_surface = 0;
+
+       if (!state->disc_updated)
+               return;
+
+       disc_surface = state->disc_h * state->disc_w;
+
+       atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
+                               ATMEL_HLCDC_LAYER_DISCEN,
+                               disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
+
+       if (!disc_surface)
+               return;
+
+       atmel_hlcdc_layer_update_cfg(&plane->layer,
+                                    layout->disc_pos,
+                                    0xffffffff,
+                                    state->disc_x | (state->disc_y << 16));
+
+       atmel_hlcdc_layer_update_cfg(&plane->layer,
+                                    layout->disc_size,
+                                    0xffffffff,
+                                    (state->disc_w - 1) |
+                                    ((state->disc_h - 1) << 16));
+}
+
+static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
+                                         struct drm_plane_state *s)
 {
        struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+       struct atmel_hlcdc_plane_state *state =
+                               drm_plane_state_to_atmel_hlcdc_plane_state(s);
+       const struct atmel_hlcdc_layer_cfg_layout *layout =
+                                               &plane->layer.desc->layout;
+       struct drm_framebuffer *fb = state->base.fb;
+       const struct drm_display_mode *mode;
+       struct drm_crtc_state *crtc_state;
        unsigned int patched_crtc_w;
        unsigned int patched_crtc_h;
        unsigned int patched_src_w;
@@ -430,196 +555,196 @@ int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
        int vsub = 1;
        int i;
 
-       if ((req->src_x | req->src_y | req->src_w | req->src_h) &
+       if (!state->base.crtc || !fb)
+               return 0;
+
+       crtc_state = s->state->crtc_states[drm_crtc_index(s->crtc)];
+       mode = &crtc_state->adjusted_mode;
+
+       state->src_x = s->src_x;
+       state->src_y = s->src_y;
+       state->src_h = s->src_h;
+       state->src_w = s->src_w;
+       state->crtc_x = s->crtc_x;
+       state->crtc_y = s->crtc_y;
+       state->crtc_h = s->crtc_h;
+       state->crtc_w = s->crtc_w;
+       if ((state->src_x | state->src_y | state->src_w | state->src_h) &
            SUBPIXEL_MASK)
                return -EINVAL;
 
-       req->src_x >>= 16;
-       req->src_y >>= 16;
-       req->src_w >>= 16;
-       req->src_h >>= 16;
+       state->src_x >>= 16;
+       state->src_y >>= 16;
+       state->src_w >>= 16;
+       state->src_h >>= 16;
 
-       req->nplanes = drm_format_num_planes(req->fb->pixel_format);
-       if (req->nplanes > ATMEL_HLCDC_MAX_PLANES)
+       state->nplanes = drm_format_num_planes(fb->pixel_format);
+       if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
                return -EINVAL;
 
        /*
         * Swap width and size in case of 90 or 270 degrees rotation
         */
-       if (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
-               tmp = req->crtc_w;
-               req->crtc_w = req->crtc_h;
-               req->crtc_h = tmp;
-               tmp = req->src_w;
-               req->src_w = req->src_h;
-               req->src_h = tmp;
+       if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
+               tmp = state->crtc_w;
+               state->crtc_w = state->crtc_h;
+               state->crtc_h = tmp;
+               tmp = state->src_w;
+               state->src_w = state->src_h;
+               state->src_h = tmp;
        }
 
-       if (req->crtc_x + req->crtc_w > mode->hdisplay)
-               patched_crtc_w = mode->hdisplay - req->crtc_x;
+       if (state->crtc_x + state->crtc_w > mode->hdisplay)
+               patched_crtc_w = mode->hdisplay - state->crtc_x;
        else
-               patched_crtc_w = req->crtc_w;
+               patched_crtc_w = state->crtc_w;
 
-       if (req->crtc_x < 0) {
-               patched_crtc_w += req->crtc_x;
-               x_offset = -req->crtc_x;
-               req->crtc_x = 0;
+       if (state->crtc_x < 0) {
+               patched_crtc_w += state->crtc_x;
+               x_offset = -state->crtc_x;
+               state->crtc_x = 0;
        }
 
-       if (req->crtc_y + req->crtc_h > mode->vdisplay)
-               patched_crtc_h = mode->vdisplay - req->crtc_y;
+       if (state->crtc_y + state->crtc_h > mode->vdisplay)
+               patched_crtc_h = mode->vdisplay - state->crtc_y;
        else
-               patched_crtc_h = req->crtc_h;
+               patched_crtc_h = state->crtc_h;
 
-       if (req->crtc_y < 0) {
-               patched_crtc_h += req->crtc_y;
-               y_offset = -req->crtc_y;
-               req->crtc_y = 0;
+       if (state->crtc_y < 0) {
+               patched_crtc_h += state->crtc_y;
+               y_offset = -state->crtc_y;
+               state->crtc_y = 0;
        }
 
-       patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * req->src_w,
-                                         req->crtc_w);
-       patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * req->src_h,
-                                         req->crtc_h);
+       patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
+                                         state->crtc_w);
+       patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
+                                         state->crtc_h);
 
-       hsub = drm_format_horz_chroma_subsampling(req->fb->pixel_format);
-       vsub = drm_format_vert_chroma_subsampling(req->fb->pixel_format);
+       hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
+       vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
 
-       for (i = 0; i < req->nplanes; i++) {
+       for (i = 0; i < state->nplanes; i++) {
                unsigned int offset = 0;
                int xdiv = i ? hsub : 1;
                int ydiv = i ? vsub : 1;
 
-               req->bpp[i] = drm_format_plane_cpp(req->fb->pixel_format, i);
-               if (!req->bpp[i])
+               state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
+               if (!state->bpp[i])
                        return -EINVAL;
 
-               switch (plane->rotation & 0xf) {
+               switch (state->base.rotation & 0xf) {
                case BIT(DRM_ROTATE_90):
-                       offset = ((y_offset + req->src_y + patched_src_w - 1) /
-                                 ydiv) * req->fb->pitches[i];
-                       offset += ((x_offset + req->src_x) / xdiv) *
-                                 req->bpp[i];
-                       req->xstride[i] = ((patched_src_w - 1) / ydiv) *
-                                         req->fb->pitches[i];
-                       req->pstride[i] = -req->fb->pitches[i] - req->bpp[i];
+                       offset = ((y_offset + state->src_y + patched_src_w - 1) /
+                                 ydiv) * fb->pitches[i];
+                       offset += ((x_offset + state->src_x) / xdiv) *
+                                 state->bpp[i];
+                       state->xstride[i] = ((patched_src_w - 1) / ydiv) *
+                                         fb->pitches[i];
+                       state->pstride[i] = -fb->pitches[i] - state->bpp[i];
                        break;
                case BIT(DRM_ROTATE_180):
-                       offset = ((y_offset + req->src_y + patched_src_h - 1) /
-                                 ydiv) * req->fb->pitches[i];
-                       offset += ((x_offset + req->src_x + patched_src_w - 1) /
-                                  xdiv) * req->bpp[i];
-                       req->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
-                                          req->bpp[i]) - req->fb->pitches[i];
-                       req->pstride[i] = -2 * req->bpp[i];
+                       offset = ((y_offset + state->src_y + patched_src_h - 1) /
+                                 ydiv) * fb->pitches[i];
+                       offset += ((x_offset + state->src_x + patched_src_w - 1) /
+                                  xdiv) * state->bpp[i];
+                       state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
+                                          state->bpp[i]) - fb->pitches[i];
+                       state->pstride[i] = -2 * state->bpp[i];
                        break;
                case BIT(DRM_ROTATE_270):
-                       offset = ((y_offset + req->src_y) / ydiv) *
-                                req->fb->pitches[i];
-                       offset += ((x_offset + req->src_x + patched_src_h - 1) /
-                                  xdiv) * req->bpp[i];
-                       req->xstride[i] = -(((patched_src_w - 1) / ydiv) *
-                                           req->fb->pitches[i]) -
-                                         (2 * req->bpp[i]);
-                       req->pstride[i] = req->fb->pitches[i] - req->bpp[i];
+                       offset = ((y_offset + state->src_y) / ydiv) *
+                                fb->pitches[i];
+                       offset += ((x_offset + state->src_x + patched_src_h - 1) /
+                                  xdiv) * state->bpp[i];
+                       state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
+                                           fb->pitches[i]) -
+                                         (2 * state->bpp[i]);
+                       state->pstride[i] = fb->pitches[i] - state->bpp[i];
                        break;
                case BIT(DRM_ROTATE_0):
                default:
-                       offset = ((y_offset + req->src_y) / ydiv) *
-                                req->fb->pitches[i];
-                       offset += ((x_offset + req->src_x) / xdiv) *
-                                 req->bpp[i];
-                       req->xstride[i] = req->fb->pitches[i] -
+                       offset = ((y_offset + state->src_y) / ydiv) *
+                                fb->pitches[i];
+                       offset += ((x_offset + state->src_x) / xdiv) *
+                                 state->bpp[i];
+                       state->xstride[i] = fb->pitches[i] -
                                          ((patched_src_w / xdiv) *
-                                          req->bpp[i]);
-                       req->pstride[i] = 0;
+                                          state->bpp[i]);
+                       state->pstride[i] = 0;
                        break;
                }
 
-               req->offsets[i] = offset + req->fb->offsets[i];
+               state->offsets[i] = offset + fb->offsets[i];
        }
 
-       req->src_w = patched_src_w;
-       req->src_h = patched_src_h;
-       req->crtc_w = patched_crtc_w;
-       req->crtc_h = patched_crtc_h;
+       state->src_w = patched_src_w;
+       state->src_h = patched_src_h;
+       state->crtc_w = patched_crtc_w;
+       state->crtc_h = patched_crtc_h;
 
-       return atmel_hlcdc_plane_check_update_req(p, req, mode);
-}
+       if (!layout->size &&
+           (mode->hdisplay != state->crtc_w ||
+            mode->vdisplay != state->crtc_h))
+               return -EINVAL;
 
-int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
-                               struct atmel_hlcdc_plane_update_req *req)
-{
-       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
-       int ret;
+       if (plane->layer.desc->max_height &&
+           state->crtc_h > plane->layer.desc->max_height)
+               return -EINVAL;
 
-       ret = atmel_hlcdc_layer_update_start(&plane->layer);
-       if (ret)
-               return ret;
+       if (plane->layer.desc->max_width &&
+           state->crtc_w > plane->layer.desc->max_width)
+               return -EINVAL;
 
-       atmel_hlcdc_plane_update_pos_and_size(plane, req);
-       atmel_hlcdc_plane_update_general_settings(plane, req);
-       atmel_hlcdc_plane_update_format(plane, req);
-       atmel_hlcdc_plane_update_buffers(plane, req);
+       if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
+           (!layout->memsize ||
+            atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
+               return -EINVAL;
 
-       atmel_hlcdc_layer_update_commit(&plane->layer);
+       if (state->crtc_x < 0 || state->crtc_y < 0)
+               return -EINVAL;
+
+       if (state->crtc_w + state->crtc_x > mode->hdisplay ||
+           state->crtc_h + state->crtc_y > mode->vdisplay)
+               return -EINVAL;
 
        return 0;
 }
 
-int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p,
-                                      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,
-                                      const struct drm_display_mode *mode)
+static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
+                                       struct drm_framebuffer *fb,
+                                       const struct drm_plane_state *new_state)
 {
        struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
-       struct atmel_hlcdc_plane_update_req req;
-       int ret = 0;
-
-       memset(&req, 0, sizeof(req));
-       req.crtc_x = crtc_x;
-       req.crtc_y = crtc_y;
-       req.crtc_w = crtc_w;
-       req.crtc_h = crtc_h;
-       req.src_x = src_x;
-       req.src_y = src_y;
-       req.src_w = src_w;
-       req.src_h = src_h;
-       req.fb = fb;
-
-       ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req, mode);
-       if (ret)
-               return ret;
 
-       if (!req.crtc_h || !req.crtc_w)
-               return atmel_hlcdc_layer_disable(&plane->layer);
-
-       return atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
+       return atmel_hlcdc_layer_update_start(&plane->layer);
 }
 
-static int atmel_hlcdc_plane_update(struct drm_plane *p,
-                                   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)
+static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
+                                           struct drm_plane_state *old_s)
 {
-       return atmel_hlcdc_plane_update_with_mode(p, crtc, fb, crtc_x, crtc_y,
-                                                 crtc_w, crtc_h, src_x, src_y,
-                                                 src_w, src_h, &crtc->hwmode);
+       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+       struct atmel_hlcdc_plane_state *state =
+                       drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
+
+       if (!p->state->crtc || !p->state->fb)
+               return;
+
+       atmel_hlcdc_plane_update_pos_and_size(plane, state);
+       atmel_hlcdc_plane_update_general_settings(plane, state);
+       atmel_hlcdc_plane_update_format(plane, state);
+       atmel_hlcdc_plane_update_buffers(plane, state);
+       atmel_hlcdc_plane_update_disc_area(plane, state);
+
+       atmel_hlcdc_layer_update_commit(&plane->layer);
 }
 
-static int atmel_hlcdc_plane_disable(struct drm_plane *p)
+static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
+                                            struct drm_plane_state *old_state)
 {
        struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
 
-       return atmel_hlcdc_layer_disable(&plane->layer);
+       atmel_hlcdc_layer_disable(&plane->layer);
 }
 
 static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
@@ -635,38 +760,36 @@ static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
        devm_kfree(p->dev->dev, plane);
 }
 
-static int atmel_hlcdc_plane_set_alpha(struct atmel_hlcdc_plane *plane,
-                                      u8 alpha)
+static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
+                                                struct drm_plane_state *s,
+                                                struct drm_property *property,
+                                                uint64_t val)
 {
-       atmel_hlcdc_layer_update_start(&plane->layer);
-       atmel_hlcdc_layer_update_cfg(&plane->layer,
-                                    plane->layer.desc->layout.general_config,
-                                    ATMEL_HLCDC_LAYER_GA_MASK,
-                                    alpha << ATMEL_HLCDC_LAYER_GA_SHIFT);
-       atmel_hlcdc_layer_update_commit(&plane->layer);
-
-       return 0;
-}
+       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+       struct atmel_hlcdc_plane_properties *props = plane->properties;
+       struct atmel_hlcdc_plane_state *state =
+                       drm_plane_state_to_atmel_hlcdc_plane_state(s);
 
-static int atmel_hlcdc_plane_set_rotation(struct atmel_hlcdc_plane *plane,
-                                         unsigned int rotation)
-{
-       plane->rotation = rotation;
+       if (property == props->alpha)
+               state->alpha = val;
+       else
+               return -EINVAL;
 
        return 0;
 }
 
-static int atmel_hlcdc_plane_set_property(struct drm_plane *p,
-                                         struct drm_property *property,
-                                         uint64_t value)
+static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
+                                       const struct drm_plane_state *s,
+                                       struct drm_property *property,
+                                       uint64_t *val)
 {
        struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
        struct atmel_hlcdc_plane_properties *props = plane->properties;
+       const struct atmel_hlcdc_plane_state *state =
+               container_of(s, const struct atmel_hlcdc_plane_state, base);
 
        if (property == props->alpha)
-               atmel_hlcdc_plane_set_alpha(plane, value);
-       else if (property == props->rotation)
-               atmel_hlcdc_plane_set_rotation(plane, value);
+               *val = state->alpha;
        else
                return -EINVAL;
 
@@ -694,8 +817,8 @@ static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
 
        if (desc->layout.xstride && desc->layout.pstride)
                drm_object_attach_property(&plane->base.base,
-                                          props->rotation,
-                                          BIT(DRM_ROTATE_0));
+                               plane->base.dev->mode_config.rotation_property,
+                               BIT(DRM_ROTATE_0));
 
        if (desc->layout.csc) {
                /*
@@ -717,11 +840,76 @@ static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
        }
 }
 
+static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
+       .prepare_fb = atmel_hlcdc_plane_prepare_fb,
+       .atomic_check = atmel_hlcdc_plane_atomic_check,
+       .atomic_update = atmel_hlcdc_plane_atomic_update,
+       .atomic_disable = atmel_hlcdc_plane_atomic_disable,
+};
+
+static void atmel_hlcdc_plane_reset(struct drm_plane *p)
+{
+       struct atmel_hlcdc_plane_state *state;
+
+       if (p->state) {
+               state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
+
+               if (state->base.fb)
+                       drm_framebuffer_unreference(state->base.fb);
+
+               kfree(state);
+               p->state = NULL;
+       }
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (state) {
+               state->alpha = 255;
+               p->state = &state->base;
+               p->state->plane = p;
+       }
+}
+
+static struct drm_plane_state *
+atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
+{
+       struct atmel_hlcdc_plane_state *state =
+                       drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
+       struct atmel_hlcdc_plane_state *copy;
+
+       copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+       if (!copy)
+               return NULL;
+
+       copy->disc_updated = false;
+
+       if (copy->base.fb)
+               drm_framebuffer_reference(copy->base.fb);
+
+       return &copy->base;
+}
+
+static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
+                                                  struct drm_plane_state *s)
+{
+       struct atmel_hlcdc_plane_state *state =
+                       drm_plane_state_to_atmel_hlcdc_plane_state(s);
+
+       if (s->fb)
+               drm_framebuffer_unreference(s->fb);
+
+       kfree(state);
+}
+
 static struct drm_plane_funcs layer_plane_funcs = {
-       .update_plane = atmel_hlcdc_plane_update,
-       .disable_plane = atmel_hlcdc_plane_disable,
-       .set_property = atmel_hlcdc_plane_set_property,
+       .update_plane = drm_atomic_helper_update_plane,
+       .disable_plane = drm_atomic_helper_disable_plane,
+       .set_property = drm_atomic_helper_plane_set_property,
        .destroy = atmel_hlcdc_plane_destroy,
+       .reset = atmel_hlcdc_plane_reset,
+       .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
+       .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
+       .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
+       .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
 };
 
 static struct atmel_hlcdc_plane *
@@ -755,6 +943,9 @@ atmel_hlcdc_plane_create(struct drm_device *dev,
        if (ret)
                return ERR_PTR(ret);
 
+       drm_plane_helper_add(&plane->base,
+                            &atmel_hlcdc_layer_plane_helper_funcs);
+
        /* Set default property values*/
        atmel_hlcdc_plane_init_properties(plane, desc, props);
 
@@ -774,12 +965,13 @@ atmel_hlcdc_plane_create_properties(struct drm_device *dev)
        if (!props->alpha)
                return ERR_PTR(-ENOMEM);
 
-       props->rotation = drm_mode_create_rotation_property(dev,
-                                               BIT(DRM_ROTATE_0) |
-                                               BIT(DRM_ROTATE_90) |
-                                               BIT(DRM_ROTATE_180) |
-                                               BIT(DRM_ROTATE_270));
-       if (!props->rotation)
+       dev->mode_config.rotation_property =
+                       drm_mode_create_rotation_property(dev,
+                                                         BIT(DRM_ROTATE_0) |
+                                                         BIT(DRM_ROTATE_90) |
+                                                         BIT(DRM_ROTATE_180) |
+                                                         BIT(DRM_ROTATE_270));
+       if (!dev->mode_config.rotation_property)
                return ERR_PTR(-ENOMEM);
 
        return props;
index 460389702d31cdca34a56b9e20c93f6ad4ad6f05..a39b0343c197dc8a6aea00aa244b80dae1fde232 100644 (file)
@@ -164,6 +164,7 @@ void bochs_hw_setmode(struct bochs_device *bochs,
 
        bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
 
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,      0);
        bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP,         bochs->bpp);
        bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES,        bochs->xres);
        bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES,        bochs->yres);
index c2e9c5283136bc62f9b4baf18f46d204c41bc6d9..57efdbeff008cbe2f6eaff509c81c887f4391b09 100644 (file)
@@ -92,7 +92,7 @@ drm_atomic_state_alloc(struct drm_device *dev)
 
        state->dev = dev;
 
-       DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
+       DRM_DEBUG_ATOMIC("Allocate atomic state %p\n", state);
 
        return state;
 fail:
@@ -122,7 +122,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
        struct drm_mode_config *config = &dev->mode_config;
        int i;
 
-       DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
+       DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state);
 
        for (i = 0; i < state->num_connector; i++) {
                struct drm_connector *connector = state->connectors[i];
@@ -134,6 +134,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                connector->funcs->atomic_destroy_state(connector,
                                                       state->connector_states[i]);
+               state->connectors[i] = NULL;
                state->connector_states[i] = NULL;
        }
 
@@ -145,6 +146,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                crtc->funcs->atomic_destroy_state(crtc,
                                                  state->crtc_states[i]);
+               state->crtcs[i] = NULL;
                state->crtc_states[i] = NULL;
        }
 
@@ -156,6 +158,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                plane->funcs->atomic_destroy_state(plane,
                                                   state->plane_states[i]);
+               state->planes[i] = NULL;
                state->plane_states[i] = NULL;
        }
 }
@@ -170,9 +173,12 @@ EXPORT_SYMBOL(drm_atomic_state_clear);
  */
 void drm_atomic_state_free(struct drm_atomic_state *state)
 {
+       if (!state)
+               return;
+
        drm_atomic_state_clear(state);
 
-       DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
+       DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state);
 
        kfree_state(state);
 }
@@ -217,8 +223,8 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
        state->crtcs[index] = crtc;
        crtc_state->state = state;
 
-       DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
-                     crtc->base.id, crtc_state, state);
+       DRM_DEBUG_ATOMIC("Added [CRTC:%d] %p state to %p\n",
+                        crtc->base.id, crtc_state, state);
 
        return crtc_state;
 }
@@ -248,11 +254,14 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
        struct drm_mode_config *config = &dev->mode_config;
 
        /* FIXME: Mode prop is missing, which also controls ->enable. */
-       if (property == config->prop_active) {
+       if (property == config->prop_active)
                state->active = val;
-       else if (crtc->funcs->atomic_set_property)
+       else if (crtc->funcs->atomic_set_property)
                return crtc->funcs->atomic_set_property(crtc, state, property, val);
-       return -EINVAL;
+       else
+               return -EINVAL;
+
+       return 0;
 }
 EXPORT_SYMBOL(drm_atomic_crtc_set_property);
 
@@ -266,9 +275,17 @@ int drm_atomic_crtc_get_property(struct drm_crtc *crtc,
                const struct drm_crtc_state *state,
                struct drm_property *property, uint64_t *val)
 {
-       if (crtc->funcs->atomic_get_property)
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *config = &dev->mode_config;
+
+       if (property == config->prop_active)
+               *val = state->active;
+       else if (crtc->funcs->atomic_get_property)
                return crtc->funcs->atomic_get_property(crtc, state, property, val);
-       return -EINVAL;
+       else
+               return -EINVAL;
+
+       return 0;
 }
 
 /**
@@ -293,8 +310,8 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
         */
 
        if (state->active && !state->enable) {
-               DRM_DEBUG_KMS("[CRTC:%d] active without enabled\n",
-                             crtc->base.id);
+               DRM_DEBUG_ATOMIC("[CRTC:%d] active without enabled\n",
+                                crtc->base.id);
                return -EINVAL;
        }
 
@@ -340,8 +357,8 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
        state->planes[index] = plane;
        plane_state->state = state;
 
-       DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
-                     plane->base.id, plane_state, state);
+       DRM_DEBUG_ATOMIC("Added [PLANE:%d] %p state to %p\n",
+                        plane->base.id, plane_state, state);
 
        if (plane_state->crtc) {
                struct drm_crtc_state *crtc_state;
@@ -450,6 +467,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
                *val = state->src_w;
        } else if (property == config->prop_src_h) {
                *val = state->src_h;
+       } else if (property == config->rotation_property) {
+               *val = state->rotation;
        } else if (plane->funcs->atomic_get_property) {
                return plane->funcs->atomic_get_property(plane, state, property, val);
        } else {
@@ -473,14 +492,14 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
                struct drm_plane_state *state)
 {
        unsigned int fb_width, fb_height;
-       unsigned int i;
+       int ret;
 
        /* either *both* CRTC and FB must be set, or neither */
        if (WARN_ON(state->crtc && !state->fb)) {
-               DRM_DEBUG_KMS("CRTC set but no FB\n");
+               DRM_DEBUG_ATOMIC("CRTC set but no FB\n");
                return -EINVAL;
        } else if (WARN_ON(state->fb && !state->crtc)) {
-               DRM_DEBUG_KMS("FB set but no CRTC\n");
+               DRM_DEBUG_ATOMIC("FB set but no CRTC\n");
                return -EINVAL;
        }
 
@@ -490,18 +509,16 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
 
        /* Check whether this plane is usable on this CRTC */
        if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) {
-               DRM_DEBUG_KMS("Invalid crtc for plane\n");
+               DRM_DEBUG_ATOMIC("Invalid crtc for plane\n");
                return -EINVAL;
        }
 
        /* Check whether this plane supports the fb pixel format. */
-       for (i = 0; i < plane->format_count; i++)
-               if (state->fb->pixel_format == plane->format_types[i])
-                       break;
-       if (i == plane->format_count) {
-               DRM_DEBUG_KMS("Invalid pixel format %s\n",
-                             drm_get_format_name(state->fb->pixel_format));
-               return -EINVAL;
+       ret = drm_plane_check_pixel_format(plane, state->fb->pixel_format);
+       if (ret) {
+               DRM_DEBUG_ATOMIC("Invalid pixel format %s\n",
+                                drm_get_format_name(state->fb->pixel_format));
+               return ret;
        }
 
        /* Give drivers some help against integer overflows */
@@ -509,9 +526,9 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
            state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
            state->crtc_h > INT_MAX ||
            state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
-               DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
-                             state->crtc_w, state->crtc_h,
-                             state->crtc_x, state->crtc_y);
+               DRM_DEBUG_ATOMIC("Invalid CRTC coordinates %ux%u+%d+%d\n",
+                                state->crtc_w, state->crtc_h,
+                                state->crtc_x, state->crtc_y);
                return -ERANGE;
        }
 
@@ -523,12 +540,12 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
            state->src_x > fb_width - state->src_w ||
            state->src_h > fb_height ||
            state->src_y > fb_height - state->src_h) {
-               DRM_DEBUG_KMS("Invalid source coordinates "
-                             "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
-                             state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
-                             state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10,
-                             state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10,
-                             state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10);
+               DRM_DEBUG_ATOMIC("Invalid source coordinates "
+                                "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
+                                state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
+                                state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10,
+                                state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10,
+                                state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10);
                return -ENOSPC;
        }
 
@@ -575,7 +592,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
         * at most the array is a bit too large.
         */
        if (index >= state->num_connector) {
-               DRM_DEBUG_KMS("Hot-added connector would overflow state array, restarting\n");
+               DRM_DEBUG_ATOMIC("Hot-added connector would overflow state array, restarting\n");
                return ERR_PTR(-EAGAIN);
        }
 
@@ -590,8 +607,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
        state->connectors[index] = connector;
        connector_state->state = state;
 
-       DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
-                     connector->base.id, connector_state, state);
+       DRM_DEBUG_ATOMIC("Added [CONNECTOR:%d] %p state to %p\n",
+                        connector->base.id, connector_state, state);
 
        if (connector_state->crtc) {
                struct drm_crtc_state *crtc_state;
@@ -752,10 +769,11 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
        }
 
        if (crtc)
-               DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
-                             plane_state, crtc->base.id);
+               DRM_DEBUG_ATOMIC("Link plane state %p to [CRTC:%d]\n",
+                                plane_state, crtc->base.id);
        else
-               DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state);
+               DRM_DEBUG_ATOMIC("Link plane state %p to [NOCRTC]\n",
+                                plane_state);
 
        return 0;
 }
@@ -782,10 +800,11 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
        plane_state->fb = fb;
 
        if (fb)
-               DRM_DEBUG_KMS("Set [FB:%d] for plane state %p\n",
-                             fb->base.id, plane_state);
+               DRM_DEBUG_ATOMIC("Set [FB:%d] for plane state %p\n",
+                                fb->base.id, plane_state);
        else
-               DRM_DEBUG_KMS("Set [NOFB] for plane state %p\n", plane_state);
+               DRM_DEBUG_ATOMIC("Set [NOFB] for plane state %p\n",
+                                plane_state);
 }
 EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
 
@@ -818,11 +837,11 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
        conn_state->crtc = crtc;
 
        if (crtc)
-               DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
-                             conn_state, crtc->base.id);
+               DRM_DEBUG_ATOMIC("Link connector state %p to [CRTC:%d]\n",
+                                conn_state, crtc->base.id);
        else
-               DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n",
-                             conn_state);
+               DRM_DEBUG_ATOMIC("Link connector state %p to [NOCRTC]\n",
+                                conn_state);
 
        return 0;
 }
@@ -858,8 +877,8 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
        if (ret)
                return ret;
 
-       DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n",
-                     crtc->base.id, state);
+       DRM_DEBUG_ATOMIC("Adding all current connectors for [CRTC:%d] to %p\n",
+                        crtc->base.id, state);
 
        /*
         * Changed connectors are already in @state, so only need to look at the
@@ -901,8 +920,8 @@ drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
                        num_connected_connectors++;
        }
 
-       DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n",
-                     state, num_connected_connectors, crtc->base.id);
+       DRM_DEBUG_ATOMIC("State %p has %i connectors for [CRTC:%d]\n",
+                        state, num_connected_connectors, crtc->base.id);
 
        return num_connected_connectors;
 }
@@ -953,7 +972,7 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
        int ncrtcs = config->num_crtc;
        int i, ret = 0;
 
-       DRM_DEBUG_KMS("checking %p\n", state);
+       DRM_DEBUG_ATOMIC("checking %p\n", state);
 
        for (i = 0; i < nplanes; i++) {
                struct drm_plane *plane = state->planes[i];
@@ -963,8 +982,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
 
                ret = drm_atomic_plane_check(plane, state->plane_states[i]);
                if (ret) {
-                       DRM_DEBUG_KMS("[PLANE:%d] atomic core check failed\n",
-                                     plane->base.id);
+                       DRM_DEBUG_ATOMIC("[PLANE:%d] atomic core check failed\n",
+                                        plane->base.id);
                        return ret;
                }
        }
@@ -977,8 +996,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
 
                ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]);
                if (ret) {
-                       DRM_DEBUG_KMS("[CRTC:%d] atomic core check failed\n",
-                                     crtc->base.id);
+                       DRM_DEBUG_ATOMIC("[CRTC:%d] atomic core check failed\n",
+                                        crtc->base.id);
                        return ret;
                }
        }
@@ -996,8 +1015,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
 
                        if (crtc_state->mode_changed ||
                            crtc_state->active_changed) {
-                               DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n",
-                                             crtc->base.id);
+                               DRM_DEBUG_ATOMIC("[CRTC:%d] requires full modeset\n",
+                                                crtc->base.id);
                                return -EINVAL;
                        }
                }
@@ -1032,7 +1051,7 @@ int drm_atomic_commit(struct drm_atomic_state *state)
        if (ret)
                return ret;
 
-       DRM_DEBUG_KMS("commiting %p\n", state);
+       DRM_DEBUG_ATOMIC("commiting %p\n", state);
 
        return config->funcs->atomic_commit(state->dev, state, false);
 }
@@ -1063,7 +1082,7 @@ int drm_atomic_async_commit(struct drm_atomic_state *state)
        if (ret)
                return ret;
 
-       DRM_DEBUG_KMS("commiting %p asynchronously\n", state);
+       DRM_DEBUG_ATOMIC("commiting %p asynchronously\n", state);
 
        return config->funcs->atomic_commit(state->dev, state, true);
 }
index 7e3a52b97c7d4154b82870f2c2d2ebb04298a5e0..41c38edade74d1e748e265c3f3194b7c5c48a68b 100644 (file)
@@ -116,9 +116,9 @@ steal_encoder(struct drm_atomic_state *state,
         */
        WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
 
-       DRM_DEBUG_KMS("[ENCODER:%d:%s] in use on [CRTC:%d], stealing it\n",
-                     encoder->base.id, encoder->name,
-                     encoder_crtc->base.id);
+       DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d], stealing it\n",
+                        encoder->base.id, encoder->name,
+                        encoder_crtc->base.id);
 
        crtc_state = drm_atomic_get_crtc_state(state, encoder_crtc);
        if (IS_ERR(crtc_state))
@@ -130,9 +130,9 @@ steal_encoder(struct drm_atomic_state *state,
                if (connector->state->best_encoder != encoder)
                        continue;
 
-               DRM_DEBUG_KMS("Stealing encoder from [CONNECTOR:%d:%s]\n",
-                             connector->base.id,
-                             connector->name);
+               DRM_DEBUG_ATOMIC("Stealing encoder from [CONNECTOR:%d:%s]\n",
+                                connector->base.id,
+                                connector->name);
 
                connector_state = drm_atomic_get_connector_state(state,
                                                                 connector);
@@ -151,7 +151,7 @@ steal_encoder(struct drm_atomic_state *state,
 static int
 update_connector_routing(struct drm_atomic_state *state, int conn_idx)
 {
-       struct drm_connector_helper_funcs *funcs;
+       const struct drm_connector_helper_funcs *funcs;
        struct drm_encoder *new_encoder;
        struct drm_crtc *encoder_crtc;
        struct drm_connector *connector;
@@ -165,9 +165,9 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
        if (!connector)
                return 0;
 
-       DRM_DEBUG_KMS("Updating routing for [CONNECTOR:%d:%s]\n",
-                       connector->base.id,
-                       connector->name);
+       DRM_DEBUG_ATOMIC("Updating routing for [CONNECTOR:%d:%s]\n",
+                        connector->base.id,
+                        connector->name);
 
        if (connector->state->crtc != connector_state->crtc) {
                if (connector->state->crtc) {
@@ -186,7 +186,7 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
        }
 
        if (!connector_state->crtc) {
-               DRM_DEBUG_KMS("Disabling [CONNECTOR:%d:%s]\n",
+               DRM_DEBUG_ATOMIC("Disabling [CONNECTOR:%d:%s]\n",
                                connector->base.id,
                                connector->name);
 
@@ -199,19 +199,19 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
        new_encoder = funcs->best_encoder(connector);
 
        if (!new_encoder) {
-               DRM_DEBUG_KMS("No suitable encoder found for [CONNECTOR:%d:%s]\n",
-                             connector->base.id,
-                             connector->name);
+               DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
+                                connector->base.id,
+                                connector->name);
                return -EINVAL;
        }
 
        if (new_encoder == connector_state->best_encoder) {
-               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n",
-                             connector->base.id,
-                             connector->name,
-                             new_encoder->base.id,
-                             new_encoder->name,
-                             connector_state->crtc->base.id);
+               DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n",
+                                connector->base.id,
+                                connector->name,
+                                new_encoder->base.id,
+                                new_encoder->name,
+                                connector_state->crtc->base.id);
 
                return 0;
        }
@@ -222,9 +222,9 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
        if (encoder_crtc) {
                ret = steal_encoder(state, new_encoder, encoder_crtc);
                if (ret) {
-                       DRM_DEBUG_KMS("Encoder stealing failed for [CONNECTOR:%d:%s]\n",
-                                     connector->base.id,
-                                     connector->name);
+                       DRM_DEBUG_ATOMIC("Encoder stealing failed for [CONNECTOR:%d:%s]\n",
+                                        connector->base.id,
+                                        connector->name);
                        return ret;
                }
        }
@@ -235,12 +235,12 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
        crtc_state = state->crtc_states[idx];
        crtc_state->mode_changed = true;
 
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n",
-                     connector->base.id,
-                     connector->name,
-                     new_encoder->base.id,
-                     new_encoder->name,
-                     connector_state->crtc->base.id);
+       DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n",
+                        connector->base.id,
+                        connector->name,
+                        new_encoder->base.id,
+                        new_encoder->name,
+                        connector_state->crtc->base.id);
 
        return 0;
 }
@@ -264,7 +264,7 @@ mode_fixup(struct drm_atomic_state *state)
        }
 
        for (i = 0; i < state->num_connector; i++) {
-               struct drm_encoder_helper_funcs *funcs;
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
 
                conn_state = state->connector_states[i];
@@ -292,7 +292,7 @@ mode_fixup(struct drm_atomic_state *state)
                                        encoder->bridge, &crtc_state->mode,
                                        &crtc_state->adjusted_mode);
                        if (!ret) {
-                               DRM_DEBUG_KMS("Bridge fixup failed\n");
+                               DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
                                return -EINVAL;
                        }
                }
@@ -301,23 +301,23 @@ mode_fixup(struct drm_atomic_state *state)
                        ret = funcs->atomic_check(encoder, crtc_state,
                                                  conn_state);
                        if (ret) {
-                               DRM_DEBUG_KMS("[ENCODER:%d:%s] check failed\n",
-                                             encoder->base.id, encoder->name);
+                               DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] check failed\n",
+                                                encoder->base.id, encoder->name);
                                return ret;
                        }
                } else {
                        ret = funcs->mode_fixup(encoder, &crtc_state->mode,
                                                &crtc_state->adjusted_mode);
                        if (!ret) {
-                               DRM_DEBUG_KMS("[ENCODER:%d:%s] fixup failed\n",
-                                             encoder->base.id, encoder->name);
+                               DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] fixup failed\n",
+                                                encoder->base.id, encoder->name);
                                return -EINVAL;
                        }
                }
        }
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc;
 
                crtc_state = state->crtc_states[i];
@@ -330,8 +330,8 @@ mode_fixup(struct drm_atomic_state *state)
                ret = funcs->mode_fixup(crtc, &crtc_state->mode,
                                        &crtc_state->adjusted_mode);
                if (!ret) {
-                       DRM_DEBUG_KMS("[CRTC:%d] fixup failed\n",
-                                     crtc->base.id);
+                       DRM_DEBUG_ATOMIC("[CRTC:%d] fixup failed\n",
+                                        crtc->base.id);
                        return -EINVAL;
                }
        }
@@ -346,7 +346,7 @@ needs_modeset(struct drm_crtc_state *state)
 }
 
 /**
- * drm_atomic_helper_check - validate state object for modeset changes
+ * drm_atomic_helper_check_modeset - validate state object for modeset changes
  * @dev: DRM device
  * @state: the driver state object
  *
@@ -384,14 +384,14 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
                        continue;
 
                if (!drm_mode_equal(&crtc->state->mode, &crtc_state->mode)) {
-                       DRM_DEBUG_KMS("[CRTC:%d] mode changed\n",
-                                     crtc->base.id);
+                       DRM_DEBUG_ATOMIC("[CRTC:%d] mode changed\n",
+                                        crtc->base.id);
                        crtc_state->mode_changed = true;
                }
 
                if (crtc->state->enable != crtc_state->enable) {
-                       DRM_DEBUG_KMS("[CRTC:%d] enable changed\n",
-                                     crtc->base.id);
+                       DRM_DEBUG_ATOMIC("[CRTC:%d] enable changed\n",
+                                        crtc->base.id);
                        crtc_state->mode_changed = true;
                }
        }
@@ -428,17 +428,17 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
                 * a full modeset because update_connector_routing force that.
                 */
                if (crtc->state->active != crtc_state->active) {
-                       DRM_DEBUG_KMS("[CRTC:%d] active changed\n",
-                                     crtc->base.id);
+                       DRM_DEBUG_ATOMIC("[CRTC:%d] active changed\n",
+                                        crtc->base.id);
                        crtc_state->active_changed = true;
                }
 
                if (!needs_modeset(crtc_state))
                        continue;
 
-               DRM_DEBUG_KMS("[CRTC:%d] needs all connectors, enable: %c, active: %c\n",
-                             crtc->base.id,
-                             crtc_state->enable ? 'y' : 'n',
+               DRM_DEBUG_ATOMIC("[CRTC:%d] needs all connectors, enable: %c, active: %c\n",
+                                crtc->base.id,
+                                crtc_state->enable ? 'y' : 'n',
                              crtc_state->active ? 'y' : 'n');
 
                ret = drm_atomic_add_affected_connectors(state, crtc);
@@ -449,8 +449,8 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
                                                                crtc);
 
                if (crtc_state->enable != !!num_connectors) {
-                       DRM_DEBUG_KMS("[CRTC:%d] enabled/connectors mismatch\n",
-                                     crtc->base.id);
+                       DRM_DEBUG_ATOMIC("[CRTC:%d] enabled/connectors mismatch\n",
+                                        crtc->base.id);
 
                        return -EINVAL;
                }
@@ -461,7 +461,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
 EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
 
 /**
- * drm_atomic_helper_check - validate state object for modeset changes
+ * drm_atomic_helper_check_planes - validate state object for planes changes
  * @dev: DRM device
  * @state: the driver state object
  *
@@ -481,7 +481,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
        int i, ret = 0;
 
        for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = state->planes[i];
                struct drm_plane_state *plane_state = state->plane_states[i];
 
@@ -497,14 +497,14 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
 
                ret = funcs->atomic_check(plane, plane_state);
                if (ret) {
-                       DRM_DEBUG_KMS("[PLANE:%d] atomic driver check failed\n",
-                                     plane->base.id);
+                       DRM_DEBUG_ATOMIC("[PLANE:%d] atomic driver check failed\n",
+                                        plane->base.id);
                        return ret;
                }
        }
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc = state->crtcs[i];
 
                if (!crtc)
@@ -517,8 +517,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
 
                ret = funcs->atomic_check(crtc, state->crtc_states[i]);
                if (ret) {
-                       DRM_DEBUG_KMS("[CRTC:%d] atomic driver check failed\n",
-                                     crtc->base.id);
+                       DRM_DEBUG_ATOMIC("[CRTC:%d] atomic driver check failed\n",
+                                        crtc->base.id);
                        return ret;
                }
        }
@@ -571,9 +571,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
        int i;
 
        for (i = 0; i < old_state->num_connector; i++) {
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_connector_state *old_conn_state;
                struct drm_connector *connector;
-               struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
                struct drm_crtc_state *old_crtc_state;
 
@@ -587,7 +587,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)];
 
-               if (!old_crtc_state->active)
+               if (!old_crtc_state->active ||
+                   !needs_modeset(old_conn_state->crtc->state))
                        continue;
 
                encoder = old_conn_state->best_encoder;
@@ -600,12 +601,12 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                funcs = encoder->helper_private;
 
-               DRM_DEBUG_KMS("disabling [ENCODER:%d:%s]\n",
-                             encoder->base.id, encoder->name);
+               DRM_DEBUG_ATOMIC("disabling [ENCODER:%d:%s]\n",
+                                encoder->base.id, encoder->name);
 
                /*
                 * Each encoder has at most one connector (since we always steal
-                * it away), so we won't call call disable hooks twice.
+                * it away), so we won't call disable hooks twice.
                 */
                if (encoder->bridge)
                        encoder->bridge->funcs->disable(encoder->bridge);
@@ -623,7 +624,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
        }
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc;
                struct drm_crtc_state *old_crtc_state;
 
@@ -639,8 +640,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                funcs = crtc->helper_private;
 
-               DRM_DEBUG_KMS("disabling [CRTC:%d]\n",
-                             crtc->base.id);
+               DRM_DEBUG_ATOMIC("disabling [CRTC:%d]\n",
+                                crtc->base.id);
 
 
                /* Right function depends upon target state. */
@@ -713,7 +714,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
        int i;
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc;
 
                crtc = old_state->crtcs[i];
@@ -723,18 +724,18 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                funcs = crtc->helper_private;
 
-               if (crtc->state->enable) {
-                       DRM_DEBUG_KMS("modeset on [CRTC:%d]\n",
-                                     crtc->base.id);
+               if (crtc->state->enable && funcs->mode_set_nofb) {
+                       DRM_DEBUG_ATOMIC("modeset on [CRTC:%d]\n",
+                                        crtc->base.id);
 
                        funcs->mode_set_nofb(crtc);
                }
        }
 
        for (i = 0; i < old_state->num_connector; i++) {
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_connector *connector;
                struct drm_crtc_state *new_crtc_state;
-               struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
                struct drm_display_mode *mode, *adjusted_mode;
 
@@ -752,14 +753,15 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
                if (!new_crtc_state->mode_changed)
                        continue;
 
-               DRM_DEBUG_KMS("modeset on [ENCODER:%d:%s]\n",
-                             encoder->base.id, encoder->name);
+               DRM_DEBUG_ATOMIC("modeset on [ENCODER:%d:%s]\n",
+                                encoder->base.id, encoder->name);
 
                /*
                 * Each encoder has at most one connector (since we always steal
-                * it away), so we won't call call mode_set hooks twice.
+                * it away), so we won't call mode_set hooks twice.
                 */
-               funcs->mode_set(encoder, mode, adjusted_mode);
+               if (funcs->mode_set)
+                       funcs->mode_set(encoder, mode, adjusted_mode);
 
                if (encoder->bridge && encoder->bridge->funcs->mode_set)
                        encoder->bridge->funcs->mode_set(encoder->bridge,
@@ -768,40 +770,50 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
 }
 
 /**
- * drm_atomic_helper_commit_pre_planes - modeset commit before plane updates
+ * drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs
  * @dev: DRM device
- * @state: atomic state
+ * @old_state: atomic state object with old state structures
  *
- * This function commits the modeset changes that need to be committed before
- * updating planes. It shuts down all the outputs that need to be shut down and
+ * This function shuts down all the outputs that need to be shut down and
  * prepares them (if required) with the new mode.
+ *
+ * For compatability with legacy crtc helpers this should be called before
+ * drm_atomic_helper_commit_planes(), which is what the default commit function
+ * does. But drivers with different needs can group the modeset commits together
+ * and do the plane commits at the end. This is useful for drivers doing runtime
+ * PM since planes updates then only happen when the CRTC is actually enabled.
  */
-void drm_atomic_helper_commit_pre_planes(struct drm_device *dev,
-                                        struct drm_atomic_state *state)
+void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
+                                              struct drm_atomic_state *old_state)
 {
-       disable_outputs(dev, state);
-       set_routing_links(dev, state);
-       crtc_set_mode(dev, state);
+       disable_outputs(dev, old_state);
+       set_routing_links(dev, old_state);
+       crtc_set_mode(dev, old_state);
 }
-EXPORT_SYMBOL(drm_atomic_helper_commit_pre_planes);
+EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables);
 
 /**
- * drm_atomic_helper_commit_post_planes - modeset commit after plane updates
+ * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs
  * @dev: DRM device
  * @old_state: atomic state object with old state structures
  *
- * This function commits the modeset changes that need to be committed after
- * updating planes: It enables all the outputs with the new configuration which
- * had to be turned off for the update.
+ * This function enables all the outputs with the new configuration which had to
+ * be turned off for the update.
+ *
+ * For compatability with legacy crtc helpers this should be called after
+ * drm_atomic_helper_commit_planes(), which is what the default commit function
+ * does. But drivers with different needs can group the modeset commits together
+ * and do the plane commits at the end. This is useful for drivers doing runtime
+ * PM since planes updates then only happen when the CRTC is actually enabled.
  */
-void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
-                                         struct drm_atomic_state *old_state)
+void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
+                                             struct drm_atomic_state *old_state)
 {
        int ncrtcs = old_state->dev->mode_config.num_crtc;
        int i;
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc;
 
                crtc = old_state->crtcs[i];
@@ -816,8 +828,8 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
                funcs = crtc->helper_private;
 
                if (crtc->state->enable) {
-                       DRM_DEBUG_KMS("enabling [CRTC:%d]\n",
-                                     crtc->base.id);
+                       DRM_DEBUG_ATOMIC("enabling [CRTC:%d]\n",
+                                        crtc->base.id);
 
                        if (funcs->enable)
                                funcs->enable(crtc);
@@ -827,8 +839,8 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
        }
 
        for (i = 0; i < old_state->num_connector; i++) {
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_connector *connector;
-               struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
 
                connector = old_state->connectors[i];
@@ -836,18 +848,19 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
                if (!connector || !connector->state->best_encoder)
                        continue;
 
-               if (!connector->state->crtc->state->active)
+               if (!connector->state->crtc->state->active ||
+                   !needs_modeset(connector->state->crtc->state))
                        continue;
 
                encoder = connector->state->best_encoder;
                funcs = encoder->helper_private;
 
-               DRM_DEBUG_KMS("enabling [ENCODER:%d:%s]\n",
-                             encoder->base.id, encoder->name);
+               DRM_DEBUG_ATOMIC("enabling [ENCODER:%d:%s]\n",
+                                encoder->base.id, encoder->name);
 
                /*
                 * Each encoder has at most one connector (since we always steal
-                * it away), so we won't call call enable hooks twice.
+                * it away), so we won't call enable hooks twice.
                 */
                if (encoder->bridge)
                        encoder->bridge->funcs->pre_enable(encoder->bridge);
@@ -861,7 +874,7 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
                        encoder->bridge->funcs->enable(encoder->bridge);
        }
 }
-EXPORT_SYMBOL(drm_atomic_helper_commit_post_planes);
+EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);
 
 static void wait_for_fences(struct drm_device *dev,
                            struct drm_atomic_state *state)
@@ -1014,7 +1027,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 
        /*
         * Everything below can be run asynchronously without the need to grab
-        * any modeset locks at all under one conditions: It must be guaranteed
+        * any modeset locks at all under one condition: It must be guaranteed
         * that the asynchronous work has either been cancelled (if the driver
         * supports it, which at least requires that the framebuffers get
         * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
@@ -1030,11 +1043,11 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 
        wait_for_fences(dev, state);
 
-       drm_atomic_helper_commit_pre_planes(dev, state);
+       drm_atomic_helper_commit_modeset_disables(dev, state);
 
        drm_atomic_helper_commit_planes(dev, state);
 
-       drm_atomic_helper_commit_post_planes(dev, state);
+       drm_atomic_helper_commit_modeset_enables(dev, state);
 
        drm_atomic_helper_wait_for_vblanks(dev, state);
 
@@ -1085,9 +1098,9 @@ EXPORT_SYMBOL(drm_atomic_helper_commit);
  */
 
 /**
- * drm_atomic_helper_prepare_planes - prepare plane resources after commit
+ * drm_atomic_helper_prepare_planes - prepare plane resources before commit
  * @dev: DRM device
- * @state: atomic state object with old state structures
+ * @state: atomic state object with new state structures
  *
  * This function prepares plane state, specifically framebuffers, for the new
  * configuration. If any failure is encountered this function will call
@@ -1103,8 +1116,9 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
        int ret, i;
 
        for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = state->planes[i];
+               struct drm_plane_state *plane_state = state->plane_states[i];
                struct drm_framebuffer *fb;
 
                if (!plane)
@@ -1112,10 +1126,10 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
 
                funcs = plane->helper_private;
 
-               fb = state->plane_states[i]->fb;
+               fb = plane_state->fb;
 
                if (fb && funcs->prepare_fb) {
-                       ret = funcs->prepare_fb(plane, fb);
+                       ret = funcs->prepare_fb(plane, fb, plane_state);
                        if (ret)
                                goto fail;
                }
@@ -1125,8 +1139,9 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
 
 fail:
        for (i--; i >= 0; i--) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = state->planes[i];
+               struct drm_plane_state *plane_state = state->plane_states[i];
                struct drm_framebuffer *fb;
 
                if (!plane)
@@ -1137,7 +1152,7 @@ fail:
                fb = state->plane_states[i]->fb;
 
                if (fb && funcs->cleanup_fb)
-                       funcs->cleanup_fb(plane, fb);
+                       funcs->cleanup_fb(plane, fb, plane_state);
 
        }
 
@@ -1166,7 +1181,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
        int i;
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc = old_state->crtcs[i];
 
                if (!crtc)
@@ -1181,7 +1196,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
        }
 
        for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = old_state->planes[i];
                struct drm_plane_state *old_plane_state;
 
@@ -1206,7 +1221,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
        }
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc = old_state->crtcs[i];
 
                if (!crtc)
@@ -1241,8 +1256,9 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
        int i;
 
        for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = old_state->planes[i];
+               struct drm_plane_state *plane_state = old_state->plane_states[i];
                struct drm_framebuffer *old_fb;
 
                if (!plane)
@@ -1250,10 +1266,10 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
 
                funcs = plane->helper_private;
 
-               old_fb = old_state->plane_states[i]->fb;
+               old_fb = plane_state->fb;
 
                if (old_fb && funcs->cleanup_fb)
-                       funcs->cleanup_fb(plane, old_fb);
+                       funcs->cleanup_fb(plane, old_fb, plane_state);
        }
 }
 EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
@@ -1678,12 +1694,13 @@ backoff:
 EXPORT_SYMBOL(drm_atomic_helper_set_config);
 
 /**
- * drm_atomic_helper_crtc_set_property - helper for crtc prorties
+ * drm_atomic_helper_crtc_set_property - helper for crtc properties
  * @crtc: DRM crtc
  * @property: DRM property
  * @val: value of property
  *
- * Provides a default plane disablle handler using the atomic driver interface.
+ * Provides a default crtc set_property handler using the atomic driver
+ * interface.
  *
  * RETURNS:
  * Zero on success, error code on failure
@@ -1737,12 +1754,13 @@ backoff:
 EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property);
 
 /**
- * drm_atomic_helper_plane_set_property - helper for plane prorties
+ * drm_atomic_helper_plane_set_property - helper for plane properties
  * @plane: DRM plane
  * @property: DRM property
  * @val: value of property
  *
- * Provides a default plane disable handler using the atomic driver interface.
+ * Provides a default plane set_property handler using the atomic driver
+ * interface.
  *
  * RETURNS:
  * Zero on success, error code on failure
@@ -1796,12 +1814,13 @@ backoff:
 EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
 
 /**
- * drm_atomic_helper_connector_set_property - helper for connector prorties
+ * drm_atomic_helper_connector_set_property - helper for connector properties
  * @connector: DRM connector
  * @property: DRM property
  * @val: value of property
  *
- * Provides a default plane disablle handler using the atomic driver interface.
+ * Provides a default connector set_property handler using the atomic driver
+ * interface.
  *
  * RETURNS:
  * Zero on success, error code on failure
@@ -1984,10 +2003,10 @@ retry:
        WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
 
        list_for_each_entry(tmp_connector, &config->connector_list, head) {
-               if (connector->state->crtc != crtc)
+               if (tmp_connector->state->crtc != crtc)
                        continue;
 
-               if (connector->dpms == DRM_MODE_DPMS_ON) {
+               if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
                        active = true;
                        break;
                }
@@ -2049,6 +2068,26 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
 
+/**
+ * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
+ * @crtc: CRTC object
+ * @state: atomic CRTC state
+ *
+ * Copies atomic state from a CRTC's current state and resets inferred values.
+ * This is useful for drivers that subclass the CRTC state.
+ */
+void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
+                                             struct drm_crtc_state *state)
+{
+       memcpy(state, crtc->state, sizeof(*state));
+
+       state->mode_changed = false;
+       state->active_changed = false;
+       state->planes_changed = false;
+       state->event = NULL;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
+
 /**
  * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
  * @crtc: drm CRTC
@@ -2064,19 +2103,34 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
        if (WARN_ON(!crtc->state))
                return NULL;
 
-       state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL);
-
-       if (state) {
-               state->mode_changed = false;
-               state->active_changed = false;
-               state->planes_changed = false;
-               state->event = NULL;
-       }
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               __drm_atomic_helper_crtc_duplicate_state(crtc, state);
 
        return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
 
+/**
+ * __drm_atomic_helper_crtc_destroy_state - release CRTC state
+ * @crtc: CRTC object
+ * @state: CRTC state object to release
+ *
+ * Releases all resources stored in the CRTC state without actually freeing
+ * the memory of the CRTC state. This is useful for drivers that subclass the
+ * CRTC state.
+ */
+void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+                                           struct drm_crtc_state *state)
+{
+       /*
+        * This is currently a placeholder so that drivers that subclass the
+        * state will automatically do the right thing if code is ever added
+        * to this function.
+        */
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
+
 /**
  * drm_atomic_helper_crtc_destroy_state - default state destroy hook
  * @crtc: drm CRTC
@@ -2088,6 +2142,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
 void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
                                          struct drm_crtc_state *state)
 {
+       __drm_atomic_helper_crtc_destroy_state(crtc, state);
        kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
@@ -2112,6 +2167,24 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
 
+/**
+ * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
+ * @plane: plane object
+ * @state: atomic plane state
+ *
+ * Copies atomic state from a plane's current state. This is useful for
+ * drivers that subclass the plane state.
+ */
+void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
+                                              struct drm_plane_state *state)
+{
+       memcpy(state, plane->state, sizeof(*state));
+
+       if (state->fb)
+               drm_framebuffer_reference(state->fb);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
+
 /**
  * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
  * @plane: drm plane
@@ -2127,15 +2200,31 @@ drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
        if (WARN_ON(!plane->state))
                return NULL;
 
-       state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
-
-       if (state && state->fb)
-               drm_framebuffer_reference(state->fb);
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               __drm_atomic_helper_plane_duplicate_state(plane, state);
 
        return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
 
+/**
+ * __drm_atomic_helper_plane_destroy_state - release plane state
+ * @plane: plane object
+ * @state: plane state object to release
+ *
+ * Releases all resources stored in the plane state without actually freeing
+ * the memory of the plane state. This is useful for drivers that subclass the
+ * plane state.
+ */
+void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+                                            struct drm_plane_state *state)
+{
+       if (state->fb)
+               drm_framebuffer_unreference(state->fb);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
+
 /**
  * drm_atomic_helper_plane_destroy_state - default state destroy hook
  * @plane: drm plane
@@ -2147,9 +2236,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
                                           struct drm_plane_state *state)
 {
-       if (state->fb)
-               drm_framebuffer_unreference(state->fb);
-
+       __drm_atomic_helper_plane_destroy_state(plane, state);
        kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
@@ -2172,6 +2259,22 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 
+/**
+ * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
+ * @connector: connector object
+ * @state: atomic connector state
+ *
+ * Copies atomic state from a connector's current state. This is useful for
+ * drivers that subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
+                                           struct drm_connector_state *state)
+{
+       memcpy(state, connector->state, sizeof(*state));
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
+
 /**
  * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
  * @connector: drm connector
@@ -2182,13 +2285,40 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 struct drm_connector_state *
 drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
 {
+       struct drm_connector_state *state;
+
        if (WARN_ON(!connector->state))
                return NULL;
 
-       return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL);
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               __drm_atomic_helper_connector_duplicate_state(connector, state);
+
+       return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
 
+/**
+ * __drm_atomic_helper_connector_destroy_state - release connector state
+ * @connector: connector object
+ * @state: connector state object to release
+ *
+ * Releases all resources stored in the connector state without actually
+ * freeing the memory of the connector state. This is useful for drivers that
+ * subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+                                           struct drm_connector_state *state)
+{
+       /*
+        * This is currently a placeholder so that drivers that subclass the
+        * state will automatically do the right thing if code is ever added
+        * to this function.
+        */
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
+
 /**
  * drm_atomic_helper_connector_destroy_state - default state destroy hook
  * @connector: drm connector
@@ -2200,6 +2330,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
 void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
                                          struct drm_connector_state *state)
 {
+       __drm_atomic_helper_connector_destroy_state(connector, state);
        kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
index d1187e571c6dd038648aa86b73d0cb2ddd526792..eaa5790c2a6f89a384f01d398bef81ef74cacb48 100644 (file)
@@ -49,7 +49,7 @@ void drm_bridge_remove(struct drm_bridge *bridge)
 }
 EXPORT_SYMBOL(drm_bridge_remove);
 
-extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
+int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
 {
        if (!dev || !bridge)
                return -EINVAL;
index 6b00173d1be4fd6c96f749a803dd23ab5495de88..d576a4dea64fa3e41db38efb63f00985458ac5df 100644 (file)
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
 
-static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
-                                                       struct drm_mode_fb_cmd2 *r,
-                                                       struct drm_file *file_priv);
+static struct drm_framebuffer *
+internal_framebuffer_create(struct drm_device *dev,
+                           struct drm_mode_fb_cmd2 *r,
+                           struct drm_file *file_priv);
 
 /* Avoid boilerplate.  I'm tired of typing. */
 #define DRM_ENUM_NAME_FN(fnname, list)                         \
@@ -524,17 +525,6 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb)
 }
 EXPORT_SYMBOL(drm_framebuffer_reference);
 
-static void drm_framebuffer_free_bug(struct kref *kref)
-{
-       BUG();
-}
-
-static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
-{
-       DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount));
-       kref_put(&fb->refcount, drm_framebuffer_free_bug);
-}
-
 /**
  * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
  * @fb: fb to unregister
@@ -670,6 +660,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        struct drm_mode_config *config = &dev->mode_config;
        int ret;
 
+       WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
+       WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);
+
        crtc->dev = dev;
        crtc->funcs = funcs;
        crtc->invert_dimensions = false;
@@ -1319,7 +1312,7 @@ void drm_plane_force_disable(struct drm_plane *plane)
                return;
        }
        /* disconnect the plane from the fb and crtc: */
-       __drm_framebuffer_unreference(plane->old_fb);
+       drm_framebuffer_unreference(plane->old_fb);
        plane->old_fb = NULL;
        plane->fb = NULL;
        plane->crtc = NULL;
@@ -2009,21 +2002,32 @@ int drm_mode_getcrtc(struct drm_device *dev,
                return -ENOENT;
 
        drm_modeset_lock_crtc(crtc, crtc->primary);
-       crtc_resp->x = crtc->x;
-       crtc_resp->y = crtc->y;
        crtc_resp->gamma_size = crtc->gamma_size;
        if (crtc->primary->fb)
                crtc_resp->fb_id = crtc->primary->fb->base.id;
        else
                crtc_resp->fb_id = 0;
 
-       if (crtc->enabled) {
-
-               drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
-               crtc_resp->mode_valid = 1;
+       if (crtc->state) {
+               crtc_resp->x = crtc->primary->state->src_x >> 16;
+               crtc_resp->y = crtc->primary->state->src_y >> 16;
+               if (crtc->state->enable) {
+                       drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
+                       crtc_resp->mode_valid = 1;
 
+               } else {
+                       crtc_resp->mode_valid = 0;
+               }
        } else {
-               crtc_resp->mode_valid = 0;
+               crtc_resp->x = crtc->x;
+               crtc_resp->y = crtc->y;
+               if (crtc->enabled) {
+                       drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
+                       crtc_resp->mode_valid = 1;
+
+               } else {
+                       crtc_resp->mode_valid = 0;
+               }
        }
        drm_modeset_unlock_crtc(crtc);
 
@@ -2127,7 +2131,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
 
        mutex_lock(&dev->mode_config.mutex);
-       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
 
        connector = drm_connector_find(dev, out_resp->connector_id);
        if (!connector) {
@@ -2157,6 +2160,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        out_resp->mm_height = connector->display_info.height_mm;
        out_resp->subpixel = connector->display_info.subpixel_order;
        out_resp->connection = connector->status;
+
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
        encoder = drm_connector_get_encoder(connector);
        if (encoder)
                out_resp->encoder_id = encoder->base.id;
@@ -2273,8 +2278,6 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
        crtc = drm_encoder_get_crtc(encoder);
        if (crtc)
                enc_resp->crtc_id = crtc->base.id;
-       else if (encoder->crtc)
-               enc_resp->crtc_id = encoder->crtc->base.id;
        else
                enc_resp->crtc_id = 0;
        drm_modeset_unlock(&dev->mode_config.connection_mutex);
@@ -2409,6 +2412,27 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
        return 0;
 }
 
+/**
+ * drm_plane_check_pixel_format - Check if the plane supports the pixel format
+ * @plane: plane to check for format support
+ * @format: the pixel format
+ *
+ * Returns:
+ * Zero of @plane has @format in its list of supported pixel formats, -EINVAL
+ * otherwise.
+ */
+int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)
+{
+       unsigned int i;
+
+       for (i = 0; i < plane->format_count; i++) {
+               if (format == plane->format_types[i])
+                       return 0;
+       }
+
+       return -EINVAL;
+}
+
 /*
  * setplane_internal - setplane handler for internal callers
  *
@@ -2429,7 +2453,6 @@ static int __setplane_internal(struct drm_plane *plane,
 {
        int ret = 0;
        unsigned int fb_width, fb_height;
-       unsigned int i;
 
        /* No fb means shut it down */
        if (!fb) {
@@ -2452,13 +2475,10 @@ static int __setplane_internal(struct drm_plane *plane,
        }
 
        /* Check whether this plane supports the fb pixel format. */
-       for (i = 0; i < plane->format_count; i++)
-               if (fb->pixel_format == plane->format_types[i])
-                       break;
-       if (i == plane->format_count) {
+       ret = drm_plane_check_pixel_format(plane, fb->pixel_format);
+       if (ret) {
                DRM_DEBUG_KMS("Invalid pixel format %s\n",
                              drm_get_format_name(fb->pixel_format));
-               ret = -EINVAL;
                goto out;
        }
 
@@ -2782,6 +2802,23 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 
                drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
 
+               /*
+                * Check whether the primary plane supports the fb pixel format.
+                * Drivers not implementing the universal planes API use a
+                * default formats list provided by the DRM core which doesn't
+                * match real hardware capabilities. Skip the check in that
+                * case.
+                */
+               if (!crtc->primary->format_default) {
+                       ret = drm_plane_check_pixel_format(crtc->primary,
+                                                          fb->pixel_format);
+                       if (ret) {
+                               DRM_DEBUG_KMS("Invalid pixel format %s\n",
+                                       drm_get_format_name(fb->pixel_format));
+                               goto out;
+                       }
+               }
+
                ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
                                              mode, fb);
                if (ret)
@@ -2907,13 +2944,11 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
         */
        if (req->flags & DRM_MODE_CURSOR_BO) {
                if (req->handle) {
-                       fb = add_framebuffer_internal(dev, &fbreq, file_priv);
+                       fb = internal_framebuffer_create(dev, &fbreq, file_priv);
                        if (IS_ERR(fb)) {
                                DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
                                return PTR_ERR(fb);
                        }
-
-                       drm_framebuffer_reference(fb);
                } else {
                        fb = NULL;
                }
@@ -3261,20 +3296,27 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
                        DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
                        return -EINVAL;
                }
+
+               if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
+                       DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n",
+                                     r->modifier[i], i);
+                       return -EINVAL;
+               }
        }
 
        return 0;
 }
 
-static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
-                                                       struct drm_mode_fb_cmd2 *r,
-                                                       struct drm_file *file_priv)
+static struct drm_framebuffer *
+internal_framebuffer_create(struct drm_device *dev,
+                           struct drm_mode_fb_cmd2 *r,
+                           struct drm_file *file_priv)
 {
        struct drm_mode_config *config = &dev->mode_config;
        struct drm_framebuffer *fb;
        int ret;
 
-       if (r->flags & ~DRM_MODE_FB_INTERLACED) {
+       if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) {
                DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
                return ERR_PTR(-EINVAL);
        }
@@ -3290,6 +3332,12 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
                return ERR_PTR(-EINVAL);
        }
 
+       if (r->flags & DRM_MODE_FB_MODIFIERS &&
+           !dev->mode_config.allow_fb_modifiers) {
+               DRM_DEBUG_KMS("driver does not support fb modifiers\n");
+               return ERR_PTR(-EINVAL);
+       }
+
        ret = framebuffer_check(r);
        if (ret)
                return ERR_PTR(ret);
@@ -3300,12 +3348,6 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
                return fb;
        }
 
-       mutex_lock(&file_priv->fbs_lock);
-       r->fb_id = fb->base.id;
-       list_add(&fb->filp_head, &file_priv->fbs);
-       DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
-       mutex_unlock(&file_priv->fbs_lock);
-
        return fb;
 }
 
@@ -3327,15 +3369,24 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
 int drm_mode_addfb2(struct drm_device *dev,
                    void *data, struct drm_file *file_priv)
 {
+       struct drm_mode_fb_cmd2 *r = data;
        struct drm_framebuffer *fb;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       fb = add_framebuffer_internal(dev, data, file_priv);
+       fb = internal_framebuffer_create(dev, r, file_priv);
        if (IS_ERR(fb))
                return PTR_ERR(fb);
 
+       /* Transfer ownership to the filp for reaping on close */
+
+       DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
+       mutex_lock(&file_priv->fbs_lock);
+       r->fb_id = fb->base.id;
+       list_add(&fb->filp_head, &file_priv->fbs);
+       mutex_unlock(&file_priv->fbs_lock);
+
        return 0;
 }
 
index b1979e7bdc8862548d3f483eac109bf7959df27e..dd895c409ca328464263a7985622b526546db6ba 100644 (file)
@@ -270,7 +270,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                              struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_display_mode *adjusted_mode, saved_mode;
+       struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
        struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        struct drm_encoder_helper_funcs *encoder_funcs;
        int saved_x, saved_y;
@@ -292,6 +292,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        }
 
        saved_mode = crtc->mode;
+       saved_hwmode = crtc->hwmode;
        saved_x = crtc->x;
        saved_y = crtc->y;
 
@@ -334,6 +335,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        }
        DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
+       crtc->hwmode = *adjusted_mode;
+
        /* Prepare the encoders and CRTCs before setting the mode. */
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 
@@ -396,9 +399,6 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                        encoder->bridge->funcs->enable(encoder->bridge);
        }
 
-       /* Store real post-adjustment hardware mode. */
-       crtc->hwmode = *adjusted_mode;
-
        /* Calculate and store various constants which
         * are later needed by vblank and swap-completion
         * timestamping. They are derived from true hwmode.
@@ -411,6 +411,7 @@ done:
        if (!ret) {
                crtc->enabled = saved_enabled;
                crtc->mode = saved_mode;
+               crtc->hwmode = saved_hwmode;
                crtc->x = saved_x;
                crtc->y = saved_y;
        }
@@ -837,6 +838,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
        for (i = 0; i < 4; i++) {
                fb->pitches[i] = mode_cmd->pitches[i];
                fb->offsets[i] = mode_cmd->offsets[i];
+               fb->modifier[i] = mode_cmd->modifier[i];
        }
        drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
                                    &fb->bits_per_pixel);
index f1283878ff6df3000608773de43ee22e77cd7b59..71dcbc64ae98b860bbb4a6aed06f502dc83737f1 100644 (file)
@@ -427,11 +427,13 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
  * retrying the transaction as appropriate.  It is assumed that the
  * aux->transfer function does not modify anything in the msg other than the
  * reply field.
+ *
+ * Returns bytes transferred on success, or a negative error code on failure.
  */
 static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 {
        unsigned int retry;
-       int err;
+       int ret;
 
        /*
         * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device
@@ -440,14 +442,14 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
         */
        for (retry = 0; retry < 7; retry++) {
                mutex_lock(&aux->hw_mutex);
-               err = aux->transfer(aux, msg);
+               ret = aux->transfer(aux, msg);
                mutex_unlock(&aux->hw_mutex);
-               if (err < 0) {
-                       if (err == -EBUSY)
+               if (ret < 0) {
+                       if (ret == -EBUSY)
                                continue;
 
-                       DRM_DEBUG_KMS("transaction failed: %d\n", err);
-                       return err;
+                       DRM_DEBUG_KMS("transaction failed: %d\n", ret);
+                       return ret;
                }
 
 
@@ -460,7 +462,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                        break;
 
                case DP_AUX_NATIVE_REPLY_NACK:
-                       DRM_DEBUG_KMS("native nack\n");
+                       DRM_DEBUG_KMS("native nack (result=%d, size=%zu)\n", ret, msg->size);
                        return -EREMOTEIO;
 
                case DP_AUX_NATIVE_REPLY_DEFER:
@@ -488,12 +490,10 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                         * Both native ACK and I2C ACK replies received. We
                         * can assume the transfer was successful.
                         */
-                       if (err < msg->size)
-                               return -EPROTO;
-                       return 0;
+                       return ret;
 
                case DP_AUX_I2C_REPLY_NACK:
-                       DRM_DEBUG_KMS("I2C nack\n");
+                       DRM_DEBUG_KMS("I2C nack (result=%d, size=%zu\n", ret, msg->size);
                        aux->i2c_nack_count++;
                        return -EREMOTEIO;
 
@@ -513,14 +513,55 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        return -EREMOTEIO;
 }
 
+/*
+ * Keep retrying drm_dp_i2c_do_msg until all data has been transferred.
+ *
+ * Returns an error code on failure, or a recommended transfer size on success.
+ */
+static int drm_dp_i2c_drain_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *orig_msg)
+{
+       int err, ret = orig_msg->size;
+       struct drm_dp_aux_msg msg = *orig_msg;
+
+       while (msg.size > 0) {
+               err = drm_dp_i2c_do_msg(aux, &msg);
+               if (err <= 0)
+                       return err == 0 ? -EPROTO : err;
+
+               if (err < msg.size && err < ret) {
+                       DRM_DEBUG_KMS("Partial I2C reply: requested %zu bytes got %d bytes\n",
+                                     msg.size, err);
+                       ret = err;
+               }
+
+               msg.size -= err;
+               msg.buffer += err;
+       }
+
+       return ret;
+}
+
+/*
+ * Bizlink designed DP->DVI-D Dual Link adapters require the I2C over AUX
+ * packets to be as large as possible. If not, the I2C transactions never
+ * succeed. Hence the default is maximum.
+ */
+static int dp_aux_i2c_transfer_size __read_mostly = DP_AUX_MAX_PAYLOAD_BYTES;
+module_param_unsafe(dp_aux_i2c_transfer_size, int, 0644);
+MODULE_PARM_DESC(dp_aux_i2c_transfer_size,
+                "Number of bytes to transfer in a single I2C over DP AUX CH message, (1-16, default 16)");
+
 static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                           int num)
 {
        struct drm_dp_aux *aux = adapter->algo_data;
        unsigned int i, j;
+       unsigned transfer_size;
        struct drm_dp_aux_msg msg;
        int err = 0;
 
+       dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, DP_AUX_MAX_PAYLOAD_BYTES);
+
        memset(&msg, 0, sizeof(msg));
 
        for (i = 0; i < num; i++) {
@@ -538,20 +579,19 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                err = drm_dp_i2c_do_msg(aux, &msg);
                if (err < 0)
                        break;
-               /*
-                * Many hardware implementations support FIFOs larger than a
-                * single byte, but it has been empirically determined that
-                * transferring data in larger chunks can actually lead to
-                * decreased performance. Therefore each message is simply
-                * transferred byte-by-byte.
+               /* We want each transaction to be as large as possible, but
+                * we'll go to smaller sizes if the hardware gives us a
+                * short reply.
                 */
-               for (j = 0; j < msgs[i].len; j++) {
+               transfer_size = dp_aux_i2c_transfer_size;
+               for (j = 0; j < msgs[i].len; j += msg.size) {
                        msg.buffer = msgs[i].buf + j;
-                       msg.size = 1;
+                       msg.size = min(transfer_size, msgs[i].len - j);
 
-                       err = drm_dp_i2c_do_msg(aux, &msg);
+                       err = drm_dp_i2c_drain_msg(aux, &msg);
                        if (err < 0)
                                break;
+                       transfer_size = err;
                }
                if (err < 0)
                        break;
index 9a5b68717ec8c31fbd27bfa313833b568444fce9..132581ca4ad84fff6b25abe13d84af96f0c1c11b 100644 (file)
@@ -733,10 +733,14 @@ static bool check_txmsg_state(struct drm_dp_mst_topology_mgr *mgr,
                              struct drm_dp_sideband_msg_tx *txmsg)
 {
        bool ret;
-       mutex_lock(&mgr->qlock);
+
+       /*
+        * All updates to txmsg->state are protected by mgr->qlock, and the two
+        * cases we check here are terminal states. For those the barriers
+        * provided by the wake_up/wait_event pair are enough.
+        */
        ret = (txmsg->state == DRM_DP_SIDEBAND_TX_RX ||
               txmsg->state == DRM_DP_SIDEBAND_TX_TIMEOUT);
-       mutex_unlock(&mgr->qlock);
        return ret;
 }
 
@@ -1363,12 +1367,13 @@ static int process_single_tx_qlock(struct drm_dp_mst_topology_mgr *mgr,
        return 0;
 }
 
-/* must be called holding qlock */
 static void process_single_down_tx_qlock(struct drm_dp_mst_topology_mgr *mgr)
 {
        struct drm_dp_sideband_msg_tx *txmsg;
        int ret;
 
+       WARN_ON(!mutex_is_locked(&mgr->qlock));
+
        /* construct a chunk from the first msg in the tx_msg queue */
        if (list_empty(&mgr->tx_msg_downq)) {
                mgr->tx_down_in_progress = false;
@@ -2319,6 +2324,19 @@ out:
 }
 EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi);
 
+int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
+{
+       int slots = 0;
+       port = drm_dp_get_validated_port_ref(mgr, port);
+       if (!port)
+               return slots;
+
+       slots = port->vcpi.num_slots;
+       drm_dp_put_port(port);
+       return slots;
+}
+EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots);
+
 /**
  * drm_dp_mst_reset_vcpi_slots() - Reset number of slots to 0 for VCPI
  * @mgr: manager for this port
index d51213464672a9c1b7d3362f355b6ddde29c2403..48f7359e2a6bfed94791c98f78431aab824f7b94 100644 (file)
@@ -70,7 +70,7 @@ void drm_err(const char *format, ...)
        vaf.fmt = format;
        vaf.va = &args;
 
-       printk(KERN_ERR "[" DRM_NAME ":%pf] *ERROR* %pV",
+       printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV",
               __builtin_return_address(0), &vaf);
 
        va_end(args);
index cc0ae047ed3bd8fcc265e38a06d8ec86207deb55..5c1aca443e54f851cf7abeb9679962f3ec96ef29 100644 (file)
@@ -304,7 +304,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
        }
 
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
-       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+       drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
        offset = fbi->var.xoffset * bytes_per_pixel;
        offset += fbi->var.yoffset * fb->pitches[0];
index 1e6a0c760c5df9447852672728739225ce48b63b..309b9476fe965f9a26e852ce3d851b1e64c3fb85 100644 (file)
@@ -1034,23 +1034,45 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
        crtc_count = 0;
        for (i = 0; i < fb_helper->crtc_count; i++) {
                struct drm_display_mode *desired_mode;
-               int x, y;
+               struct drm_mode_set *mode_set;
+               int x, y, j;
+               /* in case of tile group, are we the last tile vert or horiz?
+                * If no tile group you are always the last one both vertically
+                * and horizontally
+                */
+               bool lastv = true, lasth = true;
+
                desired_mode = fb_helper->crtc_info[i].desired_mode;
+               mode_set = &fb_helper->crtc_info[i].mode_set;
+
+               if (!desired_mode)
+                       continue;
+
+               crtc_count++;
+
                x = fb_helper->crtc_info[i].x;
                y = fb_helper->crtc_info[i].y;
-               if (desired_mode) {
-                       if (gamma_size == 0)
-                               gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
-                       if (desired_mode->hdisplay + x < sizes.fb_width)
-                               sizes.fb_width = desired_mode->hdisplay + x;
-                       if (desired_mode->vdisplay + y < sizes.fb_height)
-                               sizes.fb_height = desired_mode->vdisplay + y;
-                       if (desired_mode->hdisplay + x > sizes.surface_width)
-                               sizes.surface_width = desired_mode->hdisplay + x;
-                       if (desired_mode->vdisplay + y > sizes.surface_height)
-                               sizes.surface_height = desired_mode->vdisplay + y;
-                       crtc_count++;
+
+               if (gamma_size == 0)
+                       gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
+
+               sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
+               sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
+
+               for (j = 0; j < mode_set->num_connectors; j++) {
+                       struct drm_connector *connector = mode_set->connectors[j];
+                       if (connector->has_tile) {
+                               lasth = (connector->tile_h_loc == (connector->num_h_tile - 1));
+                               lastv = (connector->tile_v_loc == (connector->num_v_tile - 1));
+                               /* cloning to multiple tiles is just crazy-talk, so: */
+                               break;
+                       }
                }
+
+               if (lasth)
+                       sizes.fb_width  = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
+               if (lastv)
+                       sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
        }
 
        if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
@@ -1261,12 +1283,12 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
                                                      int width, int height)
 {
        struct drm_cmdline_mode *cmdline_mode;
-       struct drm_display_mode *mode = NULL;
+       struct drm_display_mode *mode;
        bool prefer_non_interlace;
 
        cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
        if (cmdline_mode->specified == false)
-               return mode;
+               return NULL;
 
        /* attempt to find a matching mode in the list of modes
         *  we have gotten so far, if not add a CVT mode that conforms
@@ -1275,7 +1297,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
                goto create_mode;
 
        prefer_non_interlace = !cmdline_mode->interlace;
- again:
+again:
        list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
                /* check width/height */
                if (mode->hdisplay != cmdline_mode->xres ||
index f1b32f91d94163bcdca46a6ee5f29bd789e23336..cbb4fc0fc969ee2236e112cbb5974742ceffc191 100644 (file)
@@ -37,6 +37,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_gem.h>
 
+#include "drm_internal.h"
 #include "drm_legacy.h"
 
 /**
index 2f4c4343dfa32f5a3f2c81e83a67f9409a31e11f..aa8bbb460c5715a619988d6d4350b4a4507173f8 100644 (file)
@@ -1016,7 +1016,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
        return 0;
 }
 
-drm_ioctl_compat_t *drm_compat_ioctls[] = {
+static drm_ioctl_compat_t *drm_compat_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version,
        [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique,
        [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP32)] = compat_drm_getmap,
index 3785d66721f2f6fdba2d134ba8eaa0c9ab8fb416..266dcd6cdf3bf3ad1d487ad70110496b294e5491 100644 (file)
@@ -321,6 +321,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
                else
                        req->value = 64;
                break;
+       case DRM_CAP_ADDFB2_MODIFIERS:
+               req->value = dev->mode_config.allow_fb_modifiers;
+               break;
        default:
                return -EINVAL;
        }
@@ -521,8 +524,13 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
        return 0;
 }
 
-#define DRM_IOCTL_DEF(ioctl, _func, _flags) \
-       [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl}
+#define DRM_IOCTL_DEF(ioctl, _func, _flags)    \
+       [DRM_IOCTL_NR(ioctl)] = {               \
+               .cmd = ioctl,                   \
+               .func = _func,                  \
+               .flags = _flags,                \
+               .name = #ioctl                  \
+       }
 
 /** Ioctl table */
 static const struct drm_ioctl_desc drm_ioctls[] = {
@@ -660,39 +668,29 @@ long drm_ioctl(struct file *filp,
        int retcode = -EINVAL;
        char stack_kdata[128];
        char *kdata = NULL;
-       unsigned int usize, asize;
+       unsigned int usize, asize, drv_size;
 
        dev = file_priv->minor->dev;
 
        if (drm_device_is_unplugged(dev))
                return -ENODEV;
 
-       if ((nr >= DRM_CORE_IOCTL_COUNT) &&
-           ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
-               goto err_i1;
-       if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) &&
-           (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) {
-               u32 drv_size;
+       if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END) {
+               /* driver ioctl */
+               if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
+                       goto err_i1;
                ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
-               drv_size = _IOC_SIZE(ioctl->cmd_drv);
-               usize = asize = _IOC_SIZE(cmd);
-               if (drv_size > asize)
-                       asize = drv_size;
-               cmd = ioctl->cmd_drv;
-       }
-       else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
-               u32 drv_size;
-
+       } else {
+               /* core ioctl */
+               if (nr >= DRM_CORE_IOCTL_COUNT)
+                       goto err_i1;
                ioctl = &drm_ioctls[nr];
+       }
 
-               drv_size = _IOC_SIZE(ioctl->cmd);
-               usize = asize = _IOC_SIZE(cmd);
-               if (drv_size > asize)
-                       asize = drv_size;
-
-               cmd = ioctl->cmd;
-       } else
-               goto err_i1;
+       drv_size = _IOC_SIZE(ioctl->cmd);
+       usize = _IOC_SIZE(cmd);
+       asize = max(usize, drv_size);
+       cmd = ioctl->cmd;
 
        DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
                  task_pid_nr(current),
@@ -773,12 +771,13 @@ EXPORT_SYMBOL(drm_ioctl);
  */
 bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
 {
-       if ((nr >= DRM_COMMAND_END && nr < DRM_CORE_IOCTL_COUNT) ||
-           (nr < DRM_COMMAND_BASE)) {
-               *flags = drm_ioctls[nr].flags;
-               return true;
-       }
+       if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END)
+               return false;
+
+       if (nr >= DRM_CORE_IOCTL_COUNT)
+               return false;
 
-       return false;
+       *flags = drm_ioctls[nr].flags;
+       return true;
 }
 EXPORT_SYMBOL(drm_ioctl_flags);
index 10574a0c3a55127cae5fb3e90d7b309defdcc681..c8a34476570a4e95bd1c2abb67660fa5f5b57620 100644 (file)
@@ -276,7 +276,6 @@ static void vblank_disable_fn(unsigned long arg)
 void drm_vblank_cleanup(struct drm_device *dev)
 {
        int crtc;
-       unsigned long irqflags;
 
        /* Bail if the driver didn't call drm_vblank_init() */
        if (dev->num_crtcs == 0)
@@ -285,11 +284,10 @@ void drm_vblank_cleanup(struct drm_device *dev)
        for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
                struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
 
-               del_timer_sync(&vblank->disable_timer);
+               WARN_ON(vblank->enabled &&
+                       drm_core_check_feature(dev, DRIVER_MODESET));
 
-               spin_lock_irqsave(&dev->vbl_lock, irqflags);
-               vblank_disable_and_save(dev, crtc);
-               spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+               del_timer_sync(&vblank->disable_timer);
        }
 
        kfree(dev->vblank);
@@ -475,17 +473,23 @@ int drm_irq_uninstall(struct drm_device *dev)
        dev->irq_enabled = false;
 
        /*
-        * Wake up any waiters so they don't hang.
+        * Wake up any waiters so they don't hang. This is just to paper over
+        * isssues for UMS drivers which aren't in full control of their
+        * vblank/irq handling. KMS drivers must ensure that vblanks are all
+        * disabled when uninstalling the irq handler.
         */
        if (dev->num_crtcs) {
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
                for (i = 0; i < dev->num_crtcs; i++) {
                        struct drm_vblank_crtc *vblank = &dev->vblank[i];
 
+                       if (!vblank->enabled)
+                               continue;
+
+                       WARN_ON(drm_core_check_feature(dev, DRIVER_MODESET));
+
+                       vblank_disable_and_save(dev, i);
                        wake_up(&vblank->queue);
-                       vblank->enabled = false;
-                       vblank->last =
-                               dev->driver->get_vblank_counter(dev, i);
                }
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
        }
@@ -1052,7 +1056,7 @@ EXPORT_SYMBOL(drm_vblank_get);
  * Acquire a reference count on vblank events to avoid having them disabled
  * while in use.
  *
- * This is the native kms version of drm_vblank_off().
+ * This is the native kms version of drm_vblank_get().
  *
  * Returns:
  * Zero on success, nonzero on failure.
@@ -1232,6 +1236,38 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_vblank_off);
 
+/**
+ * drm_crtc_vblank_reset - reset vblank state to off on a CRTC
+ * @crtc: CRTC in question
+ *
+ * Drivers can use this function to reset the vblank state to off at load time.
+ * Drivers should use this together with the drm_crtc_vblank_off() and
+ * drm_crtc_vblank_on() functions. The difference compared to
+ * drm_crtc_vblank_off() is that this function doesn't save the vblank counter
+ * and hence doesn't need to call any driver hooks.
+ */
+void drm_crtc_vblank_reset(struct drm_crtc *drm_crtc)
+{
+       struct drm_device *dev = drm_crtc->dev;
+       unsigned long irqflags;
+       int crtc = drm_crtc_index(drm_crtc);
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+
+       spin_lock_irqsave(&dev->vbl_lock, irqflags);
+       /*
+        * Prevent subsequent drm_vblank_get() from enabling the vblank
+        * interrupt by bumping the refcount.
+        */
+       if (!vblank->inmodeset) {
+               atomic_inc(&vblank->refcount);
+               vblank->inmodeset = 1;
+       }
+       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
+       WARN_ON(!list_empty(&dev->vblank_event_list));
+}
+EXPORT_SYMBOL(drm_crtc_vblank_reset);
+
 /**
  * drm_vblank_on - enable vblank events on a CRTC
  * @dev: DRM device
@@ -1653,7 +1689,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
        struct timeval tvblank;
        unsigned long irqflags;
 
-       if (!dev->num_crtcs)
+       if (WARN_ON_ONCE(!dev->num_crtcs))
                return false;
 
        if (WARN_ON(crtc >= dev->num_crtcs))
index 04a209e2b66d7d61428398bb5b58b2222ec2a712..1134526286c819c87bc523a1b8852dc485804046 100644 (file)
  */
 
 static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
-                                               unsigned long size,
+                                               u64 size,
                                                unsigned alignment,
                                                unsigned long color,
                                                enum drm_mm_search_flags flags);
 static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
-                                               unsigned long size,
+                                               u64 size,
                                                unsigned alignment,
                                                unsigned long color,
-                                               unsigned long start,
-                                               unsigned long end,
+                                               u64 start,
+                                               u64 end,
                                                enum drm_mm_search_flags flags);
 
 static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
                                 struct drm_mm_node *node,
-                                unsigned long size, unsigned alignment,
+                                u64 size, unsigned alignment,
                                 unsigned long color,
                                 enum drm_mm_allocator_flags flags)
 {
        struct drm_mm *mm = hole_node->mm;
-       unsigned long hole_start = drm_mm_hole_node_start(hole_node);
-       unsigned long hole_end = drm_mm_hole_node_end(hole_node);
-       unsigned long adj_start = hole_start;
-       unsigned long adj_end = hole_end;
+       u64 hole_start = drm_mm_hole_node_start(hole_node);
+       u64 hole_end = drm_mm_hole_node_end(hole_node);
+       u64 adj_start = hole_start;
+       u64 adj_end = hole_end;
 
        BUG_ON(node->allocated);
 
@@ -124,12 +124,15 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
                adj_start = adj_end - size;
 
        if (alignment) {
-               unsigned tmp = adj_start % alignment;
-               if (tmp) {
+               u64 tmp = adj_start;
+               unsigned rem;
+
+               rem = do_div(tmp, alignment);
+               if (rem) {
                        if (flags & DRM_MM_CREATE_TOP)
-                               adj_start -= tmp;
+                               adj_start -= rem;
                        else
-                               adj_start += alignment - tmp;
+                               adj_start += alignment - rem;
                }
        }
 
@@ -176,9 +179,9 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
 int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
 {
        struct drm_mm_node *hole;
-       unsigned long end = node->start + node->size;
-       unsigned long hole_start;
-       unsigned long hole_end;
+       u64 end = node->start + node->size;
+       u64 hole_start;
+       u64 hole_end;
 
        BUG_ON(node == NULL);
 
@@ -227,7 +230,7 @@ EXPORT_SYMBOL(drm_mm_reserve_node);
  * 0 on success, -ENOSPC if there's no suitable hole.
  */
 int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
-                              unsigned long size, unsigned alignment,
+                              u64 size, unsigned alignment,
                               unsigned long color,
                               enum drm_mm_search_flags sflags,
                               enum drm_mm_allocator_flags aflags)
@@ -246,16 +249,16 @@ EXPORT_SYMBOL(drm_mm_insert_node_generic);
 
 static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
                                       struct drm_mm_node *node,
-                                      unsigned long size, unsigned alignment,
+                                      u64 size, unsigned alignment,
                                       unsigned long color,
-                                      unsigned long start, unsigned long end,
+                                      u64 start, u64 end,
                                       enum drm_mm_allocator_flags flags)
 {
        struct drm_mm *mm = hole_node->mm;
-       unsigned long hole_start = drm_mm_hole_node_start(hole_node);
-       unsigned long hole_end = drm_mm_hole_node_end(hole_node);
-       unsigned long adj_start = hole_start;
-       unsigned long adj_end = hole_end;
+       u64 hole_start = drm_mm_hole_node_start(hole_node);
+       u64 hole_end = drm_mm_hole_node_end(hole_node);
+       u64 adj_start = hole_start;
+       u64 adj_end = hole_end;
 
        BUG_ON(!hole_node->hole_follows || node->allocated);
 
@@ -271,12 +274,15 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
                mm->color_adjust(hole_node, color, &adj_start, &adj_end);
 
        if (alignment) {
-               unsigned tmp = adj_start % alignment;
-               if (tmp) {
+               u64 tmp = adj_start;
+               unsigned rem;
+
+               rem = do_div(tmp, alignment);
+               if (rem) {
                        if (flags & DRM_MM_CREATE_TOP)
-                               adj_start -= tmp;
+                               adj_start -= rem;
                        else
-                               adj_start += alignment - tmp;
+                               adj_start += alignment - rem;
                }
        }
 
@@ -324,9 +330,9 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
  * 0 on success, -ENOSPC if there's no suitable hole.
  */
 int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node,
-                                       unsigned long size, unsigned alignment,
+                                       u64 size, unsigned alignment,
                                        unsigned long color,
-                                       unsigned long start, unsigned long end,
+                                       u64 start, u64 end,
                                        enum drm_mm_search_flags sflags,
                                        enum drm_mm_allocator_flags aflags)
 {
@@ -387,32 +393,34 @@ void drm_mm_remove_node(struct drm_mm_node *node)
 }
 EXPORT_SYMBOL(drm_mm_remove_node);
 
-static int check_free_hole(unsigned long start, unsigned long end,
-                          unsigned long size, unsigned alignment)
+static int check_free_hole(u64 start, u64 end, u64 size, unsigned alignment)
 {
        if (end - start < size)
                return 0;
 
        if (alignment) {
-               unsigned tmp = start % alignment;
-               if (tmp)
-                       start += alignment - tmp;
+               u64 tmp = start;
+               unsigned rem;
+
+               rem = do_div(tmp, alignment);
+               if (rem)
+                       start += alignment - rem;
        }
 
        return end >= start + size;
 }
 
 static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
-                                                     unsigned long size,
+                                                     u64 size,
                                                      unsigned alignment,
                                                      unsigned long color,
                                                      enum drm_mm_search_flags flags)
 {
        struct drm_mm_node *entry;
        struct drm_mm_node *best;
-       unsigned long adj_start;
-       unsigned long adj_end;
-       unsigned long best_size;
+       u64 adj_start;
+       u64 adj_end;
+       u64 best_size;
 
        BUG_ON(mm->scanned_blocks);
 
@@ -421,7 +429,7 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
 
        __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
                               flags & DRM_MM_SEARCH_BELOW) {
-               unsigned long hole_size = adj_end - adj_start;
+               u64 hole_size = adj_end - adj_start;
 
                if (mm->color_adjust) {
                        mm->color_adjust(entry, color, &adj_start, &adj_end);
@@ -445,18 +453,18 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
 }
 
 static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
-                                                       unsigned long size,
+                                                       u64 size,
                                                        unsigned alignment,
                                                        unsigned long color,
-                                                       unsigned long start,
-                                                       unsigned long end,
+                                                       u64 start,
+                                                       u64 end,
                                                        enum drm_mm_search_flags flags)
 {
        struct drm_mm_node *entry;
        struct drm_mm_node *best;
-       unsigned long adj_start;
-       unsigned long adj_end;
-       unsigned long best_size;
+       u64 adj_start;
+       u64 adj_end;
+       u64 best_size;
 
        BUG_ON(mm->scanned_blocks);
 
@@ -465,7 +473,7 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
 
        __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
                               flags & DRM_MM_SEARCH_BELOW) {
-               unsigned long hole_size = adj_end - adj_start;
+               u64 hole_size = adj_end - adj_start;
 
                if (adj_start < start)
                        adj_start = start;
@@ -561,7 +569,7 @@ EXPORT_SYMBOL(drm_mm_replace_node);
  * adding/removing nodes to/from the scan list are allowed.
  */
 void drm_mm_init_scan(struct drm_mm *mm,
-                     unsigned long size,
+                     u64 size,
                      unsigned alignment,
                      unsigned long color)
 {
@@ -594,11 +602,11 @@ EXPORT_SYMBOL(drm_mm_init_scan);
  * adding/removing nodes to/from the scan list are allowed.
  */
 void drm_mm_init_scan_with_range(struct drm_mm *mm,
-                                unsigned long size,
+                                u64 size,
                                 unsigned alignment,
                                 unsigned long color,
-                                unsigned long start,
-                                unsigned long end)
+                                u64 start,
+                                u64 end)
 {
        mm->scan_color = color;
        mm->scan_alignment = alignment;
@@ -627,8 +635,8 @@ bool drm_mm_scan_add_block(struct drm_mm_node *node)
 {
        struct drm_mm *mm = node->mm;
        struct drm_mm_node *prev_node;
-       unsigned long hole_start, hole_end;
-       unsigned long adj_start, adj_end;
+       u64 hole_start, hole_end;
+       u64 adj_start, adj_end;
 
        mm->scanned_blocks++;
 
@@ -731,7 +739,7 @@ EXPORT_SYMBOL(drm_mm_clean);
  *
  * Note that @mm must be cleared to 0 before calling this function.
  */
-void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
+void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
 {
        INIT_LIST_HEAD(&mm->hole_stack);
        mm->scanned_blocks = 0;
@@ -766,18 +774,17 @@ void drm_mm_takedown(struct drm_mm * mm)
 }
 EXPORT_SYMBOL(drm_mm_takedown);
 
-static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
-                                      const char *prefix)
+static u64 drm_mm_debug_hole(struct drm_mm_node *entry,
+                                    const char *prefix)
 {
-       unsigned long hole_start, hole_end, hole_size;
+       u64 hole_start, hole_end, hole_size;
 
        if (entry->hole_follows) {
                hole_start = drm_mm_hole_node_start(entry);
                hole_end = drm_mm_hole_node_end(entry);
                hole_size = hole_end - hole_start;
-               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
-                       prefix, hole_start, hole_end,
-                       hole_size);
+               pr_debug("%s %#llx-%#llx: %llu: free\n", prefix, hole_start,
+                        hole_end, hole_size);
                return hole_size;
        }
 
@@ -792,35 +799,34 @@ static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
 void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
 {
        struct drm_mm_node *entry;
-       unsigned long total_used = 0, total_free = 0, total = 0;
+       u64 total_used = 0, total_free = 0, total = 0;
 
        total_free += drm_mm_debug_hole(&mm->head_node, prefix);
 
        drm_mm_for_each_node(entry, mm) {
-               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n",
-                       prefix, entry->start, entry->start + entry->size,
-                       entry->size);
+               pr_debug("%s %#llx-%#llx: %llu: used\n", prefix, entry->start,
+                        entry->start + entry->size, entry->size);
                total_used += entry->size;
                total_free += drm_mm_debug_hole(entry, prefix);
        }
        total = total_free + total_used;
 
-       printk(KERN_DEBUG "%s total: %lu, used %lu free %lu\n", prefix, total,
-               total_used, total_free);
+       pr_debug("%s total: %llu, used %llu free %llu\n", prefix, total,
+                total_used, total_free);
 }
 EXPORT_SYMBOL(drm_mm_debug_table);
 
 #if defined(CONFIG_DEBUG_FS)
-static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
+static u64 drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
 {
-       unsigned long hole_start, hole_end, hole_size;
+       u64 hole_start, hole_end, hole_size;
 
        if (entry->hole_follows) {
                hole_start = drm_mm_hole_node_start(entry);
                hole_end = drm_mm_hole_node_end(entry);
                hole_size = hole_end - hole_start;
-               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
-                               hole_start, hole_end, hole_size);
+               seq_printf(m, "%#llx-%#llx: %llu: free\n", hole_start,
+                          hole_end, hole_size);
                return hole_size;
        }
 
@@ -835,20 +841,20 @@ static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *en
 int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
 {
        struct drm_mm_node *entry;
-       unsigned long total_used = 0, total_free = 0, total = 0;
+       u64 total_used = 0, total_free = 0, total = 0;
 
        total_free += drm_mm_dump_hole(m, &mm->head_node);
 
        drm_mm_for_each_node(entry, mm) {
-               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n",
-                               entry->start, entry->start + entry->size,
-                               entry->size);
+               seq_printf(m, "%#016llx-%#016llx: %llu: used\n", entry->start,
+                          entry->start + entry->size, entry->size);
                total_used += entry->size;
                total_free += drm_mm_dump_hole(m, entry);
        }
        total = total_free + total_used;
 
-       seq_printf(m, "total: %lu, used %lu free %lu\n", total, total_used, total_free);
+       seq_printf(m, "total: %llu, used %llu free %llu\n", total,
+                  total_used, total_free);
        return 0;
 }
 EXPORT_SYMBOL(drm_mm_dump_table);
index 487d0e35c134d1fde06338be6c913da66abfa123..213b11ea69b5b7ecc6309cdbde007d46e0319144 100644 (file)
@@ -278,7 +278,7 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
                hblank = drm_mode->hdisplay * hblank_percentage /
                         (100 * HV_FACTOR - hblank_percentage);
                hblank -= hblank % (2 * CVT_H_GRANULARITY);
-               /* 14. find the total pixes per line */
+               /* 14. find the total pixels per line */
                drm_mode->htotal = drm_mode->hdisplay + hblank;
                drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
                drm_mode->hsync_start = drm_mode->hsync_end -
@@ -903,6 +903,12 @@ EXPORT_SYMBOL(drm_mode_duplicate);
  */
 bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
 {
+       if (!mode1 && !mode2)
+               return true;
+
+       if (!mode1 || !mode2)
+               return false;
+
        /* do clock check convert to PICOS so fb modes get matched
         * the same */
        if (mode1->clock && mode2->clock) {
@@ -1148,7 +1154,7 @@ EXPORT_SYMBOL(drm_mode_sort);
 /**
  * drm_mode_connector_list_update - update the mode list for the connector
  * @connector: the connector to update
- * @merge_type_bits: whether to merge or overright type bits.
+ * @merge_type_bits: whether to merge or overwrite type bits
  *
  * This moves the modes from the @connector probed_modes list
  * to the actual mode list. It compares the probed mode against the current
@@ -1209,7 +1215,7 @@ EXPORT_SYMBOL(drm_mode_connector_list_update);
  *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
  *
  * The intermediate drm_cmdline_mode structure is required to store additional
- * options from the command line modline like the force-enabel/disable flag.
+ * options from the command line modline like the force-enable/disable flag.
  *
  * Returns:
  * True if a valid modeline has been parsed, false otherwise.
index fd29f03645b8e465b42add64384b339c13229dc2..1b1bd42b03687683202eb600425c5d7e582c61ad 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
 #include <drm/drmP.h>
+#include "drm_internal.h"
 #include "drm_legacy.h"
 
 /**
index 5ba5792bfdbabd920b5678740a1930f1d90ace2b..33807e0adac71d9e28e4747dfd26d8a5219cf71a 100644 (file)
@@ -344,20 +344,7 @@ const struct drm_plane_funcs drm_primary_helper_funcs = {
 };
 EXPORT_SYMBOL(drm_primary_helper_funcs);
 
-/**
- * drm_primary_helper_create_plane() - Create a generic primary plane
- * @dev: drm device
- * @formats: pixel formats supported, or NULL for a default safe list
- * @num_formats: size of @formats; ignored if @formats is NULL
- *
- * Allocates and initializes a primary plane that can be used with the primary
- * plane helpers.  Drivers that wish to use driver-specific plane structures or
- * provide custom handler functions may perform their own allocation and
- * initialization rather than calling this function.
- */
-struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
-                                                 const uint32_t *formats,
-                                                 int num_formats)
+static struct drm_plane *create_primary_plane(struct drm_device *dev)
 {
        struct drm_plane *primary;
        int ret;
@@ -368,15 +355,17 @@ struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
                return NULL;
        }
 
-       if (formats == NULL) {
-               formats = safe_modeset_formats;
-               num_formats = ARRAY_SIZE(safe_modeset_formats);
-       }
+       /*
+        * Remove the format_default field from drm_plane when dropping
+        * this helper.
+        */
+       primary->format_default = true;
 
        /* possible_crtc's will be filled in later by crtc_init */
        ret = drm_universal_plane_init(dev, primary, 0,
                                       &drm_primary_helper_funcs,
-                                      formats, num_formats,
+                                      safe_modeset_formats,
+                                      ARRAY_SIZE(safe_modeset_formats),
                                       DRM_PLANE_TYPE_PRIMARY);
        if (ret) {
                kfree(primary);
@@ -385,7 +374,6 @@ struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
 
        return primary;
 }
-EXPORT_SYMBOL(drm_primary_helper_create_plane);
 
 /**
  * drm_crtc_init - Legacy CRTC initialization function
@@ -404,7 +392,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 {
        struct drm_plane *primary;
 
-       primary = drm_primary_helper_create_plane(dev, NULL, 0);
+       primary = create_primary_plane(dev);
        return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
 }
 EXPORT_SYMBOL(drm_crtc_init);
@@ -437,7 +425,8 @@ int drm_plane_helper_commit(struct drm_plane *plane,
 
        if (plane_funcs->prepare_fb && plane_state->fb &&
            plane_state->fb != old_fb) {
-               ret = plane_funcs->prepare_fb(plane, plane_state->fb);
+               ret = plane_funcs->prepare_fb(plane, plane_state->fb,
+                                             plane_state);
                if (ret)
                        goto out;
        }
@@ -487,7 +476,7 @@ int drm_plane_helper_commit(struct drm_plane *plane,
        }
 
        if (plane_funcs->cleanup_fb && old_fb)
-               plane_funcs->cleanup_fb(plane, old_fb);
+               plane_funcs->cleanup_fb(plane, old_fb, plane_state);
 out:
        if (plane_state) {
                if (plane->funcs->atomic_destroy_state)
index 5c99d3773212a92928fb31c2b198f440a6e6a0b4..ffc305fc20768c29af6883eeb2d70553839cfa6e 100644 (file)
@@ -166,23 +166,68 @@ void drm_sysfs_destroy(void)
 /*
  * Connector properties
  */
-static ssize_t status_show(struct device *device,
+static ssize_t status_store(struct device *device,
                           struct device_attribute *attr,
-                          char *buf)
+                          const char *buf, size_t count)
 {
        struct drm_connector *connector = to_drm_connector(device);
-       enum drm_connector_status status;
+       struct drm_device *dev = connector->dev;
+       enum drm_connector_status old_status;
        int ret;
 
-       ret = mutex_lock_interruptible(&connector->dev->mode_config.mutex);
+       ret = mutex_lock_interruptible(&dev->mode_config.mutex);
        if (ret)
                return ret;
 
-       status = connector->funcs->detect(connector, true);
-       mutex_unlock(&connector->dev->mode_config.mutex);
+       old_status = connector->status;
+
+       if (sysfs_streq(buf, "detect")) {
+               connector->force = 0;
+               connector->status = connector->funcs->detect(connector, true);
+       } else if (sysfs_streq(buf, "on")) {
+               connector->force = DRM_FORCE_ON;
+       } else if (sysfs_streq(buf, "on-digital")) {
+               connector->force = DRM_FORCE_ON_DIGITAL;
+       } else if (sysfs_streq(buf, "off")) {
+               connector->force = DRM_FORCE_OFF;
+       } else
+               ret = -EINVAL;
+
+       if (ret == 0 && connector->force) {
+               if (connector->force == DRM_FORCE_ON ||
+                   connector->force == DRM_FORCE_ON_DIGITAL)
+                       connector->status = connector_status_connected;
+               else
+                       connector->status = connector_status_disconnected;
+               if (connector->funcs->force)
+                       connector->funcs->force(connector);
+       }
+
+       if (old_status != connector->status) {
+               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+                             connector->base.id,
+                             connector->name,
+                             old_status, connector->status);
+
+               dev->mode_config.delayed_event = true;
+               if (dev->mode_config.poll_enabled)
+                       schedule_delayed_work(&dev->mode_config.output_poll_work,
+                                             0);
+       }
+
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
+static ssize_t status_show(struct device *device,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       struct drm_connector *connector = to_drm_connector(device);
 
        return snprintf(buf, PAGE_SIZE, "%s\n",
-                       drm_get_connector_status_name(status));
+                       drm_get_connector_status_name(connector->status));
 }
 
 static ssize_t dpms_show(struct device *device,
@@ -339,7 +384,7 @@ static ssize_t select_subconnector_show(struct device *device,
                        drm_get_dvi_i_select_name((int)subconnector));
 }
 
-static DEVICE_ATTR_RO(status);
+static DEVICE_ATTR_RW(status);
 static DEVICE_ATTR_RO(enabled);
 static DEVICE_ATTR_RO(dpms);
 static DEVICE_ATTR_RO(modes);
index 4a2c328959e59348ef7ee5f4bb0797835cd92ba5..aab49ee4ed40d2ce5b525554209fd3ffe40340b4 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #endif
 #include <asm/pgtable.h>
+#include "drm_internal.h"
 #include "drm_legacy.h"
 
 struct drm_vma_entry {
index a5e74612100e4ea02de3ab01ffceef42d8f2f61d..0a6780367d28689f907a4b750f1ee5fc2ef403d9 100644 (file)
@@ -50,7 +50,7 @@ config DRM_EXYNOS_DSI
 
 config DRM_EXYNOS_DP
        bool "EXYNOS DRM DP driver support"
-       depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
+       depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
        default DRM_EXYNOS
        select DRM_PANEL
        help
index 63f02e2380ae1a24746ed87153a1703491f23dff..970046199608484365195ecdd78d27fecc57ed4b 100644 (file)
@@ -888,8 +888,8 @@ static int decon_probe(struct platform_device *pdev)
        of_node_put(i80_if_timings);
 
        ctx->regs = of_iomap(dev->of_node, 0);
-       if (IS_ERR(ctx->regs)) {
-               ret = PTR_ERR(ctx->regs);
+       if (!ctx->regs) {
+               ret = -ENOMEM;
                goto err_del_component;
        }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
deleted file mode 100644 (file)
index ba9b3d5..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *     Inki Dae <inki.dae@samsung.com>
- *     Joonyoung Shim <jy0922.shim@samsung.com>
- *     Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-
-#include <drm/exynos_drm.h>
-#include "exynos_drm_drv.h"
-#include "exynos_drm_encoder.h"
-#include "exynos_drm_connector.h"
-
-#define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
-                               drm_connector)
-
-struct exynos_drm_connector {
-       struct drm_connector            drm_connector;
-       uint32_t                        encoder_id;
-       struct exynos_drm_display       *display;
-};
-
-static int exynos_drm_connector_get_modes(struct drm_connector *connector)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       struct edid *edid = NULL;
-       unsigned int count = 0;
-       int ret;
-
-       /*
-        * if get_edid() exists then get_edid() callback of hdmi side
-        * is called to get edid data through i2c interface else
-        * get timing from the FIMD driver(display controller).
-        *
-        * P.S. in case of lcd panel, count is always 1 if success
-        * because lcd panel has only one mode.
-        */
-       if (display->ops->get_edid) {
-               edid = display->ops->get_edid(display, connector);
-               if (IS_ERR_OR_NULL(edid)) {
-                       ret = PTR_ERR(edid);
-                       edid = NULL;
-                       DRM_ERROR("Panel operation get_edid failed %d\n", ret);
-                       goto out;
-               }
-
-               count = drm_add_edid_modes(connector, edid);
-               if (!count) {
-                       DRM_ERROR("Add edid modes failed %d\n", count);
-                       goto out;
-               }
-
-               drm_mode_connector_update_edid_property(connector, edid);
-       } else {
-               struct exynos_drm_panel_info *panel;
-               struct drm_display_mode *mode = drm_mode_create(connector->dev);
-               if (!mode) {
-                       DRM_ERROR("failed to create a new display mode.\n");
-                       return 0;
-               }
-
-               if (display->ops->get_panel)
-                       panel = display->ops->get_panel(display);
-               else {
-                       drm_mode_destroy(connector->dev, mode);
-                       return 0;
-               }
-
-               drm_display_mode_from_videomode(&panel->vm, mode);
-               mode->width_mm = panel->width_mm;
-               mode->height_mm = panel->height_mm;
-               connector->display_info.width_mm = mode->width_mm;
-               connector->display_info.height_mm = mode->height_mm;
-
-               mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-               drm_mode_set_name(mode);
-               drm_mode_probed_add(connector, mode);
-
-               count = 1;
-       }
-
-out:
-       kfree(edid);
-       return count;
-}
-
-static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
-                                           struct drm_display_mode *mode)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       int ret = MODE_BAD;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (display->ops->check_mode)
-               if (!display->ops->check_mode(display, mode))
-                       ret = MODE_OK;
-
-       return ret;
-}
-
-static struct drm_encoder *exynos_drm_best_encoder(
-               struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       return drm_encoder_find(dev, exynos_connector->encoder_id);
-}
-
-static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
-       .get_modes      = exynos_drm_connector_get_modes,
-       .mode_valid     = exynos_drm_connector_mode_valid,
-       .best_encoder   = exynos_drm_best_encoder,
-};
-
-static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
-                               unsigned int max_width, unsigned int max_height)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       unsigned int width, height;
-
-       width = max_width;
-       height = max_height;
-
-       /*
-        * if specific driver want to find desired_mode using maxmum
-        * resolution then get max width and height from that driver.
-        */
-       if (display->ops->get_max_resol)
-               display->ops->get_max_resol(display, &width, &height);
-
-       return drm_helper_probe_single_connector_modes(connector, width,
-                                                       height);
-}
-
-/* get detection status of display device. */
-static enum drm_connector_status
-exynos_drm_connector_detect(struct drm_connector *connector, bool force)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       enum drm_connector_status status = connector_status_disconnected;
-
-       if (display->ops->is_connected) {
-               if (display->ops->is_connected(display))
-                       status = connector_status_connected;
-               else
-                       status = connector_status_disconnected;
-       }
-
-       return status;
-}
-
-static void exynos_drm_connector_destroy(struct drm_connector *connector)
-{
-       struct exynos_drm_connector *exynos_connector =
-               to_exynos_connector(connector);
-
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
-       kfree(exynos_connector);
-}
-
-static struct drm_connector_funcs exynos_connector_funcs = {
-       .dpms           = drm_helper_connector_dpms,
-       .fill_modes     = exynos_drm_connector_fill_modes,
-       .detect         = exynos_drm_connector_detect,
-       .destroy        = exynos_drm_connector_destroy,
-};
-
-struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
-                                                  struct drm_encoder *encoder)
-{
-       struct exynos_drm_connector *exynos_connector;
-       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
-       struct drm_connector *connector;
-       int type;
-       int err;
-
-       exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
-       if (!exynos_connector)
-               return NULL;
-
-       connector = &exynos_connector->drm_connector;
-
-       switch (display->type) {
-       case EXYNOS_DISPLAY_TYPE_HDMI:
-               type = DRM_MODE_CONNECTOR_HDMIA;
-               connector->interlace_allowed = true;
-               connector->polled = DRM_CONNECTOR_POLL_HPD;
-               break;
-       case EXYNOS_DISPLAY_TYPE_VIDI:
-               type = DRM_MODE_CONNECTOR_VIRTUAL;
-               connector->polled = DRM_CONNECTOR_POLL_HPD;
-               break;
-       default:
-               type = DRM_MODE_CONNECTOR_Unknown;
-               break;
-       }
-
-       drm_connector_init(dev, connector, &exynos_connector_funcs, type);
-       drm_connector_helper_add(connector, &exynos_connector_helper_funcs);
-
-       err = drm_connector_register(connector);
-       if (err)
-               goto err_connector;
-
-       exynos_connector->encoder_id = encoder->base.id;
-       exynos_connector->display = display;
-       connector->dpms = DRM_MODE_DPMS_OFF;
-       connector->encoder = encoder;
-
-       err = drm_mode_connector_attach_encoder(connector, encoder);
-       if (err) {
-               DRM_ERROR("failed to attach a connector to a encoder\n");
-               goto err_sysfs;
-       }
-
-       DRM_DEBUG_KMS("connector has been created\n");
-
-       return connector;
-
-err_sysfs:
-       drm_connector_unregister(connector);
-err_connector:
-       drm_connector_cleanup(connector);
-       kfree(exynos_connector);
-       return NULL;
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h
deleted file mode 100644 (file)
index 4eb20d7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *     Inki Dae <inki.dae@samsung.com>
- *     Joonyoung Shim <jy0922.shim@samsung.com>
- *     Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DRM_CONNECTOR_H_
-#define _EXYNOS_DRM_CONNECTOR_H_
-
-struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
-                                                  struct drm_encoder *encoder);
-
-#endif
index 84f8dfe1c5ec02ec383b0d74cf615b7906388d9a..e71e331f0188c009f56bffe1fa81b2ec0be29164 100644 (file)
@@ -76,6 +76,7 @@ static struct fb_ops exynos_drm_fb_ops = {
 };
 
 static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
+                                    struct drm_fb_helper_surface_size *sizes,
                                     struct drm_framebuffer *fb)
 {
        struct fb_info *fbi = helper->fbdev;
@@ -85,7 +86,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
        unsigned long offset;
 
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
-       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+       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);
@@ -189,7 +190,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
                goto err_destroy_framebuffer;
        }
 
-       ret = exynos_drm_fbdev_update(helper, helper->fb);
+       ret = exynos_drm_fbdev_update(helper, sizes, helper->fb);
        if (ret < 0)
                goto err_dealloc_cmap;
 
index 925fc69af1a0c28a083171cdba563537ee3741da..c300e22da8ac5f2f4294c27543e62291ee0a8739 100644 (file)
@@ -284,14 +284,9 @@ static void fimd_clear_channel(struct fimd_context *ctx)
        }
 }
 
-static int fimd_ctx_initialize(struct fimd_context *ctx,
+static int fimd_iommu_attach_devices(struct fimd_context *ctx,
                        struct drm_device *drm_dev)
 {
-       struct exynos_drm_private *priv;
-       priv = drm_dev->dev_private;
-
-       ctx->drm_dev = drm_dev;
-       ctx->pipe = priv->pipe++;
 
        /* attach this sub driver to iommu mapping if supported. */
        if (is_drm_iommu_supported(ctx->drm_dev)) {
@@ -313,7 +308,7 @@ static int fimd_ctx_initialize(struct fimd_context *ctx,
        return 0;
 }
 
-static void fimd_ctx_remove(struct fimd_context *ctx)
+static void fimd_iommu_detach_devices(struct fimd_context *ctx)
 {
        /* detach this sub driver from iommu mapping if supported. */
        if (is_drm_iommu_supported(ctx->drm_dev))
@@ -1056,25 +1051,23 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
 {
        struct fimd_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
+       struct exynos_drm_private *priv = drm_dev->dev_private;
        int ret;
 
-       ret = fimd_ctx_initialize(ctx, drm_dev);
-       if (ret) {
-               DRM_ERROR("fimd_ctx_initialize failed.\n");
-               return ret;
-       }
+       ctx->drm_dev = drm_dev;
+       ctx->pipe = priv->pipe++;
 
        ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
                                           EXYNOS_DISPLAY_TYPE_LCD,
                                           &fimd_crtc_ops, ctx);
-       if (IS_ERR(ctx->crtc)) {
-               fimd_ctx_remove(ctx);
-               return PTR_ERR(ctx->crtc);
-       }
 
        if (ctx->display)
                exynos_drm_create_enc_conn(drm_dev, ctx->display);
 
+       ret = fimd_iommu_attach_devices(ctx, drm_dev);
+       if (ret)
+               return ret;
+
        return 0;
 
 }
@@ -1086,10 +1079,10 @@ static void fimd_unbind(struct device *dev, struct device *master,
 
        fimd_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
 
+       fimd_iommu_detach_devices(ctx);
+
        if (ctx->display)
                exynos_dpi_remove(ctx->display);
-
-       fimd_ctx_remove(ctx);
 }
 
 static const struct component_ops fimd_component_ops = {
index a5616872eee7f9defdebe63025b9e92f10060fc7..8ad5b7294eb4801c189fa3b2cdf90ebb24606fd3 100644 (file)
@@ -175,7 +175,7 @@ static int exynos_disable_plane(struct drm_plane *plane)
        struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc);
 
-       if (exynos_crtc->ops->win_disable)
+       if (exynos_crtc && exynos_crtc->ops->win_disable)
                exynos_crtc->ops->win_disable(exynos_crtc,
                                              exynos_plane->zpos);
 
index fa140e04d5fa72f18237054c2b10f23f77355d83..b728523e194f7581b8e9740b7ddb13e6f5606d56 100644 (file)
@@ -27,12 +27,13 @@ struct adv7511 {
        struct regmap *regmap;
        struct regmap *packet_memory_regmap;
        enum drm_connector_status status;
-       int dpms_mode;
+       bool powered;
 
        unsigned int f_tmds;
 
        unsigned int current_edid_segment;
        uint8_t edid_buf[256];
+       bool edid_read;
 
        wait_queue_head_t wq;
        struct drm_encoder *encoder;
@@ -357,6 +358,48 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
        adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
 }
 
+static void adv7511_power_on(struct adv7511 *adv7511)
+{
+       adv7511->current_edid_segment = -1;
+
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
+                    ADV7511_INT0_EDID_READY);
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
+                    ADV7511_INT1_DDC_ERROR);
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+                          ADV7511_POWER_POWER_DOWN, 0);
+
+       /*
+        * Per spec it is allowed to pulse the HDP signal to indicate that the
+        * EDID information has changed. Some monitors do this when they wakeup
+        * from standby or are enabled. When the HDP goes low the adv7511 is
+        * reset and the outputs are disabled which might cause the monitor to
+        * go to standby again. To avoid this we ignore the HDP pin for the
+        * first few seconds after enabling the output.
+        */
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
+                          ADV7511_REG_POWER2_HDP_SRC_MASK,
+                          ADV7511_REG_POWER2_HDP_SRC_NONE);
+
+       /*
+        * Most of the registers are reset during power down or when HPD is low.
+        */
+       regcache_sync(adv7511->regmap);
+
+       adv7511->powered = true;
+}
+
+static void adv7511_power_off(struct adv7511 *adv7511)
+{
+       /* TODO: setup additional power down modes */
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+                          ADV7511_POWER_POWER_DOWN,
+                          ADV7511_POWER_POWER_DOWN);
+       regcache_mark_dirty(adv7511->regmap);
+
+       adv7511->powered = false;
+}
+
 /* -----------------------------------------------------------------------------
  * Interrupt and hotplug detection
  */
@@ -379,69 +422,71 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
        return false;
 }
 
-static irqreturn_t adv7511_irq_handler(int irq, void *devid)
-{
-       struct adv7511 *adv7511 = devid;
-
-       if (adv7511_hpd(adv7511))
-               drm_helper_hpd_irq_event(adv7511->encoder->dev);
-
-       wake_up_all(&adv7511->wq);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int adv7511_is_interrupt_pending(struct adv7511 *adv7511,
-                                                unsigned int irq)
+static int adv7511_irq_process(struct adv7511 *adv7511)
 {
        unsigned int irq0, irq1;
-       unsigned int pending;
        int ret;
 
        ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
        if (ret < 0)
-               return 0;
+               return ret;
+
        ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1);
        if (ret < 0)
-               return 0;
+               return ret;
 
-       pending = (irq1 << 8) | irq0;
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-       return pending & irq;
+       if (irq0 & ADV7511_INT0_HDP)
+               drm_helper_hpd_irq_event(adv7511->encoder->dev);
+
+       if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
+               adv7511->edid_read = true;
+
+               if (adv7511->i2c_main->irq)
+                       wake_up_all(&adv7511->wq);
+       }
+
+       return 0;
 }
 
-static int adv7511_wait_for_interrupt(struct adv7511 *adv7511, int irq,
-                                     int timeout)
+static irqreturn_t adv7511_irq_handler(int irq, void *devid)
+{
+       struct adv7511 *adv7511 = devid;
+       int ret;
+
+       ret = adv7511_irq_process(adv7511);
+       return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * EDID retrieval
+ */
+
+static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
 {
-       unsigned int pending;
        int ret;
 
        if (adv7511->i2c_main->irq) {
                ret = wait_event_interruptible_timeout(adv7511->wq,
-                               adv7511_is_interrupt_pending(adv7511, irq),
-                               msecs_to_jiffies(timeout));
-               if (ret <= 0)
-                       return 0;
-               pending = adv7511_is_interrupt_pending(adv7511, irq);
+                               adv7511->edid_read, msecs_to_jiffies(timeout));
        } else {
-               if (timeout < 25)
-                       timeout = 25;
-               do {
-                       pending = adv7511_is_interrupt_pending(adv7511, irq);
-                       if (pending)
+               for (; timeout > 0; timeout -= 25) {
+                       ret = adv7511_irq_process(adv7511);
+                       if (ret < 0)
                                break;
+
+                       if (adv7511->edid_read)
+                               break;
+
                        msleep(25);
-                       timeout -= 25;
-               } while (timeout >= 25);
+               }
        }
 
-       return pending;
+       return adv7511->edid_read ? 0 : -EIO;
 }
 
-/* -----------------------------------------------------------------------------
- * EDID retrieval
- */
-
 static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
                                  size_t len)
 {
@@ -463,19 +508,14 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
                        return ret;
 
                if (status != 2) {
+                       adv7511->edid_read = false;
                        regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT,
                                     block);
-                       ret = adv7511_wait_for_interrupt(adv7511,
-                                       ADV7511_INT0_EDID_READY |
-                                       ADV7511_INT1_DDC_ERROR, 200);
-
-                       if (!(ret & ADV7511_INT0_EDID_READY))
-                               return -EIO;
+                       ret = adv7511_wait_for_edid(adv7511, 200);
+                       if (ret < 0)
+                               return ret;
                }
 
-               regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-                            ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR);
-
                /* Break this apart, hopefully more I2C controllers will
                 * support 64 byte transfers than 256 byte transfers
                 */
@@ -526,9 +566,11 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
        unsigned int count;
 
        /* Reading the EDID only works if the device is powered */
-       if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) {
+       if (!adv7511->powered) {
                regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-                            ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR);
+                            ADV7511_INT0_EDID_READY);
+               regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
+                            ADV7511_INT1_DDC_ERROR);
                regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
                                   ADV7511_POWER_POWER_DOWN, 0);
                adv7511->current_edid_segment = -1;
@@ -536,7 +578,7 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
 
        edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
 
-       if (adv7511->dpms_mode != DRM_MODE_DPMS_ON)
+       if (!adv7511->powered)
                regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
                                   ADV7511_POWER_POWER_DOWN,
                                   ADV7511_POWER_POWER_DOWN);
@@ -558,41 +600,10 @@ static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
        struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               adv7511->current_edid_segment = -1;
-
-               regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-                            ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR);
-               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-                                  ADV7511_POWER_POWER_DOWN, 0);
-               /*
-                * Per spec it is allowed to pulse the HDP signal to indicate
-                * that the EDID information has changed. Some monitors do this
-                * when they wakeup from standby or are enabled. When the HDP
-                * goes low the adv7511 is reset and the outputs are disabled
-                * which might cause the monitor to go to standby again. To
-                * avoid this we ignore the HDP pin for the first few seconds
-                * after enabeling the output.
-                */
-               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
-                                  ADV7511_REG_POWER2_HDP_SRC_MASK,
-                                  ADV7511_REG_POWER2_HDP_SRC_NONE);
-               /* Most of the registers are reset during power down or
-                * when HPD is low
-                */
-               regcache_sync(adv7511->regmap);
-               break;
-       default:
-               /* TODO: setup additional power down modes */
-               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-                                  ADV7511_POWER_POWER_DOWN,
-                                  ADV7511_POWER_POWER_DOWN);
-               regcache_mark_dirty(adv7511->regmap);
-               break;
-       }
-
-       adv7511->dpms_mode = mode;
+       if (mode == DRM_MODE_DPMS_ON)
+               adv7511_power_on(adv7511);
+       else
+               adv7511_power_off(adv7511);
 }
 
 static enum drm_connector_status
@@ -620,10 +631,9 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
         * there is a pending HPD interrupt and the cable is connected there was
         * at least one transition from disconnected to connected and the chip
         * has to be reinitialized. */
-       if (status == connector_status_connected && hpd &&
-           adv7511->dpms_mode == DRM_MODE_DPMS_ON) {
+       if (status == connector_status_connected && hpd && adv7511->powered) {
                regcache_mark_dirty(adv7511->regmap);
-               adv7511_encoder_dpms(encoder, adv7511->dpms_mode);
+               adv7511_power_on(adv7511);
                adv7511_get_modes(encoder, connector);
                if (adv7511->status == connector_status_connected)
                        status = connector_status_disconnected;
@@ -858,7 +868,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        if (!adv7511)
                return -ENOMEM;
 
-       adv7511->dpms_mode = DRM_MODE_DPMS_OFF;
+       adv7511->powered = false;
        adv7511->status = connector_status_disconnected;
 
        ret = adv7511_parse_dt(dev->of_node, &link_config);
@@ -918,10 +928,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
                     ADV7511_CEC_CTRL_POWER_DOWN);
 
-       regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-                          ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN);
-
-       adv7511->current_edid_segment = -1;
+       adv7511_power_off(adv7511);
 
        i2c_set_clientdata(i2c, adv7511);
 
index a9041d1a8ff002f332705db5d80082761788ad19..5febffdb027d9ae72d0e5e4b2725b7bb6d5d4274 100644 (file)
@@ -25,6 +25,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_encoder_slave.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_of.h>
 #include <drm/i2c/tda998x.h>
 
 #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
@@ -387,7 +388,7 @@ set_page(struct tda998x_priv *priv, uint16_t reg)
                };
                int ret = i2c_master_send(client, buf, sizeof(buf));
                if (ret < 0) {
-                       dev_err(&client->dev, "setpage %04x err %d\n",
+                       dev_err(&client->dev, "%s %04x err %d\n", __func__,
                                        reg, ret);
                        return ret;
                }
@@ -1035,8 +1036,9 @@ tda998x_encoder_detect(struct tda998x_priv *priv)
                        connector_status_disconnected;
 }
 
-static int read_edid_block(struct tda998x_priv *priv, uint8_t *buf, int blk)
+static int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length)
 {
+       struct tda998x_priv *priv = data;
        uint8_t offset, segptr;
        int ret, i;
 
@@ -1080,8 +1082,8 @@ static int read_edid_block(struct tda998x_priv *priv, uint8_t *buf, int blk)
                return -ETIMEDOUT;
        }
 
-       ret = reg_read_range(priv, REG_EDID_DATA_0, buf, EDID_LENGTH);
-       if (ret != EDID_LENGTH) {
+       ret = reg_read_range(priv, REG_EDID_DATA_0, buf, length);
+       if (ret != length) {
                dev_err(&priv->hdmi->dev, "failed to read edid block %d: %d\n",
                        blk, ret);
                return ret;
@@ -1090,82 +1092,31 @@ static int read_edid_block(struct tda998x_priv *priv, uint8_t *buf, int blk)
        return 0;
 }
 
-static uint8_t *do_get_edid(struct tda998x_priv *priv)
+static int
+tda998x_encoder_get_modes(struct tda998x_priv *priv,
+                         struct drm_connector *connector)
 {
-       int j, valid_extensions = 0;
-       uint8_t *block, *new;
-       bool print_bad_edid = drm_debug & DRM_UT_KMS;
-
-       if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
-               return NULL;
+       struct edid *edid;
+       int n;
 
        if (priv->rev == TDA19988)
                reg_clear(priv, REG_TX4, TX4_PD_RAM);
 
-       /* base block fetch */
-       if (read_edid_block(priv, block, 0))
-               goto fail;
-
-       if (!drm_edid_block_valid(block, 0, print_bad_edid))
-               goto fail;
-
-       /* if there's no extensions, we're done */
-       if (block[0x7e] == 0)
-               goto done;
-
-       new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL);
-       if (!new)
-               goto fail;
-       block = new;
-
-       for (j = 1; j <= block[0x7e]; j++) {
-               uint8_t *ext_block = block + (valid_extensions + 1) * EDID_LENGTH;
-               if (read_edid_block(priv, ext_block, j))
-                       goto fail;
-
-               if (!drm_edid_block_valid(ext_block, j, print_bad_edid))
-                       goto fail;
-
-               valid_extensions++;
-       }
-
-       if (valid_extensions != block[0x7e]) {
-               block[EDID_LENGTH-1] += block[0x7e] - valid_extensions;
-               block[0x7e] = valid_extensions;
-               new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
-               if (!new)
-                       goto fail;
-               block = new;
-       }
+       edid = drm_do_get_edid(connector, read_edid_block, priv);
 
-done:
        if (priv->rev == TDA19988)
                reg_set(priv, REG_TX4, TX4_PD_RAM);
 
-       return block;
-
-fail:
-       if (priv->rev == TDA19988)
-               reg_set(priv, REG_TX4, TX4_PD_RAM);
-       dev_warn(&priv->hdmi->dev, "failed to read EDID\n");
-       kfree(block);
-       return NULL;
-}
-
-static int
-tda998x_encoder_get_modes(struct tda998x_priv *priv,
-                         struct drm_connector *connector)
-{
-       struct edid *edid = (struct edid *)do_get_edid(priv);
-       int n = 0;
-
-       if (edid) {
-               drm_mode_connector_update_edid_property(connector, edid);
-               n = drm_add_edid_modes(connector, edid);
-               priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid);
-               kfree(edid);
+       if (!edid) {
+               dev_warn(&priv->hdmi->dev, "failed to read EDID\n");
+               return 0;
        }
 
+       drm_mode_connector_update_edid_property(connector, edid);
+       n = drm_add_edid_modes(connector, edid);
+       priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid);
+       kfree(edid);
+
        return n;
 }
 
@@ -1547,6 +1498,7 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
        struct i2c_client *client = to_i2c_client(dev);
        struct drm_device *drm = data;
        struct tda998x_priv2 *priv;
+       uint32_t crtcs = 0;
        int ret;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -1555,9 +1507,18 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 
        dev_set_drvdata(dev, priv);
 
+       if (dev->of_node)
+               crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+       /* If no CRTCs were found, fall back to our old behaviour */
+       if (crtcs == 0) {
+               dev_warn(dev, "Falling back to first CRTC\n");
+               crtcs = 1 << 0;
+       }
+
        priv->base.encoder = &priv->encoder;
        priv->connector.interlace_allowed = 1;
-       priv->encoder.possible_crtcs = 1 << 0;
+       priv->encoder.possible_crtcs = crtcs;
 
        ret = tda998x_create(client, &priv->base);
        if (ret)
index f01922591679f92b9ef5b91cd228ee70e11098d3..a69002e2257d06fee72c131ca854d2975636c307 100644 (file)
@@ -28,6 +28,7 @@ i915-y += i915_cmd_parser.o \
          i915_gem_execbuffer.o \
          i915_gem_gtt.o \
          i915_gem.o \
+         i915_gem_shrinker.o \
          i915_gem_stolen.o \
          i915_gem_tiling.o \
          i915_gem_userptr.o \
@@ -83,9 +84,11 @@ i915-y += dvo_ch7017.o \
          intel_sdvo.o \
          intel_tv.o
 
+# virtual gpu code
+i915-y += i915_vgpu.o
+
 # legacy horrors
-i915-y += i915_dma.o \
-         i915_ums.o
+i915-y += i915_dma.o
 
 obj-$(CONFIG_DRM_I915)  += i915.o
 
index 806e812340d0d96b06811fa6db19f9b78efaa2aa..61ae8ff4eaed990d0f21b57b6d0490ca8b3c83d1 100644 (file)
@@ -818,23 +818,28 @@ static bool valid_reg(const u32 *table, int count, u32 addr)
        return false;
 }
 
-static u32 *vmap_batch(struct drm_i915_gem_object *obj)
+static u32 *vmap_batch(struct drm_i915_gem_object *obj,
+                      unsigned start, unsigned len)
 {
        int i;
        void *addr = NULL;
        struct sg_page_iter sg_iter;
+       int first_page = start >> PAGE_SHIFT;
+       int last_page = (len + start + 4095) >> PAGE_SHIFT;
+       int npages = last_page - first_page;
        struct page **pages;
 
-       pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages));
+       pages = drm_malloc_ab(npages, sizeof(*pages));
        if (pages == NULL) {
                DRM_DEBUG_DRIVER("Failed to get space for pages\n");
                goto finish;
        }
 
        i = 0;
-       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
-               pages[i] = sg_page_iter_page(&sg_iter);
-               i++;
+       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, first_page) {
+               pages[i++] = sg_page_iter_page(&sg_iter);
+               if (i == npages)
+                       break;
        }
 
        addr = vmap(pages, i, 0, PAGE_KERNEL);
@@ -855,61 +860,61 @@ static u32 *copy_batch(struct drm_i915_gem_object *dest_obj,
                       u32 batch_start_offset,
                       u32 batch_len)
 {
-       int ret = 0;
        int needs_clflush = 0;
-       u32 *src_base, *dest_base = NULL;
-       u32 *src_addr, *dest_addr;
-       u32 offset = batch_start_offset / sizeof(*dest_addr);
-       u32 end = batch_start_offset + batch_len;
+       void *src_base, *src;
+       void *dst = NULL;
+       int ret;
 
-       if (end > dest_obj->base.size || end > src_obj->base.size)
+       if (batch_len > dest_obj->base.size ||
+           batch_len + batch_start_offset > src_obj->base.size)
                return ERR_PTR(-E2BIG);
 
        ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush);
        if (ret) {
-               DRM_DEBUG_DRIVER("CMD: failed to prep read\n");
+               DRM_DEBUG_DRIVER("CMD: failed to prepare shadow batch\n");
                return ERR_PTR(ret);
        }
 
-       src_base = vmap_batch(src_obj);
+       src_base = vmap_batch(src_obj, batch_start_offset, batch_len);
        if (!src_base) {
                DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n");
                ret = -ENOMEM;
                goto unpin_src;
        }
 
-       src_addr = src_base + offset;
-
-       if (needs_clflush)
-               drm_clflush_virt_range((char *)src_addr, batch_len);
+       ret = i915_gem_object_get_pages(dest_obj);
+       if (ret) {
+               DRM_DEBUG_DRIVER("CMD: Failed to get pages for shadow batch\n");
+               goto unmap_src;
+       }
+       i915_gem_object_pin_pages(dest_obj);
 
        ret = i915_gem_object_set_to_cpu_domain(dest_obj, true);
        if (ret) {
-               DRM_DEBUG_DRIVER("CMD: Failed to set batch CPU domain\n");
+               DRM_DEBUG_DRIVER("CMD: Failed to set shadow batch to CPU\n");
                goto unmap_src;
        }
 
-       dest_base = vmap_batch(dest_obj);
-       if (!dest_base) {
+       dst = vmap_batch(dest_obj, 0, batch_len);
+       if (!dst) {
                DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n");
+               i915_gem_object_unpin_pages(dest_obj);
                ret = -ENOMEM;
                goto unmap_src;
        }
 
-       dest_addr = dest_base + offset;
-
-       if (batch_start_offset != 0)
-               memset((u8 *)dest_base, 0, batch_start_offset);
+       src = src_base + offset_in_page(batch_start_offset);
+       if (needs_clflush)
+               drm_clflush_virt_range(src, batch_len);
 
-       memcpy(dest_addr, src_addr, batch_len);
-       memset((u8 *)dest_addr + batch_len, 0, dest_obj->base.size - end);
+       memcpy(dst, src, batch_len);
 
 unmap_src:
        vunmap(src_base);
 unpin_src:
        i915_gem_object_unpin_pages(src_obj);
 
-       return ret ? ERR_PTR(ret) : dest_base;
+       return ret ? ERR_PTR(ret) : dst;
 }
 
 /**
@@ -1046,34 +1051,26 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
                    u32 batch_len,
                    bool is_master)
 {
-       int ret = 0;
        u32 *cmd, *batch_base, *batch_end;
        struct drm_i915_cmd_descriptor default_desc = { 0 };
        bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */
-
-       ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 4096, 0);
-       if (ret) {
-               DRM_DEBUG_DRIVER("CMD: Failed to pin shadow batch\n");
-               return -1;
-       }
+       int ret = 0;
 
        batch_base = copy_batch(shadow_batch_obj, batch_obj,
                                batch_start_offset, batch_len);
        if (IS_ERR(batch_base)) {
                DRM_DEBUG_DRIVER("CMD: Failed to copy batch\n");
-               i915_gem_object_ggtt_unpin(shadow_batch_obj);
                return PTR_ERR(batch_base);
        }
 
-       cmd = batch_base + (batch_start_offset / sizeof(*cmd));
-
        /*
         * We use the batch length as size because the shadow object is as
         * large or larger and copy_batch() will write MI_NOPs to the extra
         * space. Parsing should be faster in some cases this way.
         */
-       batch_end = cmd + (batch_len / sizeof(*batch_end));
+       batch_end = batch_base + (batch_len / sizeof(*batch_end));
 
+       cmd = batch_base;
        while (cmd < batch_end) {
                const struct drm_i915_cmd_descriptor *desc;
                u32 length;
@@ -1132,7 +1129,7 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
        }
 
        vunmap(batch_base);
-       i915_gem_object_ggtt_unpin(shadow_batch_obj);
+       i915_gem_object_unpin_pages(shadow_batch_obj);
 
        return ret;
 }
index 96e811fe24ca79cd1b6438591cf1eb05379f0edd..007c7d7d82950f597bb05ef8388fb1696ef72b38 100644 (file)
@@ -139,10 +139,11 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
        if (obj->base.name)
                seq_printf(m, " (name: %d)", obj->base.name);
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
+       list_for_each_entry(vma, &obj->vma_list, vma_link) {
                if (vma->pin_count > 0)
                        pin_count++;
-               seq_printf(m, " (pinned x %d)", pin_count);
+       }
+       seq_printf(m, " (pinned x %d)", pin_count);
        if (obj->pin_display)
                seq_printf(m, " (display)");
        if (obj->fence_reg != I915_FENCE_REG_NONE)
@@ -152,12 +153,12 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                        seq_puts(m, " (pp");
                else
                        seq_puts(m, " (g");
-               seq_printf(m, "gtt offset: %08lx, size: %08lx, type: %u)",
+               seq_printf(m, "gtt offset: %08llx, size: %08llx, type: %u)",
                           vma->node.start, vma->node.size,
                           vma->ggtt_view.type);
        }
        if (obj->stolen)
-               seq_printf(m, " (stolen: %08lx)", obj->stolen->start);
+               seq_printf(m, " (stolen: %08llx)", obj->stolen->start);
        if (obj->pin_mappable || obj->fault_mappable) {
                char s[3], *t = s;
                if (obj->pin_mappable)
@@ -580,7 +581,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
                        seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
                                   work->flip_queued_vblank,
                                   work->flip_ready_vblank,
-                                  drm_vblank_count(dev, crtc->pipe));
+                                  drm_crtc_vblank_count(&crtc->base));
                        if (work->enable_stall_check)
                                seq_puts(m, "Stall check enabled, ");
                        else
@@ -1089,7 +1090,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                seq_printf(m, "Current P-state: %d\n",
                           (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
        } else if (IS_GEN6(dev) || (IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) ||
-                  IS_BROADWELL(dev)) {
+                  IS_BROADWELL(dev) || IS_GEN9(dev)) {
                u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
                u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
                u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
@@ -1108,11 +1109,15 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
                reqf = I915_READ(GEN6_RPNSWREQ);
-               reqf &= ~GEN6_TURBO_DISABLE;
-               if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-                       reqf >>= 24;
-               else
-                       reqf >>= 25;
+               if (IS_GEN9(dev))
+                       reqf >>= 23;
+               else {
+                       reqf &= ~GEN6_TURBO_DISABLE;
+                       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+                               reqf >>= 24;
+                       else
+                               reqf >>= 25;
+               }
                reqf = intel_gpu_freq(dev_priv, reqf);
 
                rpmodectl = I915_READ(GEN6_RP_CONTROL);
@@ -1126,7 +1131,9 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                rpdownei = I915_READ(GEN6_RP_CUR_DOWN_EI);
                rpcurdown = I915_READ(GEN6_RP_CUR_DOWN);
                rpprevdown = I915_READ(GEN6_RP_PREV_DOWN);
-               if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               if (IS_GEN9(dev))
+                       cagf = (rpstat & GEN9_CAGF_MASK) >> GEN9_CAGF_SHIFT;
+               else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                        cagf = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT;
                else
                        cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
@@ -1152,7 +1159,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                           pm_ier, pm_imr, pm_isr, pm_iir, pm_mask);
                seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
                seq_printf(m, "Render p-state ratio: %d\n",
-                          (gt_perf_status & 0xff00) >> 8);
+                          (gt_perf_status & (IS_GEN9(dev) ? 0x1ff00 : 0xff00)) >> 8);
                seq_printf(m, "Render p-state VID: %d\n",
                           gt_perf_status & 0xff);
                seq_printf(m, "Render p-state limit: %d\n",
@@ -1177,19 +1184,25 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                           GEN6_CURBSYTAVG_MASK);
 
                max_freq = (rp_state_cap & 0xff0000) >> 16;
+               max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
                seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, max_freq));
 
                max_freq = (rp_state_cap & 0xff00) >> 8;
+               max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
                seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, max_freq));
 
                max_freq = rp_state_cap & 0xff;
+               max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
                seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, max_freq));
 
                seq_printf(m, "Max overclocked frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
+
+               seq_printf(m, "Idle freq: %d MHz\n",
+                          intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq));
        } else if (IS_VALLEYVIEW(dev)) {
                u32 freq_sts;
 
@@ -1204,6 +1217,9 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                seq_printf(m, "min GPU freq: %d MHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.min_freq));
 
+               seq_printf(m, "idle GPU freq: %d MHz\n",
+                          intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq));
+
                seq_printf(m,
                           "efficient (RPe) frequency: %d MHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
@@ -1778,11 +1794,12 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
        ifbdev = dev_priv->fbdev;
        fb = to_intel_framebuffer(ifbdev->helper.fb);
 
-       seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, refcount %d, obj ",
+       seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ",
                   fb->base.width,
                   fb->base.height,
                   fb->base.depth,
                   fb->base.bits_per_pixel,
+                  fb->base.modifier[0],
                   atomic_read(&fb->base.refcount.refcount));
        describe_obj(m, fb->obj);
        seq_putc(m, '\n');
@@ -1793,11 +1810,12 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
                if (ifbdev && &fb->base == ifbdev->helper.fb)
                        continue;
 
-               seq_printf(m, "user size: %d x %d, depth %d, %d bpp, refcount %d, obj ",
+               seq_printf(m, "user size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ",
                           fb->base.width,
                           fb->base.height,
                           fb->base.depth,
                           fb->base.bits_per_pixel,
+                          fb->base.modifier[0],
                           atomic_read(&fb->base.refcount.refcount));
                describe_obj(m, fb->obj);
                seq_putc(m, '\n');
@@ -1828,18 +1846,6 @@ static int i915_context_status(struct seq_file *m, void *unused)
        if (ret)
                return ret;
 
-       if (dev_priv->ips.pwrctx) {
-               seq_puts(m, "power context ");
-               describe_obj(m, dev_priv->ips.pwrctx);
-               seq_putc(m, '\n');
-       }
-
-       if (dev_priv->ips.renderctx) {
-               seq_puts(m, "render context ");
-               describe_obj(m, dev_priv->ips.renderctx);
-               seq_putc(m, '\n');
-       }
-
        list_for_each_entry(ctx, &dev_priv->context_list, link) {
                if (!i915.enable_execlists &&
                    ctx->legacy_hw_ctx.rcs_state == NULL)
@@ -2183,7 +2189,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
                struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
 
                seq_puts(m, "aliasing PPGTT:\n");
-               seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset);
+               seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd.pd_offset);
 
                ppgtt->debug_dump(ppgtt, m);
        }
@@ -2243,6 +2249,11 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
        enum pipe pipe;
        bool enabled = false;
 
+       if (!HAS_PSR(dev)) {
+               seq_puts(m, "PSR not supported\n");
+               return 0;
+       }
+
        intel_runtime_pm_get(dev_priv);
 
        mutex_lock(&dev_priv->psr.lock);
@@ -2255,17 +2266,15 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
        seq_printf(m, "Re-enable work scheduled: %s\n",
                   yesno(work_busy(&dev_priv->psr.work.work)));
 
-       if (HAS_PSR(dev)) {
-               if (HAS_DDI(dev))
-                       enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
-               else {
-                       for_each_pipe(dev_priv, pipe) {
-                               stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) &
-                                       VLV_EDP_PSR_CURR_STATE_MASK;
-                               if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
-                                   (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
-                                       enabled = true;
-                       }
+       if (HAS_DDI(dev))
+               enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+       else {
+               for_each_pipe(dev_priv, pipe) {
+                       stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) &
+                               VLV_EDP_PSR_CURR_STATE_MASK;
+                       if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+                           (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+                               enabled = true;
                }
        }
        seq_printf(m, "HW Enabled & Active bit: %s", yesno(enabled));
@@ -2282,7 +2291,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
                   yesno((bool)dev_priv->psr.link_standby));
 
        /* CHV PSR has no kind of performance counter */
-       if (HAS_PSR(dev) && HAS_DDI(dev)) {
+       if (HAS_DDI(dev)) {
                psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
                        EDP_PSR_PERF_CNT_MASK;
 
@@ -2305,8 +2314,7 @@ static int i915_sink_crc(struct seq_file *m, void *data)
        u8 crc[6];
 
        drm_modeset_lock_all(dev);
-       list_for_each_entry(connector, &dev->mode_config.connector_list,
-                           base.head) {
+       for_each_intel_connector(dev, connector) {
 
                if (connector->base.dpms != DRM_MODE_DPMS_ON)
                        continue;
@@ -2674,7 +2682,8 @@ static int i915_display_info(struct seq_file *m, void *unused)
                        active = cursor_position(dev, crtc->pipe, &x, &y);
                        seq_printf(m, "\tcursor visible? %s, position (%d, %d), size %dx%d, addr 0x%08x, active? %s\n",
                                   yesno(crtc->cursor_base),
-                                  x, y, crtc->cursor_width, crtc->cursor_height,
+                                  x, y, crtc->base.cursor->state->crtc_w,
+                                  crtc->base.cursor->state->crtc_h,
                                   crtc->cursor_addr, yesno(active));
                }
 
@@ -2850,7 +2859,7 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
        for_each_pipe(dev_priv, pipe) {
                seq_printf(m, "Pipe %c\n", pipe_name(pipe));
 
-               for_each_plane(pipe, plane) {
+               for_each_plane(dev_priv, pipe, plane) {
                        entry = &ddb->plane[pipe][plane];
                        seq_printf(m, "  Plane%-8d%8u%8u%8u\n", plane + 1,
                                   entry->start, entry->end,
@@ -2867,6 +2876,115 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
        return 0;
 }
 
+static void drrs_status_per_crtc(struct seq_file *m,
+               struct drm_device *dev, struct intel_crtc *intel_crtc)
+{
+       struct intel_encoder *intel_encoder;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_drrs *drrs = &dev_priv->drrs;
+       int vrefresh = 0;
+
+       for_each_encoder_on_crtc(dev, &intel_crtc->base, intel_encoder) {
+               /* Encoder connected on this CRTC */
+               switch (intel_encoder->type) {
+               case INTEL_OUTPUT_EDP:
+                       seq_puts(m, "eDP:\n");
+                       break;
+               case INTEL_OUTPUT_DSI:
+                       seq_puts(m, "DSI:\n");
+                       break;
+               case INTEL_OUTPUT_HDMI:
+                       seq_puts(m, "HDMI:\n");
+                       break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+                       seq_puts(m, "DP:\n");
+                       break;
+               default:
+                       seq_printf(m, "Other encoder (id=%d).\n",
+                                               intel_encoder->type);
+                       return;
+               }
+       }
+
+       if (dev_priv->vbt.drrs_type == STATIC_DRRS_SUPPORT)
+               seq_puts(m, "\tVBT: DRRS_type: Static");
+       else if (dev_priv->vbt.drrs_type == SEAMLESS_DRRS_SUPPORT)
+               seq_puts(m, "\tVBT: DRRS_type: Seamless");
+       else if (dev_priv->vbt.drrs_type == DRRS_NOT_SUPPORTED)
+               seq_puts(m, "\tVBT: DRRS_type: None");
+       else
+               seq_puts(m, "\tVBT: DRRS_type: FIXME: Unrecognized Value");
+
+       seq_puts(m, "\n\n");
+
+       if (intel_crtc->config->has_drrs) {
+               struct intel_panel *panel;
+
+               mutex_lock(&drrs->mutex);
+               /* DRRS Supported */
+               seq_puts(m, "\tDRRS Supported: Yes\n");
+
+               /* disable_drrs() will make drrs->dp NULL */
+               if (!drrs->dp) {
+                       seq_puts(m, "Idleness DRRS: Disabled");
+                       mutex_unlock(&drrs->mutex);
+                       return;
+               }
+
+               panel = &drrs->dp->attached_connector->panel;
+               seq_printf(m, "\t\tBusy_frontbuffer_bits: 0x%X",
+                                       drrs->busy_frontbuffer_bits);
+
+               seq_puts(m, "\n\t\t");
+               if (drrs->refresh_rate_type == DRRS_HIGH_RR) {
+                       seq_puts(m, "DRRS_State: DRRS_HIGH_RR\n");
+                       vrefresh = panel->fixed_mode->vrefresh;
+               } else if (drrs->refresh_rate_type == DRRS_LOW_RR) {
+                       seq_puts(m, "DRRS_State: DRRS_LOW_RR\n");
+                       vrefresh = panel->downclock_mode->vrefresh;
+               } else {
+                       seq_printf(m, "DRRS_State: Unknown(%d)\n",
+                                               drrs->refresh_rate_type);
+                       mutex_unlock(&drrs->mutex);
+                       return;
+               }
+               seq_printf(m, "\t\tVrefresh: %d", vrefresh);
+
+               seq_puts(m, "\n\t\t");
+               mutex_unlock(&drrs->mutex);
+       } else {
+               /* DRRS not supported. Print the VBT parameter*/
+               seq_puts(m, "\tDRRS Supported : No");
+       }
+       seq_puts(m, "\n");
+}
+
+static int i915_drrs_status(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct intel_crtc *intel_crtc;
+       int active_crtc_cnt = 0;
+
+       for_each_intel_crtc(dev, intel_crtc) {
+               drm_modeset_lock(&intel_crtc->base.mutex, NULL);
+
+               if (intel_crtc->active) {
+                       active_crtc_cnt++;
+                       seq_printf(m, "\nCRTC %d:  ", active_crtc_cnt);
+
+                       drrs_status_per_crtc(m, dev, intel_crtc);
+               }
+
+               drm_modeset_unlock(&intel_crtc->base.mutex);
+       }
+
+       if (!active_crtc_cnt)
+               seq_puts(m, "No active crtc found\n");
+
+       return 0;
+}
+
 struct pipe_crc_info {
        const char *name;
        struct drm_device *dev;
@@ -4189,7 +4307,7 @@ i915_max_freq_set(void *data, u64 val)
 {
        struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 rp_state_cap, hw_max, hw_min;
+       u32 hw_max, hw_min;
        int ret;
 
        if (INTEL_INFO(dev)->gen < 6)
@@ -4206,18 +4324,10 @@ i915_max_freq_set(void *data, u64 val)
        /*
         * Turbo will still be enabled, but won't go above the set value.
         */
-       if (IS_VALLEYVIEW(dev)) {
-               val = intel_freq_opcode(dev_priv, val);
-
-               hw_max = dev_priv->rps.max_freq;
-               hw_min = dev_priv->rps.min_freq;
-       } else {
-               val = intel_freq_opcode(dev_priv, val);
+       val = intel_freq_opcode(dev_priv, val);
 
-               rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
-               hw_max = dev_priv->rps.max_freq;
-               hw_min = (rp_state_cap >> 16) & 0xff;
-       }
+       hw_max = dev_priv->rps.max_freq;
+       hw_min = dev_priv->rps.min_freq;
 
        if (val < hw_min || val > hw_max || val < dev_priv->rps.min_freq_softlimit) {
                mutex_unlock(&dev_priv->rps.hw_lock);
@@ -4226,10 +4336,7 @@ i915_max_freq_set(void *data, u64 val)
 
        dev_priv->rps.max_freq_softlimit = val;
 
-       if (IS_VALLEYVIEW(dev))
-               valleyview_set_rps(dev, val);
-       else
-               gen6_set_rps(dev, val);
+       intel_set_rps(dev, val);
 
        mutex_unlock(&dev_priv->rps.hw_lock);
 
@@ -4267,7 +4374,7 @@ i915_min_freq_set(void *data, u64 val)
 {
        struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 rp_state_cap, hw_max, hw_min;
+       u32 hw_max, hw_min;
        int ret;
 
        if (INTEL_INFO(dev)->gen < 6)
@@ -4284,18 +4391,10 @@ i915_min_freq_set(void *data, u64 val)
        /*
         * Turbo will still be enabled, but won't go below the set value.
         */
-       if (IS_VALLEYVIEW(dev)) {
-               val = intel_freq_opcode(dev_priv, val);
-
-               hw_max = dev_priv->rps.max_freq;
-               hw_min = dev_priv->rps.min_freq;
-       } else {
-               val = intel_freq_opcode(dev_priv, val);
+       val = intel_freq_opcode(dev_priv, val);
 
-               rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
-               hw_max = dev_priv->rps.max_freq;
-               hw_min = (rp_state_cap >> 16) & 0xff;
-       }
+       hw_max = dev_priv->rps.max_freq;
+       hw_min = dev_priv->rps.min_freq;
 
        if (val < hw_min || val > hw_max || val > dev_priv->rps.max_freq_softlimit) {
                mutex_unlock(&dev_priv->rps.hw_lock);
@@ -4304,10 +4403,7 @@ i915_min_freq_set(void *data, u64 val)
 
        dev_priv->rps.min_freq_softlimit = val;
 
-       if (IS_VALLEYVIEW(dev))
-               valleyview_set_rps(dev, val);
-       else
-               gen6_set_rps(dev, val);
+       intel_set_rps(dev, val);
 
        mutex_unlock(&dev_priv->rps.hw_lock);
 
@@ -4374,6 +4470,112 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops,
                        i915_cache_sharing_get, i915_cache_sharing_set,
                        "%llu\n");
 
+static int i915_sseu_status(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned int s_tot = 0, ss_tot = 0, ss_per = 0, eu_tot = 0, eu_per = 0;
+
+       if ((INTEL_INFO(dev)->gen < 8) || IS_BROADWELL(dev))
+               return -ENODEV;
+
+       seq_puts(m, "SSEU Device Info\n");
+       seq_printf(m, "  Available Slice Total: %u\n",
+                  INTEL_INFO(dev)->slice_total);
+       seq_printf(m, "  Available Subslice Total: %u\n",
+                  INTEL_INFO(dev)->subslice_total);
+       seq_printf(m, "  Available Subslice Per Slice: %u\n",
+                  INTEL_INFO(dev)->subslice_per_slice);
+       seq_printf(m, "  Available EU Total: %u\n",
+                  INTEL_INFO(dev)->eu_total);
+       seq_printf(m, "  Available EU Per Subslice: %u\n",
+                  INTEL_INFO(dev)->eu_per_subslice);
+       seq_printf(m, "  Has Slice Power Gating: %s\n",
+                  yesno(INTEL_INFO(dev)->has_slice_pg));
+       seq_printf(m, "  Has Subslice Power Gating: %s\n",
+                  yesno(INTEL_INFO(dev)->has_subslice_pg));
+       seq_printf(m, "  Has EU Power Gating: %s\n",
+                  yesno(INTEL_INFO(dev)->has_eu_pg));
+
+       seq_puts(m, "SSEU Device Status\n");
+       if (IS_CHERRYVIEW(dev)) {
+               const int ss_max = 2;
+               int ss;
+               u32 sig1[ss_max], sig2[ss_max];
+
+               sig1[0] = I915_READ(CHV_POWER_SS0_SIG1);
+               sig1[1] = I915_READ(CHV_POWER_SS1_SIG1);
+               sig2[0] = I915_READ(CHV_POWER_SS0_SIG2);
+               sig2[1] = I915_READ(CHV_POWER_SS1_SIG2);
+
+               for (ss = 0; ss < ss_max; ss++) {
+                       unsigned int eu_cnt;
+
+                       if (sig1[ss] & CHV_SS_PG_ENABLE)
+                               /* skip disabled subslice */
+                               continue;
+
+                       s_tot = 1;
+                       ss_per++;
+                       eu_cnt = ((sig1[ss] & CHV_EU08_PG_ENABLE) ? 0 : 2) +
+                                ((sig1[ss] & CHV_EU19_PG_ENABLE) ? 0 : 2) +
+                                ((sig1[ss] & CHV_EU210_PG_ENABLE) ? 0 : 2) +
+                                ((sig2[ss] & CHV_EU311_PG_ENABLE) ? 0 : 2);
+                       eu_tot += eu_cnt;
+                       eu_per = max(eu_per, eu_cnt);
+               }
+               ss_tot = ss_per;
+       } else if (IS_SKYLAKE(dev)) {
+               const int s_max = 3, ss_max = 4;
+               int s, ss;
+               u32 s_reg[s_max], eu_reg[2*s_max], eu_mask[2];
+
+               s_reg[0] = I915_READ(GEN9_SLICE0_PGCTL_ACK);
+               s_reg[1] = I915_READ(GEN9_SLICE1_PGCTL_ACK);
+               s_reg[2] = I915_READ(GEN9_SLICE2_PGCTL_ACK);
+               eu_reg[0] = I915_READ(GEN9_SLICE0_SS01_EU_PGCTL_ACK);
+               eu_reg[1] = I915_READ(GEN9_SLICE0_SS23_EU_PGCTL_ACK);
+               eu_reg[2] = I915_READ(GEN9_SLICE1_SS01_EU_PGCTL_ACK);
+               eu_reg[3] = I915_READ(GEN9_SLICE1_SS23_EU_PGCTL_ACK);
+               eu_reg[4] = I915_READ(GEN9_SLICE2_SS01_EU_PGCTL_ACK);
+               eu_reg[5] = I915_READ(GEN9_SLICE2_SS23_EU_PGCTL_ACK);
+               eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
+                            GEN9_PGCTL_SSA_EU19_ACK |
+                            GEN9_PGCTL_SSA_EU210_ACK |
+                            GEN9_PGCTL_SSA_EU311_ACK;
+               eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
+                            GEN9_PGCTL_SSB_EU19_ACK |
+                            GEN9_PGCTL_SSB_EU210_ACK |
+                            GEN9_PGCTL_SSB_EU311_ACK;
+
+               for (s = 0; s < s_max; s++) {
+                       if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
+                               /* skip disabled slice */
+                               continue;
+
+                       s_tot++;
+                       ss_per = INTEL_INFO(dev)->subslice_per_slice;
+                       ss_tot += ss_per;
+                       for (ss = 0; ss < ss_max; ss++) {
+                               unsigned int eu_cnt;
+
+                               eu_cnt = 2 * hweight32(eu_reg[2*s + ss/2] &
+                                                      eu_mask[ss%2]);
+                               eu_tot += eu_cnt;
+                               eu_per = max(eu_per, eu_cnt);
+                       }
+               }
+       }
+       seq_printf(m, "  Enabled Slice Total: %u\n", s_tot);
+       seq_printf(m, "  Enabled Subslice Total: %u\n", ss_tot);
+       seq_printf(m, "  Enabled Subslice Per Slice: %u\n", ss_per);
+       seq_printf(m, "  Enabled EU Total: %u\n", eu_tot);
+       seq_printf(m, "  Enabled EU Per Subslice: %u\n", eu_per);
+
+       return 0;
+}
+
 static int i915_forcewake_open(struct inode *inode, struct file *file)
 {
        struct drm_device *dev = inode->i_private;
@@ -4487,6 +4689,8 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_dp_mst_info", i915_dp_mst_info, 0},
        {"i915_wa_registers", i915_wa_registers, 0},
        {"i915_ddb_info", i915_ddb_info, 0},
+       {"i915_sseu_status", i915_sseu_status, 0},
+       {"i915_drrs_status", i915_drrs_status, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
index 1a46787129e7a2c5022a0ecf7ced69418afa8320..68e0c85a17cfcd5779ffab7b9aa0e8dba7cf0fac 100644 (file)
@@ -36,6 +36,7 @@
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
+#include "i915_vgpu.h"
 #include "i915_trace.h"
 #include <linux/pci.h>
 #include <linux/console.h>
@@ -67,6 +68,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_CHIPSET_ID:
                value = dev->pdev->device;
                break;
+       case I915_PARAM_REVISION:
+               value = dev->pdev->revision;
+               break;
        case I915_PARAM_HAS_GEM:
                value = 1;
                break;
@@ -149,6 +153,16 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_MMAP_VERSION:
                value = 1;
                break;
+       case I915_PARAM_SUBSLICE_TOTAL:
+               value = INTEL_INFO(dev)->subslice_total;
+               if (!value)
+                       return -ENODEV;
+               break;
+       case I915_PARAM_EU_TOTAL:
+               value = INTEL_INFO(dev)->eu_total;
+               if (!value)
+                       return -ENODEV;
+               break;
        default:
                DRM_DEBUG("Unknown parameter %d\n", param->param);
                return -EINVAL;
@@ -605,16 +619,128 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
                }
        }
 
+       /* Initialize slice/subslice/EU info */
        if (IS_CHERRYVIEW(dev)) {
-               u32 fuse, mask_eu;
+               u32 fuse, eu_dis;
 
                fuse = I915_READ(CHV_FUSE_GT);
-               mask_eu = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK |
-                                 CHV_FGT_EU_DIS_SS0_R1_MASK |
-                                 CHV_FGT_EU_DIS_SS1_R0_MASK |
-                                 CHV_FGT_EU_DIS_SS1_R1_MASK);
-               info->eu_total = 16 - hweight32(mask_eu);
+
+               info->slice_total = 1;
+
+               if (!(fuse & CHV_FGT_DISABLE_SS0)) {
+                       info->subslice_per_slice++;
+                       eu_dis = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK |
+                                        CHV_FGT_EU_DIS_SS0_R1_MASK);
+                       info->eu_total += 8 - hweight32(eu_dis);
+               }
+
+               if (!(fuse & CHV_FGT_DISABLE_SS1)) {
+                       info->subslice_per_slice++;
+                       eu_dis = fuse & (CHV_FGT_EU_DIS_SS1_R0_MASK |
+                                       CHV_FGT_EU_DIS_SS1_R1_MASK);
+                       info->eu_total += 8 - hweight32(eu_dis);
+               }
+
+               info->subslice_total = info->subslice_per_slice;
+               /*
+                * CHV expected to always have a uniform distribution of EU
+                * across subslices.
+               */
+               info->eu_per_subslice = info->subslice_total ?
+                                       info->eu_total / info->subslice_total :
+                                       0;
+               /*
+                * CHV supports subslice power gating on devices with more than
+                * one subslice, and supports EU power gating on devices with
+                * more than one EU pair per subslice.
+               */
+               info->has_slice_pg = 0;
+               info->has_subslice_pg = (info->subslice_total > 1);
+               info->has_eu_pg = (info->eu_per_subslice > 2);
+       } else if (IS_SKYLAKE(dev)) {
+               const int s_max = 3, ss_max = 4, eu_max = 8;
+               int s, ss;
+               u32 fuse2, eu_disable[s_max], s_enable, ss_disable;
+
+               fuse2 = I915_READ(GEN8_FUSE2);
+               s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >>
+                          GEN8_F2_S_ENA_SHIFT;
+               ss_disable = (fuse2 & GEN9_F2_SS_DIS_MASK) >>
+                            GEN9_F2_SS_DIS_SHIFT;
+
+               eu_disable[0] = I915_READ(GEN8_EU_DISABLE0);
+               eu_disable[1] = I915_READ(GEN8_EU_DISABLE1);
+               eu_disable[2] = I915_READ(GEN8_EU_DISABLE2);
+
+               info->slice_total = hweight32(s_enable);
+               /*
+                * The subslice disable field is global, i.e. it applies
+                * to each of the enabled slices.
+               */
+               info->subslice_per_slice = ss_max - hweight32(ss_disable);
+               info->subslice_total = info->slice_total *
+                                      info->subslice_per_slice;
+
+               /*
+                * Iterate through enabled slices and subslices to
+                * count the total enabled EU.
+               */
+               for (s = 0; s < s_max; s++) {
+                       if (!(s_enable & (0x1 << s)))
+                               /* skip disabled slice */
+                               continue;
+
+                       for (ss = 0; ss < ss_max; ss++) {
+                               u32 n_disabled;
+
+                               if (ss_disable & (0x1 << ss))
+                                       /* skip disabled subslice */
+                                       continue;
+
+                               n_disabled = hweight8(eu_disable[s] >>
+                                                     (ss * eu_max));
+
+                               /*
+                                * Record which subslice(s) has(have) 7 EUs. we
+                                * can tune the hash used to spread work among
+                                * subslices if they are unbalanced.
+                                */
+                               if (eu_max - n_disabled == 7)
+                                       info->subslice_7eu[s] |= 1 << ss;
+
+                               info->eu_total += eu_max - n_disabled;
+                       }
+               }
+
+               /*
+                * SKL is expected to always have a uniform distribution
+                * of EU across subslices with the exception that any one
+                * EU in any one subslice may be fused off for die
+                * recovery.
+               */
+               info->eu_per_subslice = info->subslice_total ?
+                                       DIV_ROUND_UP(info->eu_total,
+                                                    info->subslice_total) : 0;
+               /*
+                * SKL supports slice power gating on devices with more than
+                * one slice, and supports EU power gating on devices with
+                * more than one EU pair per subslice.
+               */
+               info->has_slice_pg = (info->slice_total > 1) ? 1 : 0;
+               info->has_subslice_pg = 0;
+               info->has_eu_pg = (info->eu_per_subslice > 2) ? 1 : 0;
        }
+       DRM_DEBUG_DRIVER("slice total: %u\n", info->slice_total);
+       DRM_DEBUG_DRIVER("subslice total: %u\n", info->subslice_total);
+       DRM_DEBUG_DRIVER("subslice per slice: %u\n", info->subslice_per_slice);
+       DRM_DEBUG_DRIVER("EU total: %u\n", info->eu_total);
+       DRM_DEBUG_DRIVER("EU per subslice: %u\n", info->eu_per_subslice);
+       DRM_DEBUG_DRIVER("has slice power gating: %s\n",
+                        info->has_slice_pg ? "y" : "n");
+       DRM_DEBUG_DRIVER("has subslice power gating: %s\n",
+                        info->has_subslice_pg ? "y" : "n");
+       DRM_DEBUG_DRIVER("has EU power gating: %s\n",
+                        info->has_eu_pg ? "y" : "n");
 }
 
 /**
@@ -637,17 +763,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        info = (struct intel_device_info *) flags;
 
-       /* Refuse to load on gen6+ without kms enabled. */
-       if (info->gen >= 6 && !drm_core_check_feature(dev, DRIVER_MODESET)) {
-               DRM_INFO("Your hardware requires kernel modesetting (KMS)\n");
-               DRM_INFO("See CONFIG_DRM_I915_KMS, nomodeset, and i915.modeset parameters\n");
-               return -ENODEV;
-       }
-
-       /* UMS needs agp support. */
-       if (!drm_core_check_feature(dev, DRIVER_MODESET) && !dev->agp)
-               return -EINVAL;
-
        dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
        if (dev_priv == NULL)
                return -ENOMEM;
@@ -717,20 +832,18 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (ret)
                goto out_regs;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               /* WARNING: Apparently we must kick fbdev drivers before vgacon,
-                * otherwise the vga fbdev driver falls over. */
-               ret = i915_kick_out_firmware_fb(dev_priv);
-               if (ret) {
-                       DRM_ERROR("failed to remove conflicting framebuffer drivers\n");
-                       goto out_gtt;
-               }
+       /* WARNING: Apparently we must kick fbdev drivers before vgacon,
+        * otherwise the vga fbdev driver falls over. */
+       ret = i915_kick_out_firmware_fb(dev_priv);
+       if (ret) {
+               DRM_ERROR("failed to remove conflicting framebuffer drivers\n");
+               goto out_gtt;
+       }
 
-               ret = i915_kick_out_vgacon(dev_priv);
-               if (ret) {
-                       DRM_ERROR("failed to remove conflicting VGA console\n");
-                       goto out_gtt;
-               }
+       ret = i915_kick_out_vgacon(dev_priv);
+       if (ret) {
+               DRM_ERROR("failed to remove conflicting VGA console\n");
+               goto out_gtt;
        }
 
        pci_set_master(dev->pdev);
@@ -834,14 +947,19 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        intel_power_domains_init(dev_priv);
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               ret = i915_load_modeset_init(dev);
-               if (ret < 0) {
-                       DRM_ERROR("failed to init modeset\n");
-                       goto out_power_well;
-               }
+       ret = i915_load_modeset_init(dev);
+       if (ret < 0) {
+               DRM_ERROR("failed to init modeset\n");
+               goto out_power_well;
        }
 
+       /*
+        * Notify a valid surface after modesetting,
+        * when running inside a VM.
+        */
+       if (intel_vgpu_active(dev))
+               I915_WRITE(vgtif_reg(display_ready), VGT_DRV_DISPLAY_READY);
+
        i915_setup_sysfs(dev);
 
        if (INTEL_INFO(dev)->num_pipes) {
@@ -921,28 +1039,25 @@ int i915_driver_unload(struct drm_device *dev)
 
        acpi_video_unregister();
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               intel_fbdev_fini(dev);
+       intel_fbdev_fini(dev);
 
        drm_vblank_cleanup(dev);
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               intel_modeset_cleanup(dev);
-
-               /*
-                * free the memory space allocated for the child device
-                * config parsed from VBT
-                */
-               if (dev_priv->vbt.child_dev && dev_priv->vbt.child_dev_num) {
-                       kfree(dev_priv->vbt.child_dev);
-                       dev_priv->vbt.child_dev = NULL;
-                       dev_priv->vbt.child_dev_num = 0;
-               }
+       intel_modeset_cleanup(dev);
 
-               vga_switcheroo_unregister_client(dev->pdev);
-               vga_client_register(dev->pdev, NULL, NULL, NULL);
+       /*
+        * free the memory space allocated for the child device
+        * config parsed from VBT
+        */
+       if (dev_priv->vbt.child_dev && dev_priv->vbt.child_dev_num) {
+               kfree(dev_priv->vbt.child_dev);
+               dev_priv->vbt.child_dev = NULL;
+               dev_priv->vbt.child_dev_num = 0;
        }
 
+       vga_switcheroo_unregister_client(dev->pdev);
+       vga_client_register(dev->pdev, NULL, NULL, NULL);
+
        /* Free error state after interrupts are fully disabled. */
        cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
        i915_destroy_error_state(dev);
@@ -952,17 +1067,15 @@ int i915_driver_unload(struct drm_device *dev)
 
        intel_opregion_fini(dev);
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               /* Flush any outstanding unpin_work. */
-               flush_workqueue(dev_priv->wq);
+       /* Flush any outstanding unpin_work. */
+       flush_workqueue(dev_priv->wq);
 
-               mutex_lock(&dev->struct_mutex);
-               i915_gem_cleanup_ringbuffer(dev);
-               i915_gem_batch_pool_fini(&dev_priv->mm.batch_pool);
-               i915_gem_context_fini(dev);
-               mutex_unlock(&dev->struct_mutex);
-               i915_gem_cleanup_stolen(dev);
-       }
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_cleanup_ringbuffer(dev);
+       i915_gem_batch_pool_fini(&dev_priv->mm.batch_pool);
+       i915_gem_context_fini(dev);
+       mutex_unlock(&dev->struct_mutex);
+       i915_gem_cleanup_stolen(dev);
 
        intel_teardown_gmbus(dev);
        intel_teardown_mchbar(dev);
@@ -1023,8 +1136,7 @@ void i915_driver_preclose(struct drm_device *dev, struct drm_file *file)
        i915_gem_release(dev, file);
        mutex_unlock(&dev->struct_mutex);
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               intel_modeset_preclose(dev, file);
+       intel_modeset_preclose(dev, file);
 }
 
 void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
@@ -1087,7 +1199,7 @@ const struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, intel_sprite_get_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
index 8039cec71fc24a3750812dc519b08bee6a824f41..82f8be4b6745969804163e6cab7cf63199b0c22b 100644 (file)
@@ -346,7 +346,6 @@ static const struct intel_device_info intel_broadwell_gt3m_info = {
 };
 
 static const struct intel_device_info intel_cherryview_info = {
-       .is_preliminary = 1,
        .gen = 8, .num_pipes = 3,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
@@ -369,6 +368,19 @@ static const struct intel_device_info intel_skylake_info = {
        IVB_CURSOR_OFFSETS,
 };
 
+static const struct intel_device_info intel_skylake_gt3_info = {
+       .is_preliminary = 1,
+       .is_skylake = 1,
+       .gen = 9, .num_pipes = 3,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
+       .has_llc = 1,
+       .has_ddi = 1,
+       .has_fbc = 1,
+       GEN_DEFAULT_PIPEOFFSETS,
+       IVB_CURSOR_OFFSETS,
+};
+
 /*
  * Make sure any device matches here are from most specific to most
  * general.  For example, since the Quanta match is based on the subsystem
@@ -406,7 +418,9 @@ static const struct intel_device_info intel_skylake_info = {
        INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info), \
        INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info), \
        INTEL_CHV_IDS(&intel_cherryview_info),  \
-       INTEL_SKL_IDS(&intel_skylake_info)
+       INTEL_SKL_GT1_IDS(&intel_skylake_info), \
+       INTEL_SKL_GT2_IDS(&intel_skylake_info), \
+       INTEL_SKL_GT3_IDS(&intel_skylake_gt3_info)      \
 
 static const struct pci_device_id pciidlist[] = {              /* aka */
        INTEL_PCI_IDS,
@@ -553,6 +567,7 @@ static int i915_drm_suspend(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
        pci_power_t opregion_target_state;
+       int error;
 
        /* ignore lid events during suspend */
        mutex_lock(&dev_priv->modeset_restore_lock);
@@ -567,37 +582,32 @@ static int i915_drm_suspend(struct drm_device *dev)
 
        pci_save_state(dev->pdev);
 
-       /* If KMS is active, we do the leavevt stuff here */
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               int error;
-
-               error = i915_gem_suspend(dev);
-               if (error) {
-                       dev_err(&dev->pdev->dev,
-                               "GEM idle failed, resume might fail\n");
-                       return error;
-               }
+       error = i915_gem_suspend(dev);
+       if (error) {
+               dev_err(&dev->pdev->dev,
+                       "GEM idle failed, resume might fail\n");
+               return error;
+       }
 
-               intel_suspend_gt_powersave(dev);
+       intel_suspend_gt_powersave(dev);
 
-               /*
-                * Disable CRTCs directly since we want to preserve sw state
-                * for _thaw. Also, power gate the CRTC power wells.
-                */
-               drm_modeset_lock_all(dev);
-               for_each_crtc(dev, crtc)
-                       intel_crtc_control(crtc, false);
-               drm_modeset_unlock_all(dev);
+       /*
+        * Disable CRTCs directly since we want to preserve sw state
+        * for _thaw. Also, power gate the CRTC power wells.
+        */
+       drm_modeset_lock_all(dev);
+       for_each_crtc(dev, crtc)
+               intel_crtc_control(crtc, false);
+       drm_modeset_unlock_all(dev);
 
-               intel_dp_mst_suspend(dev);
+       intel_dp_mst_suspend(dev);
 
-               intel_runtime_pm_disable_interrupts(dev_priv);
-               intel_hpd_cancel_work(dev_priv);
+       intel_runtime_pm_disable_interrupts(dev_priv);
+       intel_hpd_cancel_work(dev_priv);
 
-               intel_suspend_encoders(dev_priv);
+       intel_suspend_encoders(dev_priv);
 
-               intel_suspend_hw(dev);
-       }
+       intel_suspend_hw(dev);
 
        i915_gem_suspend_gtt_mappings(dev);
 
@@ -622,7 +632,7 @@ static int i915_drm_suspend(struct drm_device *dev)
        return 0;
 }
 
-static int i915_drm_suspend_late(struct drm_device *drm_dev)
+static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
 {
        struct drm_i915_private *dev_priv = drm_dev->dev_private;
        int ret;
@@ -636,7 +646,17 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev)
        }
 
        pci_disable_device(drm_dev->pdev);
-       pci_set_power_state(drm_dev->pdev, PCI_D3hot);
+       /*
+        * During hibernation on some GEN4 platforms the BIOS may try to access
+        * the device even though it's already in D3 and hang the machine. So
+        * leave the device in D0 on those platforms and hope the BIOS will
+        * power down the device properly. Platforms where this was seen:
+        * Lenovo Thinkpad X301, X61s
+        */
+       if (!(hibernation &&
+             drm_dev->pdev->subsystem_vendor == PCI_VENDOR_ID_LENOVO &&
+             INTEL_INFO(dev_priv)->gen == 4))
+               pci_set_power_state(drm_dev->pdev, PCI_D3hot);
 
        return 0;
 }
@@ -662,60 +682,55 @@ int i915_suspend_legacy(struct drm_device *dev, pm_message_t state)
        if (error)
                return error;
 
-       return i915_drm_suspend_late(dev);
+       return i915_drm_suspend_late(dev, false);
 }
 
 static int i915_drm_resume(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               mutex_lock(&dev->struct_mutex);
-               i915_gem_restore_gtt_mappings(dev);
-               mutex_unlock(&dev->struct_mutex);
-       }
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_restore_gtt_mappings(dev);
+       mutex_unlock(&dev->struct_mutex);
 
        i915_restore_state(dev);
        intel_opregion_setup(dev);
 
-       /* KMS EnterVT equivalent */
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               intel_init_pch_refclk(dev);
-               drm_mode_config_reset(dev);
+       intel_init_pch_refclk(dev);
+       drm_mode_config_reset(dev);
 
-               mutex_lock(&dev->struct_mutex);
-               if (i915_gem_init_hw(dev)) {
-                       DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n");
-                       atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
-               }
-               mutex_unlock(&dev->struct_mutex);
+       mutex_lock(&dev->struct_mutex);
+       if (i915_gem_init_hw(dev)) {
+               DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n");
+               atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
+       }
+       mutex_unlock(&dev->struct_mutex);
 
-               /* We need working interrupts for modeset enabling ... */
-               intel_runtime_pm_enable_interrupts(dev_priv);
+       /* We need working interrupts for modeset enabling ... */
+       intel_runtime_pm_enable_interrupts(dev_priv);
 
-               intel_modeset_init_hw(dev);
+       intel_modeset_init_hw(dev);
 
-               spin_lock_irq(&dev_priv->irq_lock);
-               if (dev_priv->display.hpd_irq_setup)
-                       dev_priv->display.hpd_irq_setup(dev);
-               spin_unlock_irq(&dev_priv->irq_lock);
+       spin_lock_irq(&dev_priv->irq_lock);
+       if (dev_priv->display.hpd_irq_setup)
+               dev_priv->display.hpd_irq_setup(dev);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
-               drm_modeset_lock_all(dev);
-               intel_modeset_setup_hw_state(dev, true);
-               drm_modeset_unlock_all(dev);
+       drm_modeset_lock_all(dev);
+       intel_modeset_setup_hw_state(dev, true);
+       drm_modeset_unlock_all(dev);
 
-               intel_dp_mst_resume(dev);
+       intel_dp_mst_resume(dev);
 
-               /*
-                * ... but also need to make sure that hotplug processing
-                * doesn't cause havoc. Like in the driver load code we don't
-                * bother with the tiny race here where we might loose hotplug
-                * notifications.
-                * */
-               intel_hpd_init(dev_priv);
-               /* Config may have changed between suspend and resume */
-               drm_helper_hpd_irq_event(dev);
-       }
+       /*
+        * ... but also need to make sure that hotplug processing
+        * doesn't cause havoc. Like in the driver load code we don't
+        * bother with the tiny race here where we might loose hotplug
+        * notifications.
+        * */
+       intel_hpd_init(dev_priv);
+       /* Config may have changed between suspend and resume */
+       drm_helper_hpd_irq_event(dev);
 
        intel_opregion_init(dev);
 
@@ -851,38 +866,29 @@ int i915_reset(struct drm_device *dev)
         * was running at the time of the reset (i.e. we weren't VT
         * switched away).
         */
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               /* Used to prevent gem_check_wedged returning -EAGAIN during gpu reset */
-               dev_priv->gpu_error.reload_in_reset = true;
 
-               ret = i915_gem_init_hw(dev);
+       /* Used to prevent gem_check_wedged returning -EAGAIN during gpu reset */
+       dev_priv->gpu_error.reload_in_reset = true;
 
-               dev_priv->gpu_error.reload_in_reset = false;
+       ret = i915_gem_init_hw(dev);
 
-               mutex_unlock(&dev->struct_mutex);
-               if (ret) {
-                       DRM_ERROR("Failed hw init on reset %d\n", ret);
-                       return ret;
-               }
+       dev_priv->gpu_error.reload_in_reset = false;
 
-               /*
-                * FIXME: This races pretty badly against concurrent holders of
-                * ring interrupts. This is possible since we've started to drop
-                * dev->struct_mutex in select places when waiting for the gpu.
-                */
-
-               /*
-                * rps/rc6 re-init is necessary to restore state lost after the
-                * reset and the re-install of gt irqs. Skip for ironlake per
-                * previous concerns that it doesn't respond well to some forms
-                * of re-init after reset.
-                */
-               if (INTEL_INFO(dev)->gen > 5)
-                       intel_enable_gt_powersave(dev);
-       } else {
-               mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev->struct_mutex);
+       if (ret) {
+               DRM_ERROR("Failed hw init on reset %d\n", ret);
+               return ret;
        }
 
+       /*
+        * rps/rc6 re-init is necessary to restore state lost after the
+        * reset and the re-install of gt irqs. Skip for ironlake per
+        * previous concerns that it doesn't respond well to some forms
+        * of re-init after reset.
+        */
+       if (INTEL_INFO(dev)->gen > 5)
+               intel_enable_gt_powersave(dev);
+
        return 0;
 }
 
@@ -950,7 +956,17 @@ static int i915_pm_suspend_late(struct device *dev)
        if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       return i915_drm_suspend_late(drm_dev);
+       return i915_drm_suspend_late(drm_dev, false);
+}
+
+static int i915_pm_poweroff_late(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_to_i915(dev)->dev;
+
+       if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+               return 0;
+
+       return i915_drm_suspend_late(drm_dev, true);
 }
 
 static int i915_pm_resume_early(struct device *dev)
@@ -1520,7 +1536,7 @@ static const struct dev_pm_ops i915_pm_ops = {
        .thaw_early = i915_pm_resume_early,
        .thaw = i915_pm_resume,
        .poweroff = i915_pm_suspend,
-       .poweroff_late = i915_pm_suspend_late,
+       .poweroff_late = i915_pm_poweroff_late,
        .restore_early = i915_pm_resume_early,
        .restore = i915_pm_resume,
 
@@ -1630,11 +1646,9 @@ static int __init i915_init(void)
 
        if (!(driver.driver_features & DRIVER_MODESET)) {
                driver.get_vblank_timestamp = NULL;
-#ifndef CONFIG_DRM_I915_UMS
                /* Silently fail loading to not upset userspace. */
                DRM_DEBUG_DRIVER("KMS and UMS disabled.\n");
                return 0;
-#endif
        }
 
        /*
@@ -1650,10 +1664,8 @@ static int __init i915_init(void)
 
 static void __exit i915_exit(void)
 {
-#ifndef CONFIG_DRM_I915_UMS
        if (!(driver.driver_features & DRIVER_MODESET))
                return; /* Never loaded a driver. */
-#endif
 
        drm_pci_exit(&driver, &i915_pci_driver);
 }
index f2a825e39646427b7e4617627bd8ab3c3b9acb4d..e326ac9730cf9c557a80d31dbf58706bca9e0b62 100644 (file)
@@ -31,6 +31,7 @@
 #define _I915_DRV_H_
 
 #include <uapi/drm/i915_drm.h>
+#include <uapi/drm/drm_fourcc.h>
 
 #include "i915_reg.h"
 #include "intel_bios.h"
@@ -55,7 +56,7 @@
 
 #define DRIVER_NAME            "i915"
 #define DRIVER_DESC            "Intel Graphics"
-#define DRIVER_DATE            "20150130"
+#define DRIVER_DATE            "20150327"
 
 #undef WARN_ON
 /* Many gcc seem to no see through this and fall over :( */
@@ -69,6 +70,9 @@
 #define WARN_ON(x) WARN((x), "WARN_ON(" #x ")")
 #endif
 
+#undef WARN_ON_ONCE
+#define WARN_ON_ONCE(x) WARN_ONCE((x), "WARN_ON_ONCE(" #x ")")
+
 #define MISSING_CASE(x) WARN(1, "Missing switch case (%lu) in %s\n", \
                             (long) (x), __func__);
 
@@ -222,9 +226,14 @@ enum hpd_pin {
 
 #define for_each_pipe(__dev_priv, __p) \
        for ((__p) = 0; (__p) < INTEL_INFO(__dev_priv)->num_pipes; (__p)++)
-#define for_each_plane(pipe, p) \
-       for ((p) = 0; (p) < INTEL_INFO(dev)->num_sprites[(pipe)] + 1; (p)++)
-#define for_each_sprite(p, s) for ((s) = 0; (s) < INTEL_INFO(dev)->num_sprites[(p)]; (s)++)
+#define for_each_plane(__dev_priv, __pipe, __p)                                \
+       for ((__p) = 0;                                                 \
+            (__p) < INTEL_INFO(__dev_priv)->num_sprites[(__pipe)] + 1; \
+            (__p)++)
+#define for_each_sprite(__dev_priv, __p, __s)                          \
+       for ((__s) = 0;                                                 \
+            (__s) < INTEL_INFO(__dev_priv)->num_sprites[(__p)];        \
+            (__s)++)
 
 #define for_each_crtc(dev, crtc) \
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
@@ -237,6 +246,12 @@ enum hpd_pin {
                            &(dev)->mode_config.encoder_list,   \
                            base.head)
 
+#define for_each_intel_connector(dev, intel_connector)         \
+       list_for_each_entry(intel_connector,                    \
+                           &dev->mode_config.connector_list,   \
+                           base.head)
+
+
 #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \
        list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
                if ((intel_encoder)->base.crtc == (__crtc))
@@ -412,6 +427,8 @@ struct drm_i915_error_state {
        u32 forcewake;
        u32 error; /* gen6+ */
        u32 err_int; /* gen7 */
+       u32 fault_data0; /* gen8, gen9 */
+       u32 fault_data1; /* gen8, gen9 */
        u32 done_reg;
        u32 gac_eco;
        u32 gam_ecochk;
@@ -529,7 +546,7 @@ struct drm_i915_display_funcs {
         * Returns true on success, false on failure.
         */
        bool (*find_dpll)(const struct intel_limit *limit,
-                         struct intel_crtc *crtc,
+                         struct intel_crtc_state *crtc_state,
                          int target, int refclk,
                          struct dpll *match_clock,
                          struct dpll *best_clock);
@@ -538,7 +555,7 @@ struct drm_i915_display_funcs {
                                 struct drm_crtc *crtc,
                                 uint32_t sprite_width, uint32_t sprite_height,
                                 int pixel_size, bool enable, bool scaled);
-       void (*modeset_global_resources)(struct drm_device *dev);
+       void (*modeset_global_resources)(struct drm_atomic_state *state);
        /* Returns the active state of the crtc, and if the crtc is active,
         * fills out the pipe-config with the hw state. */
        bool (*get_pipe_config)(struct intel_crtc *,
@@ -692,7 +709,18 @@ struct intel_device_info {
        int trans_offsets[I915_MAX_TRANSCODERS];
        int palette_offsets[I915_MAX_PIPES];
        int cursor_offsets[I915_MAX_PIPES];
-       unsigned int eu_total;
+
+       /* Slice/subslice/EU info */
+       u8 slice_total;
+       u8 subslice_total;
+       u8 subslice_per_slice;
+       u8 eu_total;
+       u8 eu_per_subslice;
+       /* For each slice, which subslice(s) has(have) 7 EUs (bitfield)? */
+       u8 subslice_7eu[3];
+       u8 has_slice_pg:1;
+       u8 has_subslice_pg:1;
+       u8 has_eu_pg:1;
 };
 
 #undef DEFINE_FLAG
@@ -771,11 +799,20 @@ struct intel_context {
        struct list_head link;
 };
 
+enum fb_op_origin {
+       ORIGIN_GTT,
+       ORIGIN_CPU,
+       ORIGIN_CS,
+       ORIGIN_FLIP,
+};
+
 struct i915_fbc {
-       unsigned long size;
+       unsigned long uncompressed_size;
        unsigned threshold;
        unsigned int fb_id;
-       enum plane plane;
+       unsigned int possible_framebuffer_bits;
+       unsigned int busy_bits;
+       struct intel_crtc *crtc;
        int y;
 
        struct drm_mm_node compressed_fb;
@@ -787,14 +824,6 @@ struct i915_fbc {
         * possible. */
        bool enabled;
 
-       /* On gen8 some rings cannont perform fbc clean operation so for now
-        * we are doing this on SW with mmio.
-        * This variable works in the opposite information direction
-        * of ring->fbc_dirty telling software on frontbuffer tracking
-        * to perform the cache clean on sw side.
-        */
-       bool need_sw_cache_clean;
-
        struct intel_fbc_work {
                struct delayed_work work;
                struct drm_crtc *crtc;
@@ -888,150 +917,21 @@ struct intel_gmbus {
 };
 
 struct i915_suspend_saved_registers {
-       u8 saveLBB;
-       u32 saveDSPACNTR;
-       u32 saveDSPBCNTR;
        u32 saveDSPARB;
-       u32 savePIPEACONF;
-       u32 savePIPEBCONF;
-       u32 savePIPEASRC;
-       u32 savePIPEBSRC;
-       u32 saveFPA0;
-       u32 saveFPA1;
-       u32 saveDPLL_A;
-       u32 saveDPLL_A_MD;
-       u32 saveHTOTAL_A;
-       u32 saveHBLANK_A;
-       u32 saveHSYNC_A;
-       u32 saveVTOTAL_A;
-       u32 saveVBLANK_A;
-       u32 saveVSYNC_A;
-       u32 saveBCLRPAT_A;
-       u32 saveTRANSACONF;
-       u32 saveTRANS_HTOTAL_A;
-       u32 saveTRANS_HBLANK_A;
-       u32 saveTRANS_HSYNC_A;
-       u32 saveTRANS_VTOTAL_A;
-       u32 saveTRANS_VBLANK_A;
-       u32 saveTRANS_VSYNC_A;
-       u32 savePIPEASTAT;
-       u32 saveDSPASTRIDE;
-       u32 saveDSPASIZE;
-       u32 saveDSPAPOS;
-       u32 saveDSPAADDR;
-       u32 saveDSPASURF;
-       u32 saveDSPATILEOFF;
-       u32 savePFIT_PGM_RATIOS;
-       u32 saveBLC_HIST_CTL;
-       u32 saveBLC_PWM_CTL;
-       u32 saveBLC_PWM_CTL2;
-       u32 saveBLC_CPU_PWM_CTL;
-       u32 saveBLC_CPU_PWM_CTL2;
-       u32 saveFPB0;
-       u32 saveFPB1;
-       u32 saveDPLL_B;
-       u32 saveDPLL_B_MD;
-       u32 saveHTOTAL_B;
-       u32 saveHBLANK_B;
-       u32 saveHSYNC_B;
-       u32 saveVTOTAL_B;
-       u32 saveVBLANK_B;
-       u32 saveVSYNC_B;
-       u32 saveBCLRPAT_B;
-       u32 saveTRANSBCONF;
-       u32 saveTRANS_HTOTAL_B;
-       u32 saveTRANS_HBLANK_B;
-       u32 saveTRANS_HSYNC_B;
-       u32 saveTRANS_VTOTAL_B;
-       u32 saveTRANS_VBLANK_B;
-       u32 saveTRANS_VSYNC_B;
-       u32 savePIPEBSTAT;
-       u32 saveDSPBSTRIDE;
-       u32 saveDSPBSIZE;
-       u32 saveDSPBPOS;
-       u32 saveDSPBADDR;
-       u32 saveDSPBSURF;
-       u32 saveDSPBTILEOFF;
-       u32 saveVGA0;
-       u32 saveVGA1;
-       u32 saveVGA_PD;
-       u32 saveVGACNTRL;
-       u32 saveADPA;
        u32 saveLVDS;
        u32 savePP_ON_DELAYS;
        u32 savePP_OFF_DELAYS;
-       u32 saveDVOA;
-       u32 saveDVOB;
-       u32 saveDVOC;
        u32 savePP_ON;
        u32 savePP_OFF;
        u32 savePP_CONTROL;
        u32 savePP_DIVISOR;
-       u32 savePFIT_CONTROL;
-       u32 save_palette_a[256];
-       u32 save_palette_b[256];
        u32 saveFBC_CONTROL;
-       u32 saveIER;
-       u32 saveIIR;
-       u32 saveIMR;
-       u32 saveDEIER;
-       u32 saveDEIMR;
-       u32 saveGTIER;
-       u32 saveGTIMR;
-       u32 saveFDI_RXA_IMR;
-       u32 saveFDI_RXB_IMR;
        u32 saveCACHE_MODE_0;
        u32 saveMI_ARB_STATE;
        u32 saveSWF0[16];
        u32 saveSWF1[16];
        u32 saveSWF2[3];
-       u8 saveMSR;
-       u8 saveSR[8];
-       u8 saveGR[25];
-       u8 saveAR_INDEX;
-       u8 saveAR[21];
-       u8 saveDACMASK;
-       u8 saveCR[37];
        uint64_t saveFENCE[I915_MAX_NUM_FENCES];
-       u32 saveCURACNTR;
-       u32 saveCURAPOS;
-       u32 saveCURABASE;
-       u32 saveCURBCNTR;
-       u32 saveCURBPOS;
-       u32 saveCURBBASE;
-       u32 saveCURSIZE;
-       u32 saveDP_B;
-       u32 saveDP_C;
-       u32 saveDP_D;
-       u32 savePIPEA_GMCH_DATA_M;
-       u32 savePIPEB_GMCH_DATA_M;
-       u32 savePIPEA_GMCH_DATA_N;
-       u32 savePIPEB_GMCH_DATA_N;
-       u32 savePIPEA_DP_LINK_M;
-       u32 savePIPEB_DP_LINK_M;
-       u32 savePIPEA_DP_LINK_N;
-       u32 savePIPEB_DP_LINK_N;
-       u32 saveFDI_RXA_CTL;
-       u32 saveFDI_TXA_CTL;
-       u32 saveFDI_RXB_CTL;
-       u32 saveFDI_TXB_CTL;
-       u32 savePFA_CTL_1;
-       u32 savePFB_CTL_1;
-       u32 savePFA_WIN_SZ;
-       u32 savePFB_WIN_SZ;
-       u32 savePFA_WIN_POS;
-       u32 savePFB_WIN_POS;
-       u32 savePCH_DREF_CONTROL;
-       u32 saveDISP_ARB_CTL;
-       u32 savePIPEA_DATA_M1;
-       u32 savePIPEA_DATA_N1;
-       u32 savePIPEA_LINK_M1;
-       u32 savePIPEA_LINK_N1;
-       u32 savePIPEB_DATA_M1;
-       u32 savePIPEB_DATA_N1;
-       u32 savePIPEB_LINK_M1;
-       u32 savePIPEB_LINK_N1;
-       u32 saveMCHBAR_RENDER_STANDBY;
        u32 savePCH_PORT_HOTPLUG;
        u16 saveGCDGMBUS;
 };
@@ -1127,13 +1027,12 @@ struct intel_gen6_power_mgmt {
        u8 max_freq_softlimit;  /* Max frequency permitted by the driver */
        u8 max_freq;            /* Maximum frequency, RP0 if not overclocking */
        u8 min_freq;            /* AKA RPn. Minimum frequency */
+       u8 idle_freq;           /* Frequency to request when we are idle */
        u8 efficient_freq;      /* AKA RPe. Pre-determined balanced frequency */
        u8 rp1_freq;            /* "less than" RP0 power/freqency */
        u8 rp0_freq;            /* Non-overclocked max frequency. */
        u32 cz_freq;
 
-       u32 ei_interrupt_count;
-
        int last_adj;
        enum { LOW_POWER, BETWEEN, HIGH_POWER } power;
 
@@ -1170,9 +1069,6 @@ struct intel_ilk_power_mgmt {
 
        int c_m;
        int r_t;
-
-       struct drm_i915_gem_object *pwrctx;
-       struct drm_i915_gem_object *renderctx;
 };
 
 struct drm_i915_private;
@@ -1454,6 +1350,7 @@ struct intel_vbt_data {
        bool edp_initialized;
        bool edp_support;
        int edp_bpp;
+       bool edp_low_vswing;
        struct edp_power_seq edp_pps;
 
        struct {
@@ -1514,6 +1411,25 @@ struct ilk_wm_values {
        enum intel_ddb_partitioning partitioning;
 };
 
+struct vlv_wm_values {
+       struct {
+               uint16_t primary;
+               uint16_t sprite[2];
+               uint8_t cursor;
+       } pipe[3];
+
+       struct {
+               uint16_t plane;
+               uint8_t cursor;
+       } sr;
+
+       struct {
+               uint8_t cursor;
+               uint8_t sprite[2];
+               uint8_t primary;
+       } ddl[3];
+};
+
 struct skl_ddb_entry {
        uint16_t start, end;    /* in number of blocks, 'end' is exclusive */
 };
@@ -1640,6 +1556,10 @@ struct i915_workarounds {
        u32 count;
 };
 
+struct i915_virtual_gpu {
+       bool active;
+};
+
 struct drm_i915_private {
        struct drm_device *dev;
        struct kmem_cache *slab;
@@ -1652,6 +1572,8 @@ struct drm_i915_private {
 
        struct intel_uncore uncore;
 
+       struct i915_virtual_gpu vgpu;
+
        struct intel_gmbus gmbus[GMBUS_NUM_PORTS];
 
 
@@ -1870,6 +1792,7 @@ struct drm_i915_private {
                union {
                        struct ilk_wm_values hw;
                        struct skl_wm_values skl_hw;
+                       struct vlv_wm_values vlv;
                };
        } wm;
 
@@ -2114,6 +2037,9 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
  * number comparisons on buffer last_read|write_seqno. It also allows an
  * emission time to be associated with the request for tracking how far ahead
  * of the GPU the submission is.
+ *
+ * The requests are reference counted, so upon creation they should have an
+ * initial reference taken using kref_init
  */
 struct drm_i915_gem_request {
        struct kref ref;
@@ -2137,8 +2063,18 @@ struct drm_i915_gem_request {
        /** Position in the ringbuffer of the end of the whole request */
        u32 tail;
 
-       /** Context related to this request */
+       /**
+        * Context and ring buffer related to this request
+        * Contexts are refcounted, so when this request is associated with a
+        * context, we must increment the context's refcount, to guarantee that
+        * it persists while any request is linked to it. Requests themselves
+        * are also refcounted, so the request will only be freed when the last
+        * reference to it is dismissed, and the code in
+        * i915_gem_request_free() will then decrement the refcount on the
+        * context.
+        */
        struct intel_context *ctx;
+       struct intel_ringbuffer *ringbuf;
 
        /** Batch buffer related to this request if any */
        struct drm_i915_gem_object *batch_obj;
@@ -2153,6 +2089,9 @@ struct drm_i915_gem_request {
        /** file_priv list entry for this request */
        struct list_head client_list;
 
+       /** process identifier submitting this request */
+       struct pid *pid;
+
        uint32_t uniq;
 
        /**
@@ -2339,6 +2278,7 @@ struct drm_i915_cmd_table {
 })
 #define INTEL_INFO(p)  (&__I915__(p)->info)
 #define INTEL_DEVID(p) (INTEL_INFO(p)->device_id)
+#define INTEL_REVID(p) (__I915__(p)->dev->pdev->revision)
 
 #define IS_I830(dev)           (INTEL_DEVID(dev) == 0x3577)
 #define IS_845G(dev)           (INTEL_DEVID(dev) == 0x2562)
@@ -2361,9 +2301,6 @@ struct drm_i915_cmd_table {
 #define IS_IVB_GT1(dev)                (INTEL_DEVID(dev) == 0x0156 || \
                                 INTEL_DEVID(dev) == 0x0152 || \
                                 INTEL_DEVID(dev) == 0x015a)
-#define IS_SNB_GT1(dev)                (INTEL_DEVID(dev) == 0x0102 || \
-                                INTEL_DEVID(dev) == 0x0106 || \
-                                INTEL_DEVID(dev) == 0x010A)
 #define IS_VALLEYVIEW(dev)     (INTEL_INFO(dev)->is_valleyview)
 #define IS_CHERRYVIEW(dev)     (INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
 #define IS_HASWELL(dev)        (INTEL_INFO(dev)->is_haswell)
@@ -2374,6 +2311,7 @@ struct drm_i915_cmd_table {
                                 (INTEL_DEVID(dev) & 0xFF00) == 0x0C00)
 #define IS_BDW_ULT(dev)                (IS_BROADWELL(dev) && \
                                 ((INTEL_DEVID(dev) & 0xf) == 0x6 ||    \
+                                (INTEL_DEVID(dev) & 0xf) == 0xb ||     \
                                 (INTEL_DEVID(dev) & 0xf) == 0xe))
 #define IS_BDW_GT3(dev)                (IS_BROADWELL(dev) && \
                                 (INTEL_DEVID(dev) & 0x00F0) == 0x0020)
@@ -2386,6 +2324,12 @@ struct drm_i915_cmd_table {
                                 INTEL_DEVID(dev) == 0x0A1E)
 #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)
 
+#define SKL_REVID_A0           (0x0)
+#define SKL_REVID_B0           (0x1)
+#define SKL_REVID_C0           (0x2)
+#define SKL_REVID_D0           (0x3)
+#define SKL_REVID_E0           (0x4)
+
 /*
  * The genX designation typically refers to the render engine, so render
  * capability related checks should use IS_GEN, while display and other checks
@@ -2485,6 +2429,7 @@ struct drm_i915_cmd_table {
 #define NUM_L3_SLICES(dev) (IS_HSW_GT3(dev) ? 2 : HAS_L3_DPF(dev))
 
 #define GT_FREQUENCY_MULTIPLIER 50
+#define GEN9_FREQ_SCALER 3
 
 #include "i915_trace.h"
 
@@ -2493,14 +2438,11 @@ extern int i915_max_ioctl;
 
 extern int i915_suspend_legacy(struct drm_device *dev, pm_message_t state);
 extern int i915_resume_legacy(struct drm_device *dev);
-extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
-extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
 
 /* i915_params.c */
 struct i915_params {
        int modeset;
        int panel_ignore_lid;
-       unsigned int powersave;
        int semaphores;
        unsigned int lvds_downclock;
        int lvds_channel_mode;
@@ -2520,11 +2462,12 @@ struct i915_params {
        bool enable_hangcheck;
        bool fastboot;
        bool prefault_disable;
+       bool load_detect_test;
        bool reset;
        bool disable_display;
        bool disable_vtd_wa;
        int use_mmio_flip;
-       bool mmio_debug;
+       int mmio_debug;
        bool verbose_state_checks;
        bool nuclear_pageflip;
 };
@@ -2577,6 +2520,10 @@ void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
 void intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
                                enum forcewake_domains domains);
 void assert_forcewakes_inactive(struct drm_i915_private *dev_priv);
+static inline bool intel_vgpu_active(struct drm_device *dev)
+{
+       return to_i915(dev)->vgpu.active;
+}
 
 void
 i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
@@ -2655,12 +2602,6 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 void i915_gem_load(struct drm_device *dev);
-unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
-                             long target,
-                             unsigned flags);
-#define I915_SHRINK_PURGEABLE 0x1
-#define I915_SHRINK_UNBOUND 0x2
-#define I915_SHRINK_BOUND 0x4
 void *i915_gem_object_alloc(struct drm_device *dev);
 void i915_gem_object_free(struct drm_i915_gem_object *obj);
 void i915_gem_object_init(struct drm_i915_gem_object *obj,
@@ -2677,20 +2618,16 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
 #define PIN_GLOBAL 0x4
 #define PIN_OFFSET_BIAS 0x8
 #define PIN_OFFSET_MASK (~4095)
-int __must_check i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
-                                         struct i915_address_space *vm,
-                                         uint32_t alignment,
-                                         uint64_t flags,
-                                         const struct i915_ggtt_view *view);
-static inline
-int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
-                                    struct i915_address_space *vm,
-                                    uint32_t alignment,
-                                    uint64_t flags)
-{
-       return i915_gem_object_pin_view(obj, vm, alignment, flags,
-                                               &i915_ggtt_view_normal);
-}
+int __must_check
+i915_gem_object_pin(struct drm_i915_gem_object *obj,
+                   struct i915_address_space *vm,
+                   uint32_t alignment,
+                   uint64_t flags);
+int __must_check
+i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
+                        const struct i915_ggtt_view *view,
+                        uint32_t alignment,
+                        uint64_t flags);
 
 int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
                  u32 flags);
@@ -2830,8 +2767,10 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write);
 int __must_check
 i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                     u32 alignment,
-                                    struct intel_engine_cs *pipelined);
-void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj);
+                                    struct intel_engine_cs *pipelined,
+                                    const struct i915_ggtt_view *view);
+void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
+                                             const struct i915_ggtt_view *view);
 int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj,
                                int align);
 int i915_gem_open(struct drm_device *dev, struct drm_file *file);
@@ -2854,60 +2793,46 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
 
 void i915_gem_restore_fences(struct drm_device *dev);
 
-unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
-                                      struct i915_address_space *vm,
-                                      enum i915_ggtt_view_type view);
-static inline
-unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
-                                 struct i915_address_space *vm)
+unsigned long
+i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
+                             const struct i915_ggtt_view *view);
+unsigned long
+i915_gem_obj_offset(struct drm_i915_gem_object *o,
+                   struct i915_address_space *vm);
+static inline unsigned long
+i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *o)
 {
-       return i915_gem_obj_offset_view(o, vm, I915_GGTT_VIEW_NORMAL);
+       return i915_gem_obj_ggtt_offset_view(o, &i915_ggtt_view_normal);
 }
+
 bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o);
-bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
-                            struct i915_address_space *vm,
-                            enum i915_ggtt_view_type view);
-static inline
+bool i915_gem_obj_ggtt_bound_view(struct drm_i915_gem_object *o,
+                                 const struct i915_ggtt_view *view);
 bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
-                       struct i915_address_space *vm)
-{
-       return i915_gem_obj_bound_view(o, vm, I915_GGTT_VIEW_NORMAL);
-}
+                       struct i915_address_space *vm);
 
 unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
                                struct i915_address_space *vm);
-struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
-                                         struct i915_address_space *vm,
-                                         const struct i915_ggtt_view *view);
-static inline
-struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
-                                    struct i915_address_space *vm)
-{
-       return i915_gem_obj_to_vma_view(obj, vm, &i915_ggtt_view_normal);
-}
-
 struct i915_vma *
-i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
-                                      struct i915_address_space *vm,
-                                      const struct i915_ggtt_view *view);
+i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
+                   struct i915_address_space *vm);
+struct i915_vma *
+i915_gem_obj_to_ggtt_view(struct drm_i915_gem_object *obj,
+                         const struct i915_ggtt_view *view);
 
-static inline
 struct i915_vma *
 i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
-                                 struct i915_address_space *vm)
-{
-       return i915_gem_obj_lookup_or_create_vma_view(obj, vm,
-                                               &i915_ggtt_view_normal);
-}
+                                 struct i915_address_space *vm);
+struct i915_vma *
+i915_gem_obj_lookup_or_create_ggtt_vma(struct drm_i915_gem_object *obj,
+                                      const struct i915_ggtt_view *view);
 
-struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj);
-static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
-       struct i915_vma *vma;
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (vma->pin_count > 0)
-                       return true;
-       return false;
+static inline struct i915_vma *
+i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
+{
+       return i915_gem_obj_to_ggtt_view(obj, &i915_ggtt_view_normal);
 }
+bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj);
 
 /* Some GGTT VM helpers */
 #define i915_obj_to_ggtt(obj) \
@@ -2930,13 +2855,7 @@ i915_vm_to_ppgtt(struct i915_address_space *vm)
 
 static inline bool i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *obj)
 {
-       return i915_gem_obj_bound(obj, i915_obj_to_ggtt(obj));
-}
-
-static inline unsigned long
-i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *obj)
-{
-       return i915_gem_obj_offset(obj, i915_obj_to_ggtt(obj));
+       return i915_gem_obj_ggtt_bound_view(obj, &i915_ggtt_view_normal);
 }
 
 static inline unsigned long
@@ -2960,7 +2879,13 @@ i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj)
        return i915_vma_unbind(i915_gem_obj_to_ggtt(obj));
 }
 
-void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj);
+void i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj,
+                                    const struct i915_ggtt_view *view);
+static inline void
+i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj)
+{
+       i915_gem_object_ggtt_unpin_view(obj, &i915_ggtt_view_normal);
+}
 
 /* i915_gem_context.c */
 int __must_check i915_gem_context_init(struct drm_device *dev);
@@ -3032,6 +2957,17 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
                                               u32 gtt_offset,
                                               u32 size);
 
+/* i915_gem_shrinker.c */
+unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
+                             long target,
+                             unsigned flags);
+#define I915_SHRINK_PURGEABLE 0x1
+#define I915_SHRINK_UNBOUND 0x2
+#define I915_SHRINK_BOUND 0x4
+unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
+void i915_gem_shrinker_init(struct drm_i915_private *dev_priv);
+
+
 /* i915_gem_tiling.c */
 static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj)
 {
@@ -3107,10 +3043,6 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
 extern int i915_save_state(struct drm_device *dev);
 extern int i915_restore_state(struct drm_device *dev);
 
-/* i915_ums.c */
-void i915_save_display_reg(struct drm_device *dev);
-void i915_restore_display_reg(struct drm_device *dev);
-
 /* i915_sysfs.c */
 void i915_setup_sysfs(struct drm_device *dev_priv);
 void i915_teardown_sysfs(struct drm_device *dev_priv);
@@ -3182,8 +3114,7 @@ extern void i915_redisable_vga(struct drm_device *dev);
 extern void i915_redisable_vga_power_on(struct drm_device *dev);
 extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
 extern void intel_init_pch_refclk(struct drm_device *dev);
-extern void gen6_set_rps(struct drm_device *dev, u8 val);
-extern void valleyview_set_rps(struct drm_device *dev, u8 val);
+extern void intel_set_rps(struct drm_device *dev, u8 val);
 extern void intel_set_memory_cxsr(struct drm_i915_private *dev_priv,
                                  bool enable);
 extern void intel_detect_pch(struct drm_device *dev);
@@ -3196,8 +3127,6 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data,
 int i915_get_reset_stats_ioctl(struct drm_device *dev, void *data,
                               struct drm_file *file);
 
-void intel_notify_mmio_flip(struct intel_engine_cs *ring);
-
 /* overlay */
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
 extern void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e,
index c26d36cc4b313ac4d03ade4167739d7fd7be6e9c..d07c0b1fb498264ba0f6224db81434e98c7c6ff5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright Â© 2008 Intel Corporation
+ * Copyright Â© 2008-2015 Intel Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -29,9 +29,9 @@
 #include <drm/drm_vma_manager.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
+#include "i915_vgpu.h"
 #include "i915_trace.h"
 #include "intel_drv.h"
-#include <linux/oom.h>
 #include <linux/shmem_fs.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
@@ -52,15 +52,6 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
                                         struct drm_i915_fence_reg *fence,
                                         bool enable);
 
-static unsigned long i915_gem_shrinker_count(struct shrinker *shrinker,
-                                            struct shrink_control *sc);
-static unsigned long i915_gem_shrinker_scan(struct shrinker *shrinker,
-                                           struct shrink_control *sc);
-static int i915_gem_shrinker_oom(struct notifier_block *nb,
-                                unsigned long event,
-                                void *ptr);
-static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
-
 static bool cpu_cache_is_coherent(struct drm_device *dev,
                                  enum i915_cache_level level)
 {
@@ -350,7 +341,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
        struct drm_device *dev = obj->base.dev;
        void *vaddr = obj->phys_handle->vaddr + args->offset;
        char __user *user_data = to_user_ptr(args->data_ptr);
-       int ret;
+       int ret = 0;
 
        /* We manually control the domain here and pretend that it
         * remains coherent i.e. in the GTT domain, like shmem_pwrite.
@@ -359,6 +350,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
        if (ret)
                return ret;
 
+       intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU);
        if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
                unsigned long unwritten;
 
@@ -369,13 +361,18 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
                mutex_unlock(&dev->struct_mutex);
                unwritten = copy_from_user(vaddr, user_data, args->size);
                mutex_lock(&dev->struct_mutex);
-               if (unwritten)
-                       return -EFAULT;
+               if (unwritten) {
+                       ret = -EFAULT;
+                       goto out;
+               }
        }
 
        drm_clflush_virt_range(vaddr, args->size);
        i915_gem_chipset_flush(dev);
-       return 0;
+
+out:
+       intel_fb_obj_flush(obj, false);
+       return ret;
 }
 
 void *i915_gem_object_alloc(struct drm_device *dev)
@@ -809,6 +806,8 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
 
        offset = i915_gem_obj_ggtt_offset(obj) + args->offset;
 
+       intel_fb_obj_invalidate(obj, NULL, ORIGIN_GTT);
+
        while (remain > 0) {
                /* Operation in this page
                 *
@@ -829,7 +828,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
                if (fast_user_write(dev_priv->gtt.mappable, page_base,
                                    page_offset, user_data, page_length)) {
                        ret = -EFAULT;
-                       goto out_unpin;
+                       goto out_flush;
                }
 
                remain -= page_length;
@@ -837,6 +836,8 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
                offset += page_length;
        }
 
+out_flush:
+       intel_fb_obj_flush(obj, false);
 out_unpin:
        i915_gem_object_ggtt_unpin(obj);
 out:
@@ -951,6 +952,8 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
        if (ret)
                return ret;
 
+       intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU);
+
        i915_gem_object_pin_pages(obj);
 
        offset = args->offset;
@@ -1029,6 +1032,7 @@ out:
        if (needs_clflush_after)
                i915_gem_chipset_flush(dev);
 
+       intel_fb_obj_flush(obj, false);
        return ret;
 }
 
@@ -1922,12 +1926,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
        return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
 }
 
-static inline int
-i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
-{
-       return obj->madv == I915_MADV_DONTNEED;
-}
-
 /* Immediately discard the backing storage */
 static void
 i915_gem_object_truncate(struct drm_i915_gem_object *obj)
@@ -2033,85 +2031,6 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
        return 0;
 }
 
-unsigned long
-i915_gem_shrink(struct drm_i915_private *dev_priv,
-               long target, unsigned flags)
-{
-       const struct {
-               struct list_head *list;
-               unsigned int bit;
-       } phases[] = {
-               { &dev_priv->mm.unbound_list, I915_SHRINK_UNBOUND },
-               { &dev_priv->mm.bound_list, I915_SHRINK_BOUND },
-               { NULL, 0 },
-       }, *phase;
-       unsigned long count = 0;
-
-       /*
-        * As we may completely rewrite the (un)bound list whilst unbinding
-        * (due to retiring requests) we have to strictly process only
-        * one element of the list at the time, and recheck the list
-        * on every iteration.
-        *
-        * In particular, we must hold a reference whilst removing the
-        * object as we may end up waiting for and/or retiring the objects.
-        * This might release the final reference (held by the active list)
-        * and result in the object being freed from under us. This is
-        * similar to the precautions the eviction code must take whilst
-        * removing objects.
-        *
-        * Also note that although these lists do not hold a reference to
-        * the object we can safely grab one here: The final object
-        * unreferencing and the bound_list are both protected by the
-        * dev->struct_mutex and so we won't ever be able to observe an
-        * object on the bound_list with a reference count equals 0.
-        */
-       for (phase = phases; phase->list; phase++) {
-               struct list_head still_in_list;
-
-               if ((flags & phase->bit) == 0)
-                       continue;
-
-               INIT_LIST_HEAD(&still_in_list);
-               while (count < target && !list_empty(phase->list)) {
-                       struct drm_i915_gem_object *obj;
-                       struct i915_vma *vma, *v;
-
-                       obj = list_first_entry(phase->list,
-                                              typeof(*obj), global_list);
-                       list_move_tail(&obj->global_list, &still_in_list);
-
-                       if (flags & I915_SHRINK_PURGEABLE &&
-                           !i915_gem_object_is_purgeable(obj))
-                               continue;
-
-                       drm_gem_object_reference(&obj->base);
-
-                       /* For the unbound phase, this should be a no-op! */
-                       list_for_each_entry_safe(vma, v,
-                                                &obj->vma_list, vma_link)
-                               if (i915_vma_unbind(vma))
-                                       break;
-
-                       if (i915_gem_object_put_pages(obj) == 0)
-                               count += obj->base.size >> PAGE_SHIFT;
-
-                       drm_gem_object_unreference(&obj->base);
-               }
-               list_splice(&still_in_list, phase->list);
-       }
-
-       return count;
-}
-
-static unsigned long
-i915_gem_shrink_all(struct drm_i915_private *dev_priv)
-{
-       i915_gem_evict_everything(dev_priv->dev);
-       return i915_gem_shrink(dev_priv, LONG_MAX,
-                              I915_SHRINK_BOUND | I915_SHRINK_UNBOUND);
-}
-
 static int
 i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
 {
@@ -2492,6 +2411,8 @@ int __i915_add_request(struct intel_engine_cs *ring,
                list_add_tail(&request->client_list,
                              &file_priv->mm.request_list);
                spin_unlock(&file_priv->mm.lock);
+
+               request->pid = get_pid(task_pid(current));
        }
 
        trace_i915_gem_request_add(request);
@@ -2572,6 +2493,8 @@ static void i915_gem_free_request(struct drm_i915_gem_request *request)
        list_del(&request->list);
        i915_gem_request_remove_from_client(request);
 
+       put_pid(request->pid);
+
        i915_gem_request_unreference(request);
 }
 
@@ -2659,8 +2582,7 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
                if (submit_req->ctx != ring->default_context)
                        intel_lr_context_unpin(ring, submit_req->ctx);
 
-               i915_gem_context_unreference(submit_req->ctx);
-               kfree(submit_req);
+               i915_gem_request_unreference(submit_req);
        }
 
        /*
@@ -2738,27 +2660,13 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
        WARN_ON(i915_verify_lists(ring->dev));
 
-       /* Move any buffers on the active list that are no longer referenced
-        * by the ringbuffer to the flushing/inactive lists as appropriate,
-        * before we free the context associated with the requests.
+       /* Retire requests first as we use it above for the early return.
+        * If we retire requests last, we may use a later seqno and so clear
+        * the requests lists without clearing the active list, leading to
+        * confusion.
         */
-       while (!list_empty(&ring->active_list)) {
-               struct drm_i915_gem_object *obj;
-
-               obj = list_first_entry(&ring->active_list,
-                                     struct drm_i915_gem_object,
-                                     ring_list);
-
-               if (!i915_gem_request_completed(obj->last_read_req, true))
-                       break;
-
-               i915_gem_object_move_to_inactive(obj);
-       }
-
-
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
-               struct intel_ringbuffer *ringbuf;
 
                request = list_first_entry(&ring->request_list,
                                           struct drm_i915_gem_request,
@@ -2769,27 +2677,33 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
                trace_i915_gem_request_retire(request);
 
-               /* This is one of the few common intersection points
-                * between legacy ringbuffer submission and execlists:
-                * we need to tell them apart in order to find the correct
-                * ringbuffer to which the request belongs to.
-                */
-               if (i915.enable_execlists) {
-                       struct intel_context *ctx = request->ctx;
-                       ringbuf = ctx->engine[ring->id].ringbuf;
-               } else
-                       ringbuf = ring->buffer;
-
                /* We know the GPU must have read the request to have
                 * sent us the seqno + interrupt, so use the position
                 * of tail of the request to update the last known position
                 * of the GPU head.
                 */
-               ringbuf->last_retired_head = request->postfix;
+               request->ringbuf->last_retired_head = request->postfix;
 
                i915_gem_free_request(request);
        }
 
+       /* Move any buffers on the active list that are no longer referenced
+        * by the ringbuffer to the flushing/inactive lists as appropriate,
+        * before we free the context associated with the requests.
+        */
+       while (!list_empty(&ring->active_list)) {
+               struct drm_i915_gem_object *obj;
+
+               obj = list_first_entry(&ring->active_list,
+                                     struct drm_i915_gem_object,
+                                     ring_list);
+
+               if (!i915_gem_request_completed(obj->last_read_req, true))
+                       break;
+
+               i915_gem_object_move_to_inactive(obj);
+       }
+
        if (unlikely(ring->trace_irq_req &&
                     i915_gem_request_completed(ring->trace_irq_req, true))) {
                ring->irq_put(ring);
@@ -2937,9 +2851,9 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        req = obj->last_read_req;
 
        /* Do this after OLR check to make sure we make forward progress polling
-        * on this IOCTL with a timeout <=0 (like busy ioctl)
+        * on this IOCTL with a timeout == 0 (like busy ioctl)
         */
-       if (args->timeout_ns <= 0) {
+       if (args->timeout_ns == 0) {
                ret = -ETIME;
                goto out;
        }
@@ -2949,7 +2863,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        i915_gem_request_reference(req);
        mutex_unlock(&dev->struct_mutex);
 
-       ret = __i915_wait_request(req, reset_counter, true, &args->timeout_ns,
+       ret = __i915_wait_request(req, reset_counter, true,
+                                 args->timeout_ns > 0 ? &args->timeout_ns : NULL,
                                  file->driver_priv);
        mutex_lock(&dev->struct_mutex);
        i915_gem_request_unreference(req);
@@ -3512,9 +3427,9 @@ static bool i915_gem_valid_gtt_space(struct i915_vma *vma,
 static struct i915_vma *
 i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
                           struct i915_address_space *vm,
+                          const struct i915_ggtt_view *ggtt_view,
                           unsigned alignment,
-                          uint64_t flags,
-                          const struct i915_ggtt_view *view)
+                          uint64_t flags)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3526,6 +3441,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
        struct i915_vma *vma;
        int ret;
 
+       if(WARN_ON(i915_is_ggtt(vm) != !!ggtt_view))
+               return ERR_PTR(-EINVAL);
+
        fence_size = i915_gem_get_gtt_size(dev,
                                           obj->base.size,
                                           obj->tiling_mode);
@@ -3564,7 +3482,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
 
        i915_gem_object_pin_pages(obj);
 
-       vma = i915_gem_obj_lookup_or_create_vma_view(obj, vm, view);
+       vma = ggtt_view ? i915_gem_obj_lookup_or_create_ggtt_vma(obj, ggtt_view) :
+                         i915_gem_obj_lookup_or_create_vma(obj, vm);
+
        if (IS_ERR(vma))
                goto err_unpin;
 
@@ -3594,6 +3514,17 @@ search_free:
        if (ret)
                goto err_remove_node;
 
+       /*  allocate before insert / bind */
+       if (vma->vm->allocate_va_range) {
+               trace_i915_va_alloc(vma->vm, vma->node.start, vma->node.size,
+                               VM_TO_TRACE_NAME(vma->vm));
+               ret = vma->vm->allocate_va_range(vma->vm,
+                                               vma->node.start,
+                                               vma->node.size);
+               if (ret)
+                       goto err_remove_node;
+       }
+
        trace_i915_vma_bind(vma, flags);
        ret = i915_vma_bind(vma, obj->cache_level,
                            flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
@@ -3764,7 +3695,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
        }
 
        if (write)
-               intel_fb_obj_invalidate(obj, NULL);
+               intel_fb_obj_invalidate(obj, NULL, ORIGIN_GTT);
 
        trace_i915_gem_object_change_domain(obj,
                                            old_read_domains,
@@ -3946,7 +3877,8 @@ static bool is_pin_display(struct drm_i915_gem_object *obj)
 int
 i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                     u32 alignment,
-                                    struct intel_engine_cs *pipelined)
+                                    struct intel_engine_cs *pipelined,
+                                    const struct i915_ggtt_view *view)
 {
        u32 old_read_domains, old_write_domain;
        bool was_pin_display;
@@ -3982,7 +3914,9 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
         * (e.g. libkms for the bootup splash), we have to ensure that we
         * always use map_and_fenceable for all scanout buffers.
         */
-       ret = i915_gem_obj_ggtt_pin(obj, alignment, PIN_MAPPABLE);
+       ret = i915_gem_object_ggtt_pin(obj, view, alignment,
+                                      view->type == I915_GGTT_VIEW_NORMAL ?
+                                      PIN_MAPPABLE : 0);
        if (ret)
                goto err_unpin_display;
 
@@ -4010,9 +3944,11 @@ err_unpin_display:
 }
 
 void
-i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj)
+i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
+                                        const struct i915_ggtt_view *view)
 {
-       i915_gem_object_ggtt_unpin(obj);
+       i915_gem_object_ggtt_unpin_view(obj, view);
+
        obj->pin_display = is_pin_display(obj);
 }
 
@@ -4079,7 +4015,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
        }
 
        if (write)
-               intel_fb_obj_invalidate(obj, NULL);
+               intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU);
 
        trace_i915_gem_object_change_domain(obj,
                                            old_read_domains,
@@ -4161,12 +4097,12 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
        return false;
 }
 
-int
-i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
-                        struct i915_address_space *vm,
-                        uint32_t alignment,
-                        uint64_t flags,
-                        const struct i915_ggtt_view *view)
+static int
+i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
+                      struct i915_address_space *vm,
+                      const struct i915_ggtt_view *ggtt_view,
+                      uint32_t alignment,
+                      uint64_t flags)
 {
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
        struct i915_vma *vma;
@@ -4182,17 +4118,29 @@ i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
        if (WARN_ON((flags & (PIN_MAPPABLE | PIN_GLOBAL)) == PIN_MAPPABLE))
                return -EINVAL;
 
-       vma = i915_gem_obj_to_vma_view(obj, vm, view);
+       if (WARN_ON(i915_is_ggtt(vm) != !!ggtt_view))
+               return -EINVAL;
+
+       vma = ggtt_view ? i915_gem_obj_to_ggtt_view(obj, ggtt_view) :
+                         i915_gem_obj_to_vma(obj, vm);
+
+       if (IS_ERR(vma))
+               return PTR_ERR(vma);
+
        if (vma) {
                if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
                        return -EBUSY;
 
                if (i915_vma_misplaced(vma, alignment, flags)) {
+                       unsigned long offset;
+                       offset = ggtt_view ? i915_gem_obj_ggtt_offset_view(obj, ggtt_view) :
+                                            i915_gem_obj_offset(obj, vm);
                        WARN(vma->pin_count,
-                            "bo is already pinned with incorrect alignment:"
+                            "bo is already pinned in %s with incorrect alignment:"
                             " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
                             " obj->map_and_fenceable=%d\n",
-                            i915_gem_obj_offset_view(obj, vm, view->type),
+                            ggtt_view ? "ggtt" : "ppgtt",
+                            offset,
                             alignment,
                             !!(flags & PIN_MAPPABLE),
                             obj->map_and_fenceable);
@@ -4206,8 +4154,12 @@ i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
 
        bound = vma ? vma->bound : 0;
        if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
-               vma = i915_gem_object_bind_to_vm(obj, vm, alignment,
-                                                flags, view);
+               /* In true PPGTT, bind has possibly changed PDEs, which
+                * means we must do a context switch before the GPU can
+                * accurately read some of the VMAs.
+                */
+               vma = i915_gem_object_bind_to_vm(obj, vm, ggtt_view, alignment,
+                                                flags);
                if (IS_ERR(vma))
                        return PTR_ERR(vma);
        }
@@ -4233,7 +4185,7 @@ i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
                fenceable = (vma->node.size == fence_size &&
                             (vma->node.start & (fence_alignment - 1)) == 0);
 
-               mappable = (vma->node.start + obj->base.size <=
+               mappable = (vma->node.start + fence_size <=
                            dev_priv->gtt.mappable_end);
 
                obj->map_and_fenceable = mappable && fenceable;
@@ -4248,16 +4200,41 @@ i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
        return 0;
 }
 
+int
+i915_gem_object_pin(struct drm_i915_gem_object *obj,
+                   struct i915_address_space *vm,
+                   uint32_t alignment,
+                   uint64_t flags)
+{
+       return i915_gem_object_do_pin(obj, vm,
+                                     i915_is_ggtt(vm) ? &i915_ggtt_view_normal : NULL,
+                                     alignment, flags);
+}
+
+int
+i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
+                        const struct i915_ggtt_view *view,
+                        uint32_t alignment,
+                        uint64_t flags)
+{
+       if (WARN_ONCE(!view, "no view specified"))
+               return -EINVAL;
+
+       return i915_gem_object_do_pin(obj, i915_obj_to_ggtt(obj), view,
+                                     alignment, flags | PIN_GLOBAL);
+}
+
 void
-i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj)
+i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj,
+                               const struct i915_ggtt_view *view)
 {
-       struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
+       struct i915_vma *vma = i915_gem_obj_to_ggtt_view(obj, view);
 
        BUG_ON(!vma);
-       BUG_ON(vma->pin_count == 0);
-       BUG_ON(!i915_gem_obj_ggtt_bound(obj));
+       WARN_ON(vma->pin_count == 0);
+       WARN_ON(!i915_gem_obj_ggtt_bound_view(obj, view));
 
-       if (--vma->pin_count == 0)
+       if (--vma->pin_count == 0 && view->type == I915_GGTT_VIEW_NORMAL)
                obj->pin_mappable = false;
 }
 
@@ -4378,7 +4355,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
                obj->madv = args->madv;
 
        /* if the object is no longer attached, discard its backing storage */
-       if (i915_gem_object_is_purgeable(obj) && obj->pages == NULL)
+       if (obj->madv == I915_MADV_DONTNEED && obj->pages == NULL)
                i915_gem_object_truncate(obj);
 
        args->retained = obj->madv != __I915_MADV_PURGED;
@@ -4553,15 +4530,33 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
        intel_runtime_pm_put(dev_priv);
 }
 
-struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
-                                         struct i915_address_space *vm,
-                                         const struct i915_ggtt_view *view)
+struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
+                                    struct i915_address_space *vm)
 {
        struct i915_vma *vma;
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (vma->vm == vm && vma->ggtt_view.type == view->type)
+       list_for_each_entry(vma, &obj->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
+               if (vma->vm == vm)
                        return vma;
+       }
+       return NULL;
+}
+
+struct i915_vma *i915_gem_obj_to_ggtt_view(struct drm_i915_gem_object *obj,
+                                          const struct i915_ggtt_view *view)
+{
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
+       struct i915_vma *vma;
+
+       if (WARN_ONCE(!view, "no view specified"))
+               return ERR_PTR(-EINVAL);
 
+       list_for_each_entry(vma, &obj->vma_list, vma_link)
+               if (vma->vm == ggtt &&
+                   i915_ggtt_view_equal(&vma->ggtt_view, view))
+                       return vma;
        return NULL;
 }
 
@@ -4608,10 +4603,6 @@ i915_gem_suspend(struct drm_device *dev)
 
        i915_gem_retire_requests(dev);
 
-       /* Under UMS, be paranoid and evict. */
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               i915_gem_evict_everything(dev);
-
        i915_gem_stop_ringbuffers(dev);
        mutex_unlock(&dev->struct_mutex);
 
@@ -4793,6 +4784,9 @@ i915_gem_init_hw(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt())
                return -EIO;
 
+       /* Double layer security blanket, see i915_gem_init() */
+       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
        if (dev_priv->ellc_size)
                I915_WRITE(HSW_IDICR, I915_READ(HSW_IDICR) | IDIHASHMSK(0xf));
 
@@ -4825,7 +4819,7 @@ i915_gem_init_hw(struct drm_device *dev)
        for_each_ring(ring, dev_priv, i) {
                ret = ring->init_hw(ring);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
        for (i = 0; i < NUM_L3_SLICES(dev); i++)
@@ -4842,9 +4836,11 @@ i915_gem_init_hw(struct drm_device *dev)
                DRM_ERROR("Context enable failed %d\n", ret);
                i915_gem_cleanup_ringbuffer(dev);
 
-               return ret;
+               goto out;
        }
 
+out:
+       intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
        return ret;
 }
 
@@ -4878,6 +4874,14 @@ int i915_gem_init(struct drm_device *dev)
                dev_priv->gt.stop_ring = intel_logical_ring_stop;
        }
 
+       /* This is just a security blanket to placate dragons.
+        * On some systems, we very sporadically observe that the first TLBs
+        * used by the CS may be stale, despite us poking the TLB reset. If
+        * we hold the forcewake during initialisation these problems
+        * just magically go away.
+        */
+       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
        ret = i915_gem_init_userptr(dev);
        if (ret)
                goto out_unlock;
@@ -4904,6 +4908,7 @@ int i915_gem_init(struct drm_device *dev)
        }
 
 out_unlock:
+       intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
        mutex_unlock(&dev->struct_mutex);
 
        return ret;
@@ -4968,18 +4973,8 @@ i915_gem_load(struct drm_device *dev)
                          i915_gem_idle_work_handler);
        init_waitqueue_head(&dev_priv->gpu_error.reset_queue);
 
-       /* On GEN3 we really need to make sure the ARB C3 LP bit is set */
-       if (!drm_core_check_feature(dev, DRIVER_MODESET) && IS_GEN3(dev)) {
-               I915_WRITE(MI_ARB_STATE,
-                          _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE));
-       }
-
        dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL;
 
-       /* Old X drivers will take 0-2 for front, back, depth buffers */
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               dev_priv->fence_reg_start = 3;
-
        if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev))
                dev_priv->num_fence_regs = 32;
        else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
@@ -4987,6 +4982,10 @@ i915_gem_load(struct drm_device *dev)
        else
                dev_priv->num_fence_regs = 8;
 
+       if (intel_vgpu_active(dev))
+               dev_priv->num_fence_regs =
+                               I915_READ(vgtif_reg(avail_rs.fence_num));
+
        /* Initialize fence registers to zero */
        INIT_LIST_HEAD(&dev_priv->mm.fence_list);
        i915_gem_restore_fences(dev);
@@ -4996,13 +4995,7 @@ i915_gem_load(struct drm_device *dev)
 
        dev_priv->mm.interruptible = true;
 
-       dev_priv->mm.shrinker.scan_objects = i915_gem_shrinker_scan;
-       dev_priv->mm.shrinker.count_objects = i915_gem_shrinker_count;
-       dev_priv->mm.shrinker.seeks = DEFAULT_SEEKS;
-       register_shrinker(&dev_priv->mm.shrinker);
-
-       dev_priv->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom;
-       register_oom_notifier(&dev_priv->mm.oom_notifier);
+       i915_gem_shrinker_init(dev_priv);
 
        i915_gem_batch_pool_init(dev, &dev_priv->mm.batch_pool);
 
@@ -5094,106 +5087,70 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
        }
 }
 
-static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
-{
-       if (!mutex_is_locked(mutex))
-               return false;
-
-#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
-       return mutex->owner == task;
-#else
-       /* Since UP may be pre-empted, we cannot assume that we own the lock */
-       return false;
-#endif
-}
-
-static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock)
+/* All the new VM stuff */
+unsigned long
+i915_gem_obj_offset(struct drm_i915_gem_object *o,
+                   struct i915_address_space *vm)
 {
-       if (!mutex_trylock(&dev->struct_mutex)) {
-               if (!mutex_is_locked_by(&dev->struct_mutex, current))
-                       return false;
+       struct drm_i915_private *dev_priv = o->base.dev->dev_private;
+       struct i915_vma *vma;
 
-               if (to_i915(dev)->mm.shrinker_no_lock_stealing)
-                       return false;
+       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
 
-               *unlock = false;
-       } else
-               *unlock = true;
+       list_for_each_entry(vma, &o->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
+               if (vma->vm == vm)
+                       return vma->node.start;
+       }
 
-       return true;
+       WARN(1, "%s vma for this object not found.\n",
+            i915_is_ggtt(vm) ? "global" : "ppgtt");
+       return -1;
 }
 
-static int num_vma_bound(struct drm_i915_gem_object *obj)
+unsigned long
+i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
+                             const struct i915_ggtt_view *view)
 {
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(o);
        struct i915_vma *vma;
-       int count = 0;
-
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (drm_mm_node_allocated(&vma->node))
-                       count++;
-
-       return count;
-}
 
-static unsigned long
-i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(shrinker, struct drm_i915_private, mm.shrinker);
-       struct drm_device *dev = dev_priv->dev;
-       struct drm_i915_gem_object *obj;
-       unsigned long count;
-       bool unlock;
-
-       if (!i915_gem_shrinker_lock(dev, &unlock))
-               return 0;
-
-       count = 0;
-       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
-               if (obj->pages_pin_count == 0)
-                       count += obj->base.size >> PAGE_SHIFT;
-
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (!i915_gem_obj_is_pinned(obj) &&
-                   obj->pages_pin_count == num_vma_bound(obj))
-                       count += obj->base.size >> PAGE_SHIFT;
-       }
-
-       if (unlock)
-               mutex_unlock(&dev->struct_mutex);
+       list_for_each_entry(vma, &o->vma_list, vma_link)
+               if (vma->vm == ggtt &&
+                   i915_ggtt_view_equal(&vma->ggtt_view, view))
+                       return vma->node.start;
 
-       return count;
+       WARN(1, "global vma for this object not found.\n");
+       return -1;
 }
 
-/* All the new VM stuff */
-unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
-                                      struct i915_address_space *vm,
-                                      enum i915_ggtt_view_type view)
+bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
+                       struct i915_address_space *vm)
 {
-       struct drm_i915_private *dev_priv = o->base.dev->dev_private;
        struct i915_vma *vma;
 
-       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
-
        list_for_each_entry(vma, &o->vma_list, vma_link) {
-               if (vma->vm == vm && vma->ggtt_view.type == view)
-                       return vma->node.start;
-
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
+               if (vma->vm == vm && drm_mm_node_allocated(&vma->node))
+                       return true;
        }
-       WARN(1, "%s vma for this object not found.\n",
-            i915_is_ggtt(vm) ? "global" : "ppgtt");
-       return -1;
+
+       return false;
 }
 
-bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
-                            struct i915_address_space *vm,
-                            enum i915_ggtt_view_type view)
+bool i915_gem_obj_ggtt_bound_view(struct drm_i915_gem_object *o,
+                                 const struct i915_ggtt_view *view)
 {
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(o);
        struct i915_vma *vma;
 
        list_for_each_entry(vma, &o->vma_list, vma_link)
-               if (vma->vm == vm &&
-                   vma->ggtt_view.type == view &&
+               if (vma->vm == ggtt &&
+                   i915_ggtt_view_equal(&vma->ggtt_view, view) &&
                    drm_mm_node_allocated(&vma->node))
                        return true;
 
@@ -5221,118 +5178,26 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
 
        BUG_ON(list_empty(&o->vma_list));
 
-       list_for_each_entry(vma, &o->vma_list, vma_link)
+       list_for_each_entry(vma, &o->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
                if (vma->vm == vm)
                        return vma->node.size;
-
+       }
        return 0;
 }
 
-static unsigned long
-i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
+bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj)
 {
-       struct drm_i915_private *dev_priv =
-               container_of(shrinker, struct drm_i915_private, mm.shrinker);
-       struct drm_device *dev = dev_priv->dev;
-       unsigned long freed;
-       bool unlock;
-
-       if (!i915_gem_shrinker_lock(dev, &unlock))
-               return SHRINK_STOP;
-
-       freed = i915_gem_shrink(dev_priv,
-                               sc->nr_to_scan,
-                               I915_SHRINK_BOUND |
-                               I915_SHRINK_UNBOUND |
-                               I915_SHRINK_PURGEABLE);
-       if (freed < sc->nr_to_scan)
-               freed += i915_gem_shrink(dev_priv,
-                                        sc->nr_to_scan - freed,
-                                        I915_SHRINK_BOUND |
-                                        I915_SHRINK_UNBOUND);
-       if (unlock)
-               mutex_unlock(&dev->struct_mutex);
-
-       return freed;
-}
-
-static int
-i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(nb, struct drm_i915_private, mm.oom_notifier);
-       struct drm_device *dev = dev_priv->dev;
-       struct drm_i915_gem_object *obj;
-       unsigned long timeout = msecs_to_jiffies(5000) + 1;
-       unsigned long pinned, bound, unbound, freed_pages;
-       bool was_interruptible;
-       bool unlock;
-
-       while (!i915_gem_shrinker_lock(dev, &unlock) && --timeout) {
-               schedule_timeout_killable(1);
-               if (fatal_signal_pending(current))
-                       return NOTIFY_DONE;
-       }
-       if (timeout == 0) {
-               pr_err("Unable to purge GPU memory due lock contention.\n");
-               return NOTIFY_DONE;
-       }
-
-       was_interruptible = dev_priv->mm.interruptible;
-       dev_priv->mm.interruptible = false;
-
-       freed_pages = i915_gem_shrink_all(dev_priv);
-
-       dev_priv->mm.interruptible = was_interruptible;
-
-       /* Because we may be allocating inside our own driver, we cannot
-        * assert that there are no objects with pinned pages that are not
-        * being pointed to by hardware.
-        */
-       unbound = bound = pinned = 0;
-       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
-               if (!obj->base.filp) /* not backed by a freeable object */
-                       continue;
-
-               if (obj->pages_pin_count)
-                       pinned += obj->base.size;
-               else
-                       unbound += obj->base.size;
-       }
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (!obj->base.filp)
+       struct i915_vma *vma;
+       list_for_each_entry(vma, &obj->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
                        continue;
-
-               if (obj->pages_pin_count)
-                       pinned += obj->base.size;
-               else
-                       bound += obj->base.size;
+               if (vma->pin_count > 0)
+                       return true;
        }
-
-       if (unlock)
-               mutex_unlock(&dev->struct_mutex);
-
-       if (freed_pages || unbound || bound)
-               pr_info("Purging GPU memory, %lu bytes freed, %lu bytes still pinned.\n",
-                       freed_pages << PAGE_SHIFT, pinned);
-       if (unbound || bound)
-               pr_err("%lu and %lu bytes still available in the "
-                      "bound and unbound GPU page lists.\n",
-                      bound, unbound);
-
-       *(unsigned long *)ptr += freed_pages;
-       return NOTIFY_DONE;
+       return false;
 }
 
-struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
-{
-       struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
-       struct i915_vma *vma;
-
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (vma->vm == ggtt &&
-                   vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
-                       return vma;
-
-       return NULL;
-}
index 8603bf48d3eeba142913e494131396641c8cc73b..f3e84c44d0091a00195d3b827c36de435d755ed5 100644 (file)
@@ -296,11 +296,15 @@ void i915_gem_context_reset(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
-       /* In execlists mode we will unreference the context when the execlist
-        * queue is cleared and the requests destroyed.
-        */
-       if (i915.enable_execlists)
+       if (i915.enable_execlists) {
+               struct intel_context *ctx;
+
+               list_for_each_entry(ctx, &dev_priv->context_list, link) {
+                       intel_lr_context_reset(dev, ctx);
+               }
+
                return;
+       }
 
        for (i = 0; i < I915_NUM_RINGS; i++) {
                struct intel_engine_cs *ring = &dev_priv->ring[i];
@@ -565,6 +569,66 @@ mi_set_context(struct intel_engine_cs *ring,
        return ret;
 }
 
+static inline bool should_skip_switch(struct intel_engine_cs *ring,
+                                     struct intel_context *from,
+                                     struct intel_context *to)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+       if (to->remap_slice)
+               return false;
+
+       if (to->ppgtt) {
+               if (from == to && !test_bit(ring->id,
+                               &to->ppgtt->pd_dirty_rings))
+                       return true;
+       } else if (dev_priv->mm.aliasing_ppgtt) {
+               if (from == to && !test_bit(ring->id,
+                               &dev_priv->mm.aliasing_ppgtt->pd_dirty_rings))
+                       return true;
+       }
+
+       return false;
+}
+
+static bool
+needs_pd_load_pre(struct intel_engine_cs *ring, struct intel_context *to)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+       if (!to->ppgtt)
+               return false;
+
+       if (INTEL_INFO(ring->dev)->gen < 8)
+               return true;
+
+       if (ring != &dev_priv->ring[RCS])
+               return true;
+
+       return false;
+}
+
+static bool
+needs_pd_load_post(struct intel_engine_cs *ring, struct intel_context *to,
+               u32 hw_flags)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+       if (!to->ppgtt)
+               return false;
+
+       if (!IS_GEN8(ring->dev))
+               return false;
+
+       if (ring != &dev_priv->ring[RCS])
+               return false;
+
+       if (hw_flags & MI_RESTORE_INHIBIT)
+               return true;
+
+       return false;
+}
+
 static int do_switch(struct intel_engine_cs *ring,
                     struct intel_context *to)
 {
@@ -580,7 +644,7 @@ static int do_switch(struct intel_engine_cs *ring,
                BUG_ON(!i915_gem_obj_is_pinned(from->legacy_hw_ctx.rcs_state));
        }
 
-       if (from == to && !to->remap_slice)
+       if (should_skip_switch(ring, from, to))
                return 0;
 
        /* Trying to pin first makes error handling easier. */
@@ -598,11 +662,18 @@ static int do_switch(struct intel_engine_cs *ring,
         */
        from = ring->last_context;
 
-       if (to->ppgtt) {
+       if (needs_pd_load_pre(ring, to)) {
+               /* Older GENs and non render rings still want the load first,
+                * "PP_DCLV followed by PP_DIR_BASE register through Load
+                * Register Immediate commands in Ring Buffer before submitting
+                * a context."*/
                trace_switch_mm(ring, to);
                ret = to->ppgtt->switch_mm(to->ppgtt, ring);
                if (ret)
                        goto unpin_out;
+
+               /* Doing a PD load always reloads the page dirs */
+               clear_bit(ring->id, &to->ppgtt->pd_dirty_rings);
        }
 
        if (ring != &dev_priv->ring[RCS]) {
@@ -633,13 +704,41 @@ static int do_switch(struct intel_engine_cs *ring,
                        goto unpin_out;
        }
 
-       if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to))
+       if (!to->legacy_hw_ctx.initialized) {
                hw_flags |= MI_RESTORE_INHIBIT;
+               /* NB: If we inhibit the restore, the context is not allowed to
+                * die because future work may end up depending on valid address
+                * space. This means we must enforce that a page table load
+                * occur when this occurs. */
+       } else if (to->ppgtt &&
+                       test_and_clear_bit(ring->id, &to->ppgtt->pd_dirty_rings))
+               hw_flags |= MI_FORCE_RESTORE;
+
+       /* We should never emit switch_mm more than once */
+       WARN_ON(needs_pd_load_pre(ring, to) &&
+                       needs_pd_load_post(ring, to, hw_flags));
 
        ret = mi_set_context(ring, to, hw_flags);
        if (ret)
                goto unpin_out;
 
+       /* GEN8 does *not* require an explicit reload if the PDPs have been
+        * setup, and we do not wish to move them.
+        */
+       if (needs_pd_load_post(ring, to, hw_flags)) {
+               trace_switch_mm(ring, to);
+               ret = to->ppgtt->switch_mm(to->ppgtt, ring);
+               /* The hardware context switch is emitted, but we haven't
+                * actually changed the state - so it's probably safe to bail
+                * here. Still, let the user know something dangerous has
+                * happened.
+                */
+               if (ret) {
+                       DRM_ERROR("Failed to change address space on context switch\n");
+                       goto unpin_out;
+               }
+       }
+
        for (i = 0; i < MAX_L3_SLICES; i++) {
                if (!(to->remap_slice & (1<<i)))
                        continue;
@@ -677,7 +776,7 @@ static int do_switch(struct intel_engine_cs *ring,
                i915_gem_context_unreference(from);
        }
 
-       uninitialized = !to->legacy_hw_ctx.initialized && from == NULL;
+       uninitialized = !to->legacy_hw_ctx.initialized;
        to->legacy_hw_ctx.initialized = true;
 
 done:
index e3a49d94da3a794fe3524fb79eadefa423b266b8..d09e35ed9c9aa5f80e784397b0b799c5833ab64c 100644 (file)
@@ -63,6 +63,10 @@ mark_free(struct i915_vma *vma, struct list_head *unwind)
  *
  * This function is used by the object/vma binding code.
  *
+ * Since this function is only used to free up virtual address space it only
+ * ignores pinned vmas, and not object where the backing storage itself is
+ * pinned. Hence obj->pages_pin_count does not protect against eviction.
+ *
  * To clarify: This is for freeing up virtual address space, not for freeing
  * memory in e.g. the shrinker.
  */
index b773368fc62c8ac67717f6770ce20fd642a1bc8c..a3190e793ed43744980bedba4ed42e1d0e38d597 100644 (file)
@@ -251,7 +251,6 @@ static inline int use_cpu_reloc(struct drm_i915_gem_object *obj)
 {
        return (HAS_LLC(obj->base.dev) ||
                obj->base.write_domain == I915_GEM_DOMAIN_CPU ||
-               !obj->map_and_fenceable ||
                obj->cache_level != I915_CACHE_NONE);
 }
 
@@ -337,6 +336,51 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
        return 0;
 }
 
+static void
+clflush_write32(void *addr, uint32_t value)
+{
+       /* This is not a fast path, so KISS. */
+       drm_clflush_virt_range(addr, sizeof(uint32_t));
+       *(uint32_t *)addr = value;
+       drm_clflush_virt_range(addr, sizeof(uint32_t));
+}
+
+static int
+relocate_entry_clflush(struct drm_i915_gem_object *obj,
+                      struct drm_i915_gem_relocation_entry *reloc,
+                      uint64_t target_offset)
+{
+       struct drm_device *dev = obj->base.dev;
+       uint32_t page_offset = offset_in_page(reloc->offset);
+       uint64_t delta = (int)reloc->delta + target_offset;
+       char *vaddr;
+       int ret;
+
+       ret = i915_gem_object_set_to_gtt_domain(obj, true);
+       if (ret)
+               return ret;
+
+       vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+                               reloc->offset >> PAGE_SHIFT));
+       clflush_write32(vaddr + page_offset, lower_32_bits(delta));
+
+       if (INTEL_INFO(dev)->gen >= 8) {
+               page_offset = offset_in_page(page_offset + sizeof(uint32_t));
+
+               if (page_offset == 0) {
+                       kunmap_atomic(vaddr);
+                       vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+                           (reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT));
+               }
+
+               clflush_write32(vaddr + page_offset, upper_32_bits(delta));
+       }
+
+       kunmap_atomic(vaddr);
+
+       return 0;
+}
+
 static int
 i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                                   struct eb_vmas *eb,
@@ -426,8 +470,14 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
 
        if (use_cpu_reloc(obj))
                ret = relocate_entry_cpu(obj, reloc, target_offset);
-       else
+       else if (obj->map_and_fenceable)
                ret = relocate_entry_gtt(obj, reloc, target_offset);
+       else if (cpu_has_clflush)
+               ret = relocate_entry_clflush(obj, reloc, target_offset);
+       else {
+               WARN_ONCE(1, "Impossible case in relocation handling\n");
+               ret = -ENODEV;
+       }
 
        if (ret)
                return ret;
@@ -525,6 +575,12 @@ i915_gem_execbuffer_relocate(struct eb_vmas *eb)
        return ret;
 }
 
+static bool only_mappable_for_reloc(unsigned int flags)
+{
+       return (flags & (EXEC_OBJECT_NEEDS_FENCE | __EXEC_OBJECT_NEEDS_MAP)) ==
+               __EXEC_OBJECT_NEEDS_MAP;
+}
+
 static int
 i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
                                struct intel_engine_cs *ring,
@@ -536,14 +592,21 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
        int ret;
 
        flags = 0;
-       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP)
-               flags |= PIN_GLOBAL | PIN_MAPPABLE;
-       if (entry->flags & EXEC_OBJECT_NEEDS_GTT)
-               flags |= PIN_GLOBAL;
-       if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
-               flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS;
+       if (!drm_mm_node_allocated(&vma->node)) {
+               if (entry->flags & __EXEC_OBJECT_NEEDS_MAP)
+                       flags |= PIN_GLOBAL | PIN_MAPPABLE;
+               if (entry->flags & EXEC_OBJECT_NEEDS_GTT)
+                       flags |= PIN_GLOBAL;
+               if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
+                       flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS;
+       }
 
        ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, flags);
+       if ((ret == -ENOSPC  || ret == -E2BIG) &&
+           only_mappable_for_reloc(entry->flags))
+               ret = i915_gem_object_pin(obj, vma->vm,
+                                         entry->alignment,
+                                         flags & ~(PIN_GLOBAL | PIN_MAPPABLE));
        if (ret)
                return ret;
 
@@ -605,13 +668,14 @@ eb_vma_misplaced(struct i915_vma *vma)
            vma->node.start & (entry->alignment - 1))
                return true;
 
-       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable)
-               return true;
-
        if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS &&
            vma->node.start < BATCH_OFFSET_BIAS)
                return true;
 
+       /* avoid costly ping-pong once a batch bo ended up non-mappable */
+       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable)
+               return !only_mappable_for_reloc(entry->flags);
+
        return false;
 }
 
@@ -971,7 +1035,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
                        obj->dirty = 1;
                        i915_gem_request_assign(&obj->last_write_req, req);
 
-                       intel_fb_obj_invalidate(obj, ring);
+                       intel_fb_obj_invalidate(obj, ring, ORIGIN_CS);
 
                        /* update for the implicit flush after a batch */
                        obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
@@ -1076,16 +1140,15 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
                          struct drm_i915_gem_object *batch_obj,
                          u32 batch_start_offset,
                          u32 batch_len,
-                         bool is_master,
-                         u32 *flags)
+                         bool is_master)
 {
        struct drm_i915_private *dev_priv = to_i915(batch_obj->base.dev);
        struct drm_i915_gem_object *shadow_batch_obj;
-       bool need_reloc = false;
+       struct i915_vma *vma;
        int ret;
 
        shadow_batch_obj = i915_gem_batch_pool_get(&dev_priv->mm.batch_pool,
-                                                  batch_obj->base.size);
+                                                  PAGE_ALIGN(batch_len));
        if (IS_ERR(shadow_batch_obj))
                return shadow_batch_obj;
 
@@ -1095,40 +1158,30 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
                              batch_start_offset,
                              batch_len,
                              is_master);
-       if (ret) {
-               if (ret == -EACCES)
-                       return batch_obj;
-       } else {
-               struct i915_vma *vma;
+       if (ret)
+               goto err;
 
-               memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry));
+       ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 0, 0);
+       if (ret)
+               goto err;
 
-               vma = i915_gem_obj_to_ggtt(shadow_batch_obj);
-               vma->exec_entry = shadow_exec_entry;
-               vma->exec_entry->flags = __EXEC_OBJECT_PURGEABLE;
-               drm_gem_object_reference(&shadow_batch_obj->base);
-               i915_gem_execbuffer_reserve_vma(vma, ring, &need_reloc);
-               list_add_tail(&vma->exec_list, &eb->vmas);
+       memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry));
 
-               shadow_batch_obj->base.pending_read_domains =
-                       batch_obj->base.pending_read_domains;
+       vma = i915_gem_obj_to_ggtt(shadow_batch_obj);
+       vma->exec_entry = shadow_exec_entry;
+       vma->exec_entry->flags = __EXEC_OBJECT_PURGEABLE | __EXEC_OBJECT_HAS_PIN;
+       drm_gem_object_reference(&shadow_batch_obj->base);
+       list_add_tail(&vma->exec_list, &eb->vmas);
 
-               /*
-                * Set the DISPATCH_SECURE bit to remove the NON_SECURE
-                * bit from MI_BATCH_BUFFER_START commands issued in the
-                * dispatch_execbuffer implementations. We specifically
-                * don't want that set when the command parser is
-                * enabled.
-                *
-                * FIXME: with aliasing ppgtt, buffers that should only
-                * be in ggtt still end up in the aliasing ppgtt. remove
-                * this check when that is fixed.
-                */
-               if (USES_FULL_PPGTT(dev))
-                       *flags |= I915_DISPATCH_SECURE;
-       }
+       shadow_batch_obj->base.pending_read_domains = I915_GEM_DOMAIN_COMMAND;
+
+       return shadow_batch_obj;
 
-       return ret ? ERR_PTR(ret) : shadow_batch_obj;
+err:
+       if (ret == -EACCES) /* unhandled chained batch */
+               return batch_obj;
+       else
+               return ERR_PTR(ret);
 }
 
 int
@@ -1138,7 +1191,7 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
                               struct drm_i915_gem_execbuffer2 *args,
                               struct list_head *vmas,
                               struct drm_i915_gem_object *batch_obj,
-                              u64 exec_start, u32 flags)
+                              u64 exec_start, u32 dispatch_flags)
 {
        struct drm_clip_rect *cliprects = NULL;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1198,6 +1251,13 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
        if (ret)
                goto error;
 
+       if (ctx->ppgtt)
+               WARN(ctx->ppgtt->pd_dirty_rings & (1<<ring->id),
+                       "%s didn't clear reload\n", ring->name);
+       else if (dev_priv->mm.aliasing_ppgtt)
+               WARN(dev_priv->mm.aliasing_ppgtt->pd_dirty_rings &
+                       (1<<ring->id), "%s didn't clear reload\n", ring->name);
+
        instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
        instp_mask = I915_EXEC_CONSTANTS_MASK;
        switch (instp_mode) {
@@ -1266,19 +1326,19 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
 
                        ret = ring->dispatch_execbuffer(ring,
                                                        exec_start, exec_len,
-                                                       flags);
+                                                       dispatch_flags);
                        if (ret)
                                goto error;
                }
        } else {
                ret = ring->dispatch_execbuffer(ring,
                                                exec_start, exec_len,
-                                               flags);
+                                               dispatch_flags);
                if (ret)
                        return ret;
        }
 
-       trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), flags);
+       trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), dispatch_flags);
 
        i915_gem_execbuffer_move_to_active(vmas, ring);
        i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
@@ -1353,7 +1413,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        struct i915_address_space *vm;
        const u32 ctx_id = i915_execbuffer2_get_context_id(*args);
        u64 exec_start = args->batch_start_offset;
-       u32 flags;
+       u32 dispatch_flags;
        int ret;
        bool need_relocs;
 
@@ -1364,15 +1424,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        if (ret)
                return ret;
 
-       flags = 0;
+       dispatch_flags = 0;
        if (args->flags & I915_EXEC_SECURE) {
                if (!file->is_master || !capable(CAP_SYS_ADMIN))
                    return -EPERM;
 
-               flags |= I915_DISPATCH_SECURE;
+               dispatch_flags |= I915_DISPATCH_SECURE;
        }
        if (args->flags & I915_EXEC_IS_PINNED)
-               flags |= I915_DISPATCH_PINNED;
+               dispatch_flags |= I915_DISPATCH_PINNED;
 
        if ((args->flags & I915_EXEC_RING_MASK) > LAST_USER_RING) {
                DRM_DEBUG("execbuf with unknown ring: %d\n",
@@ -1487,19 +1547,34 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                goto err;
        }
 
-       if (i915_needs_cmd_parser(ring)) {
+       if (i915_needs_cmd_parser(ring) && args->batch_len) {
                batch_obj = i915_gem_execbuffer_parse(ring,
                                                      &shadow_exec_entry,
                                                      eb,
                                                      batch_obj,
                                                      args->batch_start_offset,
                                                      args->batch_len,
-                                                     file->is_master,
-                                                     &flags);
+                                                     file->is_master);
                if (IS_ERR(batch_obj)) {
                        ret = PTR_ERR(batch_obj);
                        goto err;
                }
+
+               /*
+                * Set the DISPATCH_SECURE bit to remove the NON_SECURE
+                * bit from MI_BATCH_BUFFER_START commands issued in the
+                * dispatch_execbuffer implementations. We specifically
+                * don't want that set when the command parser is
+                * enabled.
+                *
+                * FIXME: with aliasing ppgtt, buffers that should only
+                * be in ggtt still end up in the aliasing ppgtt. remove
+                * this check when that is fixed.
+                */
+               if (USES_FULL_PPGTT(dev))
+                       dispatch_flags |= I915_DISPATCH_SECURE;
+
+               exec_start = 0;
        }
 
        batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
@@ -1507,14 +1582,14 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
         * batch" bit. Hence we need to pin secure batches into the global gtt.
         * hsw should have this fixed, but bdw mucks it up again. */
-       if (flags & I915_DISPATCH_SECURE) {
+       if (dispatch_flags & I915_DISPATCH_SECURE) {
                /*
                 * So on first glance it looks freaky that we pin the batch here
                 * outside of the reservation loop. But:
                 * - The batch is already pinned into the relevant ppgtt, so we
                 *   already have the backing storage fully allocated.
                 * - No other BO uses the global gtt (well contexts, but meh),
-                *   so we don't really have issues with mutliple objects not
+                *   so we don't really have issues with multiple objects not
                 *   fitting due to fragmentation.
                 * So this is actually safe.
                 */
@@ -1527,7 +1602,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                exec_start += i915_gem_obj_offset(batch_obj, vm);
 
        ret = dev_priv->gt.do_execbuf(dev, file, ring, ctx, args,
-                                     &eb->vmas, batch_obj, exec_start, flags);
+                                     &eb->vmas, batch_obj, exec_start,
+                                     dispatch_flags);
 
        /*
         * FIXME: We crucially rely upon the active tracking for the (ppgtt)
@@ -1535,7 +1611,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
         * needs to be adjusted to also track the ggtt batch vma properly as
         * active.
         */
-       if (flags & I915_DISPATCH_SECURE)
+       if (dispatch_flags & I915_DISPATCH_SECURE)
                i915_gem_object_ggtt_unpin(batch_obj);
 err:
        /* the request owns the ref now */
index 746f77fb57a314d5b94542b12b67b7a16bfb50eb..0239fbff7bf7282930aa6f345c62ab5c8b502456 100644 (file)
@@ -27,6 +27,7 @@
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
+#include "i915_vgpu.h"
 #include "i915_trace.h"
 #include "intel_drv.h"
 
@@ -66,8 +67,9 @@
  * i915_ggtt_view_type and struct i915_ggtt_view.
  *
  * A new flavour of core GEM functions which work with GGTT bound objects were
- * added with the _view suffix. They take the struct i915_ggtt_view parameter
- * encapsulating all metadata required to implement a view.
+ * added with the _ggtt_ infix, and sometimes with _view postfix to avoid
+ * renaming  in large amounts of code. They take the struct i915_ggtt_view
+ * parameter encapsulating all metadata required to implement a view.
  *
  * As a helper for callers which are only interested in the normal view,
  * globally const i915_ggtt_view_normal singleton instance exists. All old core
@@ -91,6 +93,9 @@
  */
 
 const struct i915_ggtt_view i915_ggtt_view_normal;
+const struct i915_ggtt_view i915_ggtt_view_rotated = {
+        .type = I915_GGTT_VIEW_ROTATED
+};
 
 static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv);
 static void chv_setup_private_ppat(struct drm_i915_private *dev_priv);
@@ -103,6 +108,9 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
        has_aliasing_ppgtt = INTEL_INFO(dev)->gen >= 6;
        has_full_ppgtt = INTEL_INFO(dev)->gen >= 7;
 
+       if (intel_vgpu_active(dev))
+               has_full_ppgtt = false; /* emulation is too hard */
+
        /*
         * We don't allow disabling PPGTT for gen9+ as it's a requirement for
         * execlists, the sole mechanism available to submit work.
@@ -138,17 +146,16 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
                return has_aliasing_ppgtt ? 1 : 0;
 }
 
-
 static void ppgtt_bind_vma(struct i915_vma *vma,
                           enum i915_cache_level cache_level,
                           u32 flags);
 static void ppgtt_unbind_vma(struct i915_vma *vma);
 
-static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
-                                            enum i915_cache_level level,
-                                            bool valid)
+static inline gen8_pte_t gen8_pte_encode(dma_addr_t addr,
+                                        enum i915_cache_level level,
+                                        bool valid)
 {
-       gen8_gtt_pte_t pte = valid ? _PAGE_PRESENT | _PAGE_RW : 0;
+       gen8_pte_t pte = valid ? _PAGE_PRESENT | _PAGE_RW : 0;
        pte |= addr;
 
        switch (level) {
@@ -166,11 +173,11 @@ static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static inline gen8_ppgtt_pde_t gen8_pde_encode(struct drm_device *dev,
-                                            dma_addr_t addr,
-                                            enum i915_cache_level level)
+static inline gen8_pde_t gen8_pde_encode(struct drm_device *dev,
+                                         dma_addr_t addr,
+                                         enum i915_cache_level level)
 {
-       gen8_ppgtt_pde_t pde = _PAGE_PRESENT | _PAGE_RW;
+       gen8_pde_t pde = _PAGE_PRESENT | _PAGE_RW;
        pde |= addr;
        if (level != I915_CACHE_NONE)
                pde |= PPAT_CACHED_PDE_INDEX;
@@ -179,11 +186,11 @@ static inline gen8_ppgtt_pde_t gen8_pde_encode(struct drm_device *dev,
        return pde;
 }
 
-static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid, u32 unused)
+static gen6_pte_t snb_pte_encode(dma_addr_t addr,
+                                enum i915_cache_level level,
+                                bool valid, u32 unused)
 {
-       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
+       gen6_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -201,11 +208,11 @@ static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid, u32 unused)
+static gen6_pte_t ivb_pte_encode(dma_addr_t addr,
+                                enum i915_cache_level level,
+                                bool valid, u32 unused)
 {
-       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
+       gen6_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -225,11 +232,11 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid, u32 flags)
+static gen6_pte_t byt_pte_encode(dma_addr_t addr,
+                                enum i915_cache_level level,
+                                bool valid, u32 flags)
 {
-       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
+       gen6_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        if (!(flags & PTE_READ_ONLY))
@@ -241,11 +248,11 @@ static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid, u32 unused)
+static gen6_pte_t hsw_pte_encode(dma_addr_t addr,
+                                enum i915_cache_level level,
+                                bool valid, u32 unused)
 {
-       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
+       gen6_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
 
        if (level != I915_CACHE_NONE)
@@ -254,11 +261,11 @@ static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
-                                     enum i915_cache_level level,
-                                     bool valid, u32 unused)
+static gen6_pte_t iris_pte_encode(dma_addr_t addr,
+                                 enum i915_cache_level level,
+                                 bool valid, u32 unused)
 {
-       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
+       gen6_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -275,6 +282,162 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
        return pte;
 }
 
+#define i915_dma_unmap_single(px, dev) \
+       __i915_dma_unmap_single((px)->daddr, dev)
+
+static inline void __i915_dma_unmap_single(dma_addr_t daddr,
+                                       struct drm_device *dev)
+{
+       struct device *device = &dev->pdev->dev;
+
+       dma_unmap_page(device, daddr, 4096, PCI_DMA_BIDIRECTIONAL);
+}
+
+/**
+ * i915_dma_map_single() - Create a dma mapping for a page table/dir/etc.
+ * @px:        Page table/dir/etc to get a DMA map for
+ * @dev:       drm device
+ *
+ * Page table allocations are unified across all gens. They always require a
+ * single 4k allocation, as well as a DMA mapping. If we keep the structs
+ * symmetric here, the simple macro covers us for every page table type.
+ *
+ * Return: 0 if success.
+ */
+#define i915_dma_map_single(px, dev) \
+       i915_dma_map_page_single((px)->page, (dev), &(px)->daddr)
+
+static inline int i915_dma_map_page_single(struct page *page,
+                                          struct drm_device *dev,
+                                          dma_addr_t *daddr)
+{
+       struct device *device = &dev->pdev->dev;
+
+       *daddr = dma_map_page(device, page, 0, 4096, PCI_DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(device, *daddr))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void unmap_and_free_pt(struct i915_page_table_entry *pt,
+                              struct drm_device *dev)
+{
+       if (WARN_ON(!pt->page))
+               return;
+
+       i915_dma_unmap_single(pt, dev);
+       __free_page(pt->page);
+       kfree(pt->used_ptes);
+       kfree(pt);
+}
+
+static struct i915_page_table_entry *alloc_pt_single(struct drm_device *dev)
+{
+       struct i915_page_table_entry *pt;
+       const size_t count = INTEL_INFO(dev)->gen >= 8 ?
+               GEN8_PTES : GEN6_PTES;
+       int ret = -ENOMEM;
+
+       pt = kzalloc(sizeof(*pt), GFP_KERNEL);
+       if (!pt)
+               return ERR_PTR(-ENOMEM);
+
+       pt->used_ptes = kcalloc(BITS_TO_LONGS(count), sizeof(*pt->used_ptes),
+                               GFP_KERNEL);
+
+       if (!pt->used_ptes)
+               goto fail_bitmap;
+
+       pt->page = alloc_page(GFP_KERNEL);
+       if (!pt->page)
+               goto fail_page;
+
+       ret = i915_dma_map_single(pt, dev);
+       if (ret)
+               goto fail_dma;
+
+       return pt;
+
+fail_dma:
+       __free_page(pt->page);
+fail_page:
+       kfree(pt->used_ptes);
+fail_bitmap:
+       kfree(pt);
+
+       return ERR_PTR(ret);
+}
+
+/**
+ * alloc_pt_range() - Allocate a multiple page tables
+ * @pd:                The page directory which will have at least @count entries
+ *             available to point to the allocated page tables.
+ * @pde:       First page directory entry for which we are allocating.
+ * @count:     Number of pages to allocate.
+ * @dev:       DRM device.
+ *
+ * Allocates multiple page table pages and sets the appropriate entries in the
+ * page table structure within the page directory. Function cleans up after
+ * itself on any failures.
+ *
+ * Return: 0 if allocation succeeded.
+ */
+static int alloc_pt_range(struct i915_page_directory_entry *pd, uint16_t pde, size_t count,
+                         struct drm_device *dev)
+{
+       int i, ret;
+
+       /* 512 is the max page tables per page_directory on any platform. */
+       if (WARN_ON(pde + count > I915_PDES))
+               return -EINVAL;
+
+       for (i = pde; i < pde + count; i++) {
+               struct i915_page_table_entry *pt = alloc_pt_single(dev);
+
+               if (IS_ERR(pt)) {
+                       ret = PTR_ERR(pt);
+                       goto err_out;
+               }
+               WARN(pd->page_table[i],
+                    "Leaking page directory entry %d (%p)\n",
+                    i, pd->page_table[i]);
+               pd->page_table[i] = pt;
+       }
+
+       return 0;
+
+err_out:
+       while (i-- > pde)
+               unmap_and_free_pt(pd->page_table[i], dev);
+       return ret;
+}
+
+static void unmap_and_free_pd(struct i915_page_directory_entry *pd)
+{
+       if (pd->page) {
+               __free_page(pd->page);
+               kfree(pd);
+       }
+}
+
+static struct i915_page_directory_entry *alloc_pd_single(void)
+{
+       struct i915_page_directory_entry *pd;
+
+       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+       if (!pd)
+               return ERR_PTR(-ENOMEM);
+
+       pd->page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+       if (!pd->page) {
+               kfree(pd);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return pd;
+}
+
 /* Broadwell Page Directory Pointer Descriptors */
 static int gen8_write_pdp(struct intel_engine_cs *ring, unsigned entry,
                           uint64_t val)
@@ -304,10 +467,10 @@ static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
        int i, ret;
 
        /* bit of a hack to find the actual last used pd */
-       int used_pd = ppgtt->num_pd_entries / GEN8_PDES_PER_PAGE;
+       int used_pd = ppgtt->num_pd_entries / I915_PDES;
 
        for (i = used_pd - 1; i >= 0; i--) {
-               dma_addr_t addr = ppgtt->pd_dma_addr[i];
+               dma_addr_t addr = ppgtt->pdp.page_directory[i]->daddr;
                ret = gen8_write_pdp(ring, i, addr);
                if (ret)
                        return ret;
@@ -323,7 +486,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
-       gen8_gtt_pte_t *pt_vaddr, scratch_pte;
+       gen8_pte_t *pt_vaddr, scratch_pte;
        unsigned pdpe = start >> GEN8_PDPE_SHIFT & GEN8_PDPE_MASK;
        unsigned pde = start >> GEN8_PDE_SHIFT & GEN8_PDE_MASK;
        unsigned pte = start >> GEN8_PTE_SHIFT & GEN8_PTE_MASK;
@@ -334,11 +497,28 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
                                      I915_CACHE_LLC, use_scratch);
 
        while (num_entries) {
-               struct page *page_table = ppgtt->gen8_pt_pages[pdpe][pde];
+               struct i915_page_directory_entry *pd;
+               struct i915_page_table_entry *pt;
+               struct page *page_table;
+
+               if (WARN_ON(!ppgtt->pdp.page_directory[pdpe]))
+                       continue;
+
+               pd = ppgtt->pdp.page_directory[pdpe];
+
+               if (WARN_ON(!pd->page_table[pde]))
+                       continue;
+
+               pt = pd->page_table[pde];
+
+               if (WARN_ON(!pt->page))
+                       continue;
+
+               page_table = pt->page;
 
                last_pte = pte + num_entries;
-               if (last_pte > GEN8_PTES_PER_PAGE)
-                       last_pte = GEN8_PTES_PER_PAGE;
+               if (last_pte > GEN8_PTES)
+                       last_pte = GEN8_PTES;
 
                pt_vaddr = kmap_atomic(page_table);
 
@@ -352,7 +532,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
                kunmap_atomic(pt_vaddr);
 
                pte = 0;
-               if (++pde == GEN8_PDES_PER_PAGE) {
+               if (++pde == I915_PDES) {
                        pdpe++;
                        pde = 0;
                }
@@ -366,7 +546,7 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
-       gen8_gtt_pte_t *pt_vaddr;
+       gen8_pte_t *pt_vaddr;
        unsigned pdpe = start >> GEN8_PDPE_SHIFT & GEN8_PDPE_MASK;
        unsigned pde = start >> GEN8_PDE_SHIFT & GEN8_PDE_MASK;
        unsigned pte = start >> GEN8_PTE_SHIFT & GEN8_PTE_MASK;
@@ -375,21 +555,26 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
        pt_vaddr = NULL;
 
        for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
-               if (WARN_ON(pdpe >= GEN8_LEGACY_PDPS))
+               if (WARN_ON(pdpe >= GEN8_LEGACY_PDPES))
                        break;
 
-               if (pt_vaddr == NULL)
-                       pt_vaddr = kmap_atomic(ppgtt->gen8_pt_pages[pdpe][pde]);
+               if (pt_vaddr == NULL) {
+                       struct i915_page_directory_entry *pd = ppgtt->pdp.page_directory[pdpe];
+                       struct i915_page_table_entry *pt = pd->page_table[pde];
+                       struct page *page_table = pt->page;
+
+                       pt_vaddr = kmap_atomic(page_table);
+               }
 
                pt_vaddr[pte] =
                        gen8_pte_encode(sg_page_iter_dma_address(&sg_iter),
                                        cache_level, true);
-               if (++pte == GEN8_PTES_PER_PAGE) {
+               if (++pte == GEN8_PTES) {
                        if (!HAS_LLC(ppgtt->base.dev))
                                drm_clflush_virt_range(pt_vaddr, PAGE_SIZE);
                        kunmap_atomic(pt_vaddr);
                        pt_vaddr = NULL;
-                       if (++pde == GEN8_PDES_PER_PAGE) {
+                       if (++pde == I915_PDES) {
                                pdpe++;
                                pde = 0;
                        }
@@ -403,29 +588,33 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
        }
 }
 
-static void gen8_free_page_tables(struct page **pt_pages)
+static void gen8_free_page_tables(struct i915_page_directory_entry *pd, struct drm_device *dev)
 {
        int i;
 
-       if (pt_pages == NULL)
+       if (!pd->page)
                return;
 
-       for (i = 0; i < GEN8_PDES_PER_PAGE; i++)
-               if (pt_pages[i])
-                       __free_pages(pt_pages[i], 0);
+       for (i = 0; i < I915_PDES; i++) {
+               if (WARN_ON(!pd->page_table[i]))
+                       continue;
+
+               unmap_and_free_pt(pd->page_table[i], dev);
+               pd->page_table[i] = NULL;
+       }
 }
 
-static void gen8_ppgtt_free(const struct i915_hw_ppgtt *ppgtt)
+static void gen8_ppgtt_free(struct i915_hw_ppgtt *ppgtt)
 {
        int i;
 
        for (i = 0; i < ppgtt->num_pd_pages; i++) {
-               gen8_free_page_tables(ppgtt->gen8_pt_pages[i]);
-               kfree(ppgtt->gen8_pt_pages[i]);
-               kfree(ppgtt->gen8_pt_dma_addr[i]);
-       }
+               if (WARN_ON(!ppgtt->pdp.page_directory[i]))
+                       continue;
 
-       __free_pages(ppgtt->pd_pages, get_order(ppgtt->num_pd_pages << PAGE_SHIFT));
+               gen8_free_page_tables(ppgtt->pdp.page_directory[i], ppgtt->base.dev);
+               unmap_and_free_pd(ppgtt->pdp.page_directory[i]);
+       }
 }
 
 static void gen8_ppgtt_unmap_pages(struct i915_hw_ppgtt *ppgtt)
@@ -436,14 +625,23 @@ static void gen8_ppgtt_unmap_pages(struct i915_hw_ppgtt *ppgtt)
        for (i = 0; i < ppgtt->num_pd_pages; i++) {
                /* TODO: In the future we'll support sparse mappings, so this
                 * will have to change. */
-               if (!ppgtt->pd_dma_addr[i])
+               if (!ppgtt->pdp.page_directory[i]->daddr)
                        continue;
 
-               pci_unmap_page(hwdev, ppgtt->pd_dma_addr[i], PAGE_SIZE,
+               pci_unmap_page(hwdev, ppgtt->pdp.page_directory[i]->daddr, PAGE_SIZE,
                               PCI_DMA_BIDIRECTIONAL);
 
-               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
-                       dma_addr_t addr = ppgtt->gen8_pt_dma_addr[i][j];
+               for (j = 0; j < I915_PDES; j++) {
+                       struct i915_page_directory_entry *pd = ppgtt->pdp.page_directory[i];
+                       struct i915_page_table_entry *pt;
+                       dma_addr_t addr;
+
+                       if (WARN_ON(!pd->page_table[j]))
+                               continue;
+
+                       pt = pd->page_table[j];
+                       addr = pt->daddr;
+
                        if (addr)
                                pci_unmap_page(hwdev, addr, PAGE_SIZE,
                                               PCI_DMA_BIDIRECTIONAL);
@@ -460,86 +658,47 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
        gen8_ppgtt_free(ppgtt);
 }
 
-static struct page **__gen8_alloc_page_tables(void)
+static int gen8_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt)
 {
-       struct page **pt_pages;
-       int i;
-
-       pt_pages = kcalloc(GEN8_PDES_PER_PAGE, sizeof(struct page *), GFP_KERNEL);
-       if (!pt_pages)
-               return ERR_PTR(-ENOMEM);
-
-       for (i = 0; i < GEN8_PDES_PER_PAGE; i++) {
-               pt_pages[i] = alloc_page(GFP_KERNEL);
-               if (!pt_pages[i])
-                       goto bail;
-       }
-
-       return pt_pages;
-
-bail:
-       gen8_free_page_tables(pt_pages);
-       kfree(pt_pages);
-       return ERR_PTR(-ENOMEM);
-}
-
-static int gen8_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt,
-                                          const int max_pdp)
-{
-       struct page **pt_pages[GEN8_LEGACY_PDPS];
        int i, ret;
 
-       for (i = 0; i < max_pdp; i++) {
-               pt_pages[i] = __gen8_alloc_page_tables();
-               if (IS_ERR(pt_pages[i])) {
-                       ret = PTR_ERR(pt_pages[i]);
+       for (i = 0; i < ppgtt->num_pd_pages; i++) {
+               ret = alloc_pt_range(ppgtt->pdp.page_directory[i],
+                                    0, I915_PDES, ppgtt->base.dev);
+               if (ret)
                        goto unwind_out;
-               }
        }
 
-       /* NB: Avoid touching gen8_pt_pages until last to keep the allocation,
-        * "atomic" - for cleanup purposes.
-        */
-       for (i = 0; i < max_pdp; i++)
-               ppgtt->gen8_pt_pages[i] = pt_pages[i];
-
        return 0;
 
 unwind_out:
-       while (i--) {
-               gen8_free_page_tables(pt_pages[i]);
-               kfree(pt_pages[i]);
-       }
+       while (i--)
+               gen8_free_page_tables(ppgtt->pdp.page_directory[i], ppgtt->base.dev);
 
-       return ret;
+       return -ENOMEM;
 }
 
-static int gen8_ppgtt_allocate_dma(struct i915_hw_ppgtt *ppgtt)
+static int gen8_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt,
+                                               const int max_pdp)
 {
        int i;
 
-       for (i = 0; i < ppgtt->num_pd_pages; i++) {
-               ppgtt->gen8_pt_dma_addr[i] = kcalloc(GEN8_PDES_PER_PAGE,
-                                                    sizeof(dma_addr_t),
-                                                    GFP_KERNEL);
-               if (!ppgtt->gen8_pt_dma_addr[i])
-                       return -ENOMEM;
+       for (i = 0; i < max_pdp; i++) {
+               ppgtt->pdp.page_directory[i] = alloc_pd_single();
+               if (IS_ERR(ppgtt->pdp.page_directory[i]))
+                       goto unwind_out;
        }
 
-       return 0;
-}
+       ppgtt->num_pd_pages = max_pdp;
+       BUG_ON(ppgtt->num_pd_pages > GEN8_LEGACY_PDPES);
 
-static int gen8_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt,
-                                               const int max_pdp)
-{
-       ppgtt->pd_pages = alloc_pages(GFP_KERNEL, get_order(max_pdp << PAGE_SHIFT));
-       if (!ppgtt->pd_pages)
-               return -ENOMEM;
+       return 0;
 
-       ppgtt->num_pd_pages = 1 << get_order(max_pdp << PAGE_SHIFT);
-       BUG_ON(ppgtt->num_pd_pages > GEN8_LEGACY_PDPS);
+unwind_out:
+       while (i--)
+               unmap_and_free_pd(ppgtt->pdp.page_directory[i]);
 
-       return 0;
+       return -ENOMEM;
 }
 
 static int gen8_ppgtt_alloc(struct i915_hw_ppgtt *ppgtt,
@@ -551,18 +710,16 @@ static int gen8_ppgtt_alloc(struct i915_hw_ppgtt *ppgtt,
        if (ret)
                return ret;
 
-       ret = gen8_ppgtt_allocate_page_tables(ppgtt, max_pdp);
-       if (ret) {
-               __free_pages(ppgtt->pd_pages, get_order(max_pdp << PAGE_SHIFT));
-               return ret;
-       }
+       ret = gen8_ppgtt_allocate_page_tables(ppgtt);
+       if (ret)
+               goto err_out;
 
-       ppgtt->num_pd_entries = max_pdp * GEN8_PDES_PER_PAGE;
+       ppgtt->num_pd_entries = max_pdp * I915_PDES;
 
-       ret = gen8_ppgtt_allocate_dma(ppgtt);
-       if (ret)
-               gen8_ppgtt_free(ppgtt);
+       return 0;
 
+err_out:
+       gen8_ppgtt_free(ppgtt);
        return ret;
 }
 
@@ -573,14 +730,14 @@ static int gen8_ppgtt_setup_page_directories(struct i915_hw_ppgtt *ppgtt,
        int ret;
 
        pd_addr = pci_map_page(ppgtt->base.dev->pdev,
-                              &ppgtt->pd_pages[pd], 0,
+                              ppgtt->pdp.page_directory[pd]->page, 0,
                               PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
 
        ret = pci_dma_mapping_error(ppgtt->base.dev->pdev, pd_addr);
        if (ret)
                return ret;
 
-       ppgtt->pd_dma_addr[pd] = pd_addr;
+       ppgtt->pdp.page_directory[pd]->daddr = pd_addr;
 
        return 0;
 }
@@ -590,22 +747,23 @@ static int gen8_ppgtt_setup_page_tables(struct i915_hw_ppgtt *ppgtt,
                                        const int pt)
 {
        dma_addr_t pt_addr;
-       struct page *p;
+       struct i915_page_directory_entry *pdir = ppgtt->pdp.page_directory[pd];
+       struct i915_page_table_entry *ptab = pdir->page_table[pt];
+       struct page *p = ptab->page;
        int ret;
 
-       p = ppgtt->gen8_pt_pages[pd][pt];
        pt_addr = pci_map_page(ppgtt->base.dev->pdev,
                               p, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
        ret = pci_dma_mapping_error(ppgtt->base.dev->pdev, pt_addr);
        if (ret)
                return ret;
 
-       ppgtt->gen8_pt_dma_addr[pd][pt] = pt_addr;
+       ptab->daddr = pt_addr;
 
        return 0;
 }
 
-/**
+/*
  * GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers
  * with a net effect resembling a 2-level page table in normal x86 terms. Each
  * PDP represents 1GB of memory 4 * 512 * 512 * 4096 = 4GB legacy 32b address
@@ -618,26 +776,30 @@ static int gen8_ppgtt_setup_page_tables(struct i915_hw_ppgtt *ppgtt,
 static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
 {
        const int max_pdp = DIV_ROUND_UP(size, 1 << 30);
-       const int min_pt_pages = GEN8_PDES_PER_PAGE * max_pdp;
+       const int min_pt_pages = I915_PDES * max_pdp;
        int i, j, ret;
 
        if (size % (1<<30))
                DRM_INFO("Pages will be wasted unless GTT size (%llu) is divisible by 1GB\n", size);
 
-       /* 1. Do all our allocations for page directories and page tables. */
-       ret = gen8_ppgtt_alloc(ppgtt, max_pdp);
+       /* 1. Do all our allocations for page directories and page tables.
+        * We allocate more than was asked so that we can point the unused parts
+        * to valid entries that point to scratch page. Dynamic page tables
+        * will fix this eventually.
+        */
+       ret = gen8_ppgtt_alloc(ppgtt, GEN8_LEGACY_PDPES);
        if (ret)
                return ret;
 
        /*
         * 2. Create DMA mappings for the page directories and page tables.
         */
-       for (i = 0; i < max_pdp; i++) {
+       for (i = 0; i < GEN8_LEGACY_PDPES; i++) {
                ret = gen8_ppgtt_setup_page_directories(ppgtt, i);
                if (ret)
                        goto bail;
 
-               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
+               for (j = 0; j < I915_PDES; j++) {
                        ret = gen8_ppgtt_setup_page_tables(ppgtt, i, j);
                        if (ret)
                                goto bail;
@@ -652,11 +814,13 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
         * plugged in correctly. So we do that now/here. For aliasing PPGTT, we
         * will never need to touch the PDEs again.
         */
-       for (i = 0; i < max_pdp; i++) {
-               gen8_ppgtt_pde_t *pd_vaddr;
-               pd_vaddr = kmap_atomic(&ppgtt->pd_pages[i]);
-               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
-                       dma_addr_t addr = ppgtt->gen8_pt_dma_addr[i][j];
+       for (i = 0; i < GEN8_LEGACY_PDPES; i++) {
+               struct i915_page_directory_entry *pd = ppgtt->pdp.page_directory[i];
+               gen8_pde_t *pd_vaddr;
+               pd_vaddr = kmap_atomic(ppgtt->pdp.page_directory[i]->page);
+               for (j = 0; j < I915_PDES; j++) {
+                       struct i915_page_table_entry *pt = pd->page_table[j];
+                       dma_addr_t addr = pt->daddr;
                        pd_vaddr[j] = gen8_pde_encode(ppgtt->base.dev, addr,
                                                      I915_CACHE_LLC);
                }
@@ -670,9 +834,14 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
        ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
        ppgtt->base.cleanup = gen8_ppgtt_cleanup;
        ppgtt->base.start = 0;
-       ppgtt->base.total = ppgtt->num_pd_entries * GEN8_PTES_PER_PAGE * PAGE_SIZE;
 
-       ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true);
+       /* This is the area that we advertise as usable for the caller */
+       ppgtt->base.total = max_pdp * I915_PDES * GEN8_PTES * PAGE_SIZE;
+
+       /* Set all ptes to a valid scratch page. Also above requested space */
+       ppgtt->base.clear_range(&ppgtt->base, 0,
+                               ppgtt->num_pd_pages * GEN8_PTES * PAGE_SIZE,
+                               true);
 
        DRM_DEBUG_DRIVER("Allocated %d pages for page directories (%d wasted)\n",
                         ppgtt->num_pd_pages, ppgtt->num_pd_pages - max_pdp);
@@ -691,22 +860,23 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
 {
        struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
        struct i915_address_space *vm = &ppgtt->base;
-       gen6_gtt_pte_t __iomem *pd_addr;
-       gen6_gtt_pte_t scratch_pte;
+       gen6_pte_t __iomem *pd_addr;
+       gen6_pte_t scratch_pte;
        uint32_t pd_entry;
        int pte, pde;
 
        scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0);
 
-       pd_addr = (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm +
-               ppgtt->pd_offset / sizeof(gen6_gtt_pte_t);
+       pd_addr = (gen6_pte_t __iomem *)dev_priv->gtt.gsm +
+               ppgtt->pd.pd_offset / sizeof(gen6_pte_t);
 
        seq_printf(m, "  VM %p (pd_offset %x-%x):\n", vm,
-                  ppgtt->pd_offset, ppgtt->pd_offset + ppgtt->num_pd_entries);
+                  ppgtt->pd.pd_offset,
+                  ppgtt->pd.pd_offset + ppgtt->num_pd_entries);
        for (pde = 0; pde < ppgtt->num_pd_entries; pde++) {
                u32 expected;
-               gen6_gtt_pte_t *pt_vaddr;
-               dma_addr_t pt_addr = ppgtt->pt_dma_addr[pde];
+               gen6_pte_t *pt_vaddr;
+               dma_addr_t pt_addr = ppgtt->pd.page_table[pde]->daddr;
                pd_entry = readl(pd_addr + pde);
                expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID);
 
@@ -717,10 +887,10 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
                                   expected);
                seq_printf(m, "\tPDE: %x\n", pd_entry);
 
-               pt_vaddr = kmap_atomic(ppgtt->pt_pages[pde]);
-               for (pte = 0; pte < I915_PPGTT_PT_ENTRIES; pte+=4) {
+               pt_vaddr = kmap_atomic(ppgtt->pd.page_table[pde]->page);
+               for (pte = 0; pte < GEN6_PTES; pte+=4) {
                        unsigned long va =
-                               (pde * PAGE_SIZE * I915_PPGTT_PT_ENTRIES) +
+                               (pde * PAGE_SIZE * GEN6_PTES) +
                                (pte * PAGE_SIZE);
                        int i;
                        bool found = false;
@@ -743,33 +913,43 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
        }
 }
 
-static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
+/* Write pde (index) from the page directory @pd to the page table @pt */
+static void gen6_write_pde(struct i915_page_directory_entry *pd,
+                           const int pde, struct i915_page_table_entry *pt)
 {
-       struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
-       gen6_gtt_pte_t __iomem *pd_addr;
-       uint32_t pd_entry;
-       int i;
+       /* Caller needs to make sure the write completes if necessary */
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(pd, struct i915_hw_ppgtt, pd);
+       u32 pd_entry;
 
-       WARN_ON(ppgtt->pd_offset & 0x3f);
-       pd_addr = (gen6_gtt_pte_t __iomem*)dev_priv->gtt.gsm +
-               ppgtt->pd_offset / sizeof(gen6_gtt_pte_t);
-       for (i = 0; i < ppgtt->num_pd_entries; i++) {
-               dma_addr_t pt_addr;
+       pd_entry = GEN6_PDE_ADDR_ENCODE(pt->daddr);
+       pd_entry |= GEN6_PDE_VALID;
 
-               pt_addr = ppgtt->pt_dma_addr[i];
-               pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
-               pd_entry |= GEN6_PDE_VALID;
+       writel(pd_entry, ppgtt->pd_addr + pde);
+}
 
-               writel(pd_entry, pd_addr + i);
-       }
-       readl(pd_addr);
+/* Write all the page tables found in the ppgtt structure to incrementing page
+ * directories. */
+static void gen6_write_page_range(struct drm_i915_private *dev_priv,
+                                 struct i915_page_directory_entry *pd,
+                                 uint32_t start, uint32_t length)
+{
+       struct i915_page_table_entry *pt;
+       uint32_t pde, temp;
+
+       gen6_for_each_pde(pt, pd, start, length, temp, pde)
+               gen6_write_pde(pd, pde, pt);
+
+       /* Make sure write is complete before other code can use this page
+        * table. Also require for WC mapped PTEs */
+       readl(dev_priv->gtt.gsm);
 }
 
 static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt)
 {
-       BUG_ON(ppgtt->pd_offset & 0x3f);
+       BUG_ON(ppgtt->pd.pd_offset & 0x3f);
 
-       return (ppgtt->pd_offset / 64) << 16;
+       return (ppgtt->pd.pd_offset / 64) << 16;
 }
 
 static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
@@ -797,6 +977,16 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
        return 0;
 }
 
+static int vgpu_mm_switch(struct i915_hw_ppgtt *ppgtt,
+                         struct intel_engine_cs *ring)
+{
+       struct drm_i915_private *dev_priv = to_i915(ppgtt->base.dev);
+
+       I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
+       I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
+       return 0;
+}
+
 static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
                          struct intel_engine_cs *ring)
 {
@@ -908,21 +1098,21 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
-       gen6_gtt_pte_t *pt_vaddr, scratch_pte;
+       gen6_pte_t *pt_vaddr, scratch_pte;
        unsigned first_entry = start >> PAGE_SHIFT;
        unsigned num_entries = length >> PAGE_SHIFT;
-       unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
-       unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+       unsigned act_pt = first_entry / GEN6_PTES;
+       unsigned first_pte = first_entry % GEN6_PTES;
        unsigned last_pte, i;
 
        scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0);
 
        while (num_entries) {
                last_pte = first_pte + num_entries;
-               if (last_pte > I915_PPGTT_PT_ENTRIES)
-                       last_pte = I915_PPGTT_PT_ENTRIES;
+               if (last_pte > GEN6_PTES)
+                       last_pte = GEN6_PTES;
 
-               pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
+               pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->page);
 
                for (i = first_pte; i < last_pte; i++)
                        pt_vaddr[i] = scratch_pte;
@@ -942,22 +1132,22 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
-       gen6_gtt_pte_t *pt_vaddr;
+       gen6_pte_t *pt_vaddr;
        unsigned first_entry = start >> PAGE_SHIFT;
-       unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
-       unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+       unsigned act_pt = first_entry / GEN6_PTES;
+       unsigned act_pte = first_entry % GEN6_PTES;
        struct sg_page_iter sg_iter;
 
        pt_vaddr = NULL;
        for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
                if (pt_vaddr == NULL)
-                       pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
+                       pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->page);
 
                pt_vaddr[act_pte] =
                        vm->pte_encode(sg_page_iter_dma_address(&sg_iter),
                                       cache_level, true, flags);
 
-               if (++act_pte == I915_PPGTT_PT_ENTRIES) {
+               if (++act_pte == GEN6_PTES) {
                        kunmap_atomic(pt_vaddr);
                        pt_vaddr = NULL;
                        act_pt++;
@@ -968,26 +1158,134 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                kunmap_atomic(pt_vaddr);
 }
 
-static void gen6_ppgtt_unmap_pages(struct i915_hw_ppgtt *ppgtt)
+/* PDE TLBs are a pain invalidate pre GEN8. It requires a context reload. If we
+ * are switching between contexts with the same LRCA, we also must do a force
+ * restore.
+ */
+static inline void mark_tlbs_dirty(struct i915_hw_ppgtt *ppgtt)
+{
+       /* If current vm != vm, */
+       ppgtt->pd_dirty_rings = INTEL_INFO(ppgtt->base.dev)->ring_mask;
+}
+
+static void gen6_initialize_pt(struct i915_address_space *vm,
+               struct i915_page_table_entry *pt)
 {
+       gen6_pte_t *pt_vaddr, scratch_pte;
        int i;
 
-       if (ppgtt->pt_dma_addr) {
-               for (i = 0; i < ppgtt->num_pd_entries; i++)
-                       pci_unmap_page(ppgtt->base.dev->pdev,
-                                      ppgtt->pt_dma_addr[i],
-                                      4096, PCI_DMA_BIDIRECTIONAL);
+       WARN_ON(vm->scratch.addr == 0);
+
+       scratch_pte = vm->pte_encode(vm->scratch.addr,
+                       I915_CACHE_LLC, true, 0);
+
+       pt_vaddr = kmap_atomic(pt->page);
+
+       for (i = 0; i < GEN6_PTES; i++)
+               pt_vaddr[i] = scratch_pte;
+
+       kunmap_atomic(pt_vaddr);
+}
+
+static int gen6_alloc_va_range(struct i915_address_space *vm,
+                              uint64_t start, uint64_t length)
+{
+       DECLARE_BITMAP(new_page_tables, I915_PDES);
+       struct drm_device *dev = vm->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_hw_ppgtt *ppgtt =
+                               container_of(vm, struct i915_hw_ppgtt, base);
+       struct i915_page_table_entry *pt;
+       const uint32_t start_save = start, length_save = length;
+       uint32_t pde, temp;
+       int ret;
+
+       WARN_ON(upper_32_bits(start));
+
+       bitmap_zero(new_page_tables, I915_PDES);
+
+       /* The allocation is done in two stages so that we can bail out with
+        * minimal amount of pain. The first stage finds new page tables that
+        * need allocation. The second stage marks use ptes within the page
+        * tables.
+        */
+       gen6_for_each_pde(pt, &ppgtt->pd, start, length, temp, pde) {
+               if (pt != ppgtt->scratch_pt) {
+                       WARN_ON(bitmap_empty(pt->used_ptes, GEN6_PTES));
+                       continue;
+               }
+
+               /* We've already allocated a page table */
+               WARN_ON(!bitmap_empty(pt->used_ptes, GEN6_PTES));
+
+               pt = alloc_pt_single(dev);
+               if (IS_ERR(pt)) {
+                       ret = PTR_ERR(pt);
+                       goto unwind_out;
+               }
+
+               gen6_initialize_pt(vm, pt);
+
+               ppgtt->pd.page_table[pde] = pt;
+               set_bit(pde, new_page_tables);
+               trace_i915_page_table_entry_alloc(vm, pde, start, GEN6_PDE_SHIFT);
        }
+
+       start = start_save;
+       length = length_save;
+
+       gen6_for_each_pde(pt, &ppgtt->pd, start, length, temp, pde) {
+               DECLARE_BITMAP(tmp_bitmap, GEN6_PTES);
+
+               bitmap_zero(tmp_bitmap, GEN6_PTES);
+               bitmap_set(tmp_bitmap, gen6_pte_index(start),
+                          gen6_pte_count(start, length));
+
+               if (test_and_clear_bit(pde, new_page_tables))
+                       gen6_write_pde(&ppgtt->pd, pde, pt);
+
+               trace_i915_page_table_entry_map(vm, pde, pt,
+                                        gen6_pte_index(start),
+                                        gen6_pte_count(start, length),
+                                        GEN6_PTES);
+               bitmap_or(pt->used_ptes, tmp_bitmap, pt->used_ptes,
+                               GEN6_PTES);
+       }
+
+       WARN_ON(!bitmap_empty(new_page_tables, I915_PDES));
+
+       /* Make sure write is complete before other code can use this page
+        * table. Also require for WC mapped PTEs */
+       readl(dev_priv->gtt.gsm);
+
+       mark_tlbs_dirty(ppgtt);
+       return 0;
+
+unwind_out:
+       for_each_set_bit(pde, new_page_tables, I915_PDES) {
+               struct i915_page_table_entry *pt = ppgtt->pd.page_table[pde];
+
+               ppgtt->pd.page_table[pde] = ppgtt->scratch_pt;
+               unmap_and_free_pt(pt, vm->dev);
+       }
+
+       mark_tlbs_dirty(ppgtt);
+       return ret;
 }
 
 static void gen6_ppgtt_free(struct i915_hw_ppgtt *ppgtt)
 {
        int i;
 
-       kfree(ppgtt->pt_dma_addr);
-       for (i = 0; i < ppgtt->num_pd_entries; i++)
-               __free_page(ppgtt->pt_pages[i]);
-       kfree(ppgtt->pt_pages);
+       for (i = 0; i < ppgtt->num_pd_entries; i++) {
+               struct i915_page_table_entry *pt = ppgtt->pd.page_table[i];
+
+               if (pt != ppgtt->scratch_pt)
+                       unmap_and_free_pt(ppgtt->pd.page_table[i], ppgtt->base.dev);
+       }
+
+       unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev);
+       unmap_and_free_pd(&ppgtt->pd);
 }
 
 static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
@@ -997,7 +1295,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
 
        drm_mm_remove_node(&ppgtt->node);
 
-       gen6_ppgtt_unmap_pages(ppgtt);
        gen6_ppgtt_free(ppgtt);
 }
 
@@ -1013,6 +1310,12 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt)
         * size. We allocate at the top of the GTT to avoid fragmentation.
         */
        BUG_ON(!drm_mm_initialized(&dev_priv->gtt.base.mm));
+       ppgtt->scratch_pt = alloc_pt_single(ppgtt->base.dev);
+       if (IS_ERR(ppgtt->scratch_pt))
+               return PTR_ERR(ppgtt->scratch_pt);
+
+       gen6_initialize_pt(&ppgtt->base, ppgtt->scratch_pt);
+
 alloc:
        ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm,
                                                  &ppgtt->node, GEN6_PD_SIZE,
@@ -1026,88 +1329,43 @@ alloc:
                                               0, dev_priv->gtt.base.total,
                                               0);
                if (ret)
-                       return ret;
+                       goto err_out;
 
                retried = true;
                goto alloc;
        }
 
-       if (ppgtt->node.start < dev_priv->gtt.mappable_end)
-               DRM_DEBUG("Forced to use aperture for PDEs\n");
-
-       ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES;
-       return ret;
-}
-
-static int gen6_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt)
-{
-       int i;
-
-       ppgtt->pt_pages = kcalloc(ppgtt->num_pd_entries, sizeof(struct page *),
-                                 GFP_KERNEL);
+       if (ret)
+               goto err_out;
 
-       if (!ppgtt->pt_pages)
-               return -ENOMEM;
 
-       for (i = 0; i < ppgtt->num_pd_entries; i++) {
-               ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL);
-               if (!ppgtt->pt_pages[i]) {
-                       gen6_ppgtt_free(ppgtt);
-                       return -ENOMEM;
-               }
-       }
+       if (ppgtt->node.start < dev_priv->gtt.mappable_end)
+               DRM_DEBUG("Forced to use aperture for PDEs\n");
 
+       ppgtt->num_pd_entries = I915_PDES;
        return 0;
+
+err_out:
+       unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev);
+       return ret;
 }
 
 static int gen6_ppgtt_alloc(struct i915_hw_ppgtt *ppgtt)
 {
-       int ret;
-
-       ret = gen6_ppgtt_allocate_page_directories(ppgtt);
-       if (ret)
-               return ret;
-
-       ret = gen6_ppgtt_allocate_page_tables(ppgtt);
-       if (ret) {
-               drm_mm_remove_node(&ppgtt->node);
-               return ret;
-       }
-
-       ppgtt->pt_dma_addr = kcalloc(ppgtt->num_pd_entries, sizeof(dma_addr_t),
-                                    GFP_KERNEL);
-       if (!ppgtt->pt_dma_addr) {
-               drm_mm_remove_node(&ppgtt->node);
-               gen6_ppgtt_free(ppgtt);
-               return -ENOMEM;
-       }
-
-       return 0;
+       return gen6_ppgtt_allocate_page_directories(ppgtt);
 }
 
-static int gen6_ppgtt_setup_page_tables(struct i915_hw_ppgtt *ppgtt)
+static void gen6_scratch_va_range(struct i915_hw_ppgtt *ppgtt,
+                                 uint64_t start, uint64_t length)
 {
-       struct drm_device *dev = ppgtt->base.dev;
-       int i;
-
-       for (i = 0; i < ppgtt->num_pd_entries; i++) {
-               dma_addr_t pt_addr;
-
-               pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i], 0, 4096,
-                                      PCI_DMA_BIDIRECTIONAL);
-
-               if (pci_dma_mapping_error(dev->pdev, pt_addr)) {
-                       gen6_ppgtt_unmap_pages(ppgtt);
-                       return -EIO;
-               }
-
-               ppgtt->pt_dma_addr[i] = pt_addr;
-       }
+       struct i915_page_table_entry *unused;
+       uint32_t pde, temp;
 
-       return 0;
+       gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde)
+               ppgtt->pd.page_table[pde] = ppgtt->scratch_pt;
 }
 
-static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
+static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt, bool aliasing)
 {
        struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1123,40 +1381,57 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
        } else
                BUG();
 
+       if (intel_vgpu_active(dev))
+               ppgtt->switch_mm = vgpu_mm_switch;
+
        ret = gen6_ppgtt_alloc(ppgtt);
        if (ret)
                return ret;
 
-       ret = gen6_ppgtt_setup_page_tables(ppgtt);
-       if (ret) {
-               gen6_ppgtt_free(ppgtt);
-               return ret;
+       if (aliasing) {
+               /* preallocate all pts */
+               ret = alloc_pt_range(&ppgtt->pd, 0, ppgtt->num_pd_entries,
+                               ppgtt->base.dev);
+
+               if (ret) {
+                       gen6_ppgtt_cleanup(&ppgtt->base);
+                       return ret;
+               }
        }
 
+       ppgtt->base.allocate_va_range = gen6_alloc_va_range;
        ppgtt->base.clear_range = gen6_ppgtt_clear_range;
        ppgtt->base.insert_entries = gen6_ppgtt_insert_entries;
        ppgtt->base.cleanup = gen6_ppgtt_cleanup;
        ppgtt->base.start = 0;
-       ppgtt->base.total =  ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES * PAGE_SIZE;
+       ppgtt->base.total = ppgtt->num_pd_entries * GEN6_PTES * PAGE_SIZE;
        ppgtt->debug_dump = gen6_dump_ppgtt;
 
-       ppgtt->pd_offset =
-               ppgtt->node.start / PAGE_SIZE * sizeof(gen6_gtt_pte_t);
+       ppgtt->pd.pd_offset =
+               ppgtt->node.start / PAGE_SIZE * sizeof(gen6_pte_t);
+
+       ppgtt->pd_addr = (gen6_pte_t __iomem *)dev_priv->gtt.gsm +
+               ppgtt->pd.pd_offset / sizeof(gen6_pte_t);
+
+       if (aliasing)
+               ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true);
+       else
+               gen6_scratch_va_range(ppgtt, 0, ppgtt->base.total);
 
-       ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true);
+       gen6_write_page_range(dev_priv, &ppgtt->pd, 0, ppgtt->base.total);
 
-       DRM_DEBUG_DRIVER("Allocated pde space (%ldM) at GTT entry: %lx\n",
+       DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n",
                         ppgtt->node.size >> 20,
                         ppgtt->node.start / PAGE_SIZE);
 
-       gen6_write_pdes(ppgtt);
        DRM_DEBUG("Adding PPGTT at offset %x\n",
-                 ppgtt->pd_offset << 10);
+                 ppgtt->pd.pd_offset << 10);
 
        return 0;
 }
 
-static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
+static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt,
+               bool aliasing)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -1164,7 +1439,7 @@ static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
        ppgtt->base.scratch = dev_priv->gtt.base.scratch;
 
        if (INTEL_INFO(dev)->gen < 8)
-               return gen6_ppgtt_init(ppgtt);
+               return gen6_ppgtt_init(ppgtt, aliasing);
        else
                return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
 }
@@ -1173,7 +1448,7 @@ int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret = 0;
 
-       ret = __hw_ppgtt_init(dev, ppgtt);
+       ret = __hw_ppgtt_init(dev, ppgtt, false);
        if (ret == 0) {
                kref_init(&ppgtt->ref);
                drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
@@ -1420,15 +1695,20 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
                return;
        }
 
-       list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
-               /* TODO: Perhaps it shouldn't be gen6 specific */
-               if (i915_is_ggtt(vm)) {
-                       if (dev_priv->mm.aliasing_ppgtt)
-                               gen6_write_pdes(dev_priv->mm.aliasing_ppgtt);
-                       continue;
-               }
+       if (USES_PPGTT(dev)) {
+               list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
+                       /* TODO: Perhaps it shouldn't be gen6 specific */
+
+                       struct i915_hw_ppgtt *ppgtt =
+                                       container_of(vm, struct i915_hw_ppgtt,
+                                                    base);
+
+                       if (i915_is_ggtt(vm))
+                               ppgtt = dev_priv->mm.aliasing_ppgtt;
 
-               gen6_write_pdes(container_of(vm, struct i915_hw_ppgtt, base));
+                       gen6_write_page_range(dev_priv, &ppgtt->pd,
+                                             0, ppgtt->base.total);
+               }
        }
 
        i915_ggtt_flush(dev_priv);
@@ -1447,7 +1727,7 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
        return 0;
 }
 
-static inline void gen8_set_pte(void __iomem *addr, gen8_gtt_pte_t pte)
+static inline void gen8_set_pte(void __iomem *addr, gen8_pte_t pte)
 {
 #ifdef writeq
        writeq(pte, addr);
@@ -1464,8 +1744,8 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
-       gen8_gtt_pte_t __iomem *gtt_entries =
-               (gen8_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
+       gen8_pte_t __iomem *gtt_entries =
+               (gen8_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
        struct sg_page_iter sg_iter;
        dma_addr_t addr = 0; /* shut up gcc */
@@ -1510,8 +1790,8 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
-       gen6_gtt_pte_t __iomem *gtt_entries =
-               (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
+       gen6_pte_t __iomem *gtt_entries =
+               (gen6_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
        struct sg_page_iter sg_iter;
        dma_addr_t addr = 0;
@@ -1549,8 +1829,8 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm,
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
        unsigned num_entries = length >> PAGE_SHIFT;
-       gen8_gtt_pte_t scratch_pte, __iomem *gtt_base =
-               (gen8_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
+       gen8_pte_t scratch_pte, __iomem *gtt_base =
+               (gen8_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
        const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
        int i;
 
@@ -1575,8 +1855,8 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
        unsigned num_entries = length >> PAGE_SHIFT;
-       gen6_gtt_pte_t scratch_pte, __iomem *gtt_base =
-               (gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
+       gen6_pte_t scratch_pte, __iomem *gtt_base =
+               (gen6_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
        const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
        int i;
 
@@ -1633,11 +1913,15 @@ static void ggtt_bind_vma(struct i915_vma *vma,
        struct drm_device *dev = vma->vm->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj = vma->obj;
+       struct sg_table *pages = obj->pages;
 
        /* Currently applicable only to VLV */
        if (obj->gt_ro)
                flags |= PTE_READ_ONLY;
 
+       if (i915_is_ggtt(vma->vm))
+               pages = vma->ggtt_view.pages;
+
        /* If there is no aliasing PPGTT, or the caller needs a global mapping,
         * or we have a global mapping already but the cacheability flags have
         * changed, set the global PTEs.
@@ -1652,7 +1936,7 @@ static void ggtt_bind_vma(struct i915_vma *vma,
        if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) {
                if (!(vma->bound & GLOBAL_BIND) ||
                    (cache_level != obj->cache_level)) {
-                       vma->vm->insert_entries(vma->vm, vma->ggtt_view.pages,
+                       vma->vm->insert_entries(vma->vm, pages,
                                                vma->node.start,
                                                cache_level, flags);
                        vma->bound |= GLOBAL_BIND;
@@ -1663,8 +1947,7 @@ static void ggtt_bind_vma(struct i915_vma *vma,
            (!(vma->bound & LOCAL_BIND) ||
             (cache_level != obj->cache_level))) {
                struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
-               appgtt->base.insert_entries(&appgtt->base,
-                                           vma->ggtt_view.pages,
+               appgtt->base.insert_entries(&appgtt->base, pages,
                                            vma->node.start,
                                            cache_level, flags);
                vma->bound |= LOCAL_BIND;
@@ -1713,8 +1996,8 @@ void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
 
 static void i915_gtt_color_adjust(struct drm_mm_node *node,
                                  unsigned long color,
-                                 unsigned long *start,
-                                 unsigned long *end)
+                                 u64 *start,
+                                 u64 *end)
 {
        if (node->color != color)
                *start += 4096;
@@ -1753,6 +2036,16 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
 
        /* Subtract the guard page ... */
        drm_mm_init(&ggtt_vm->mm, start, end - start - PAGE_SIZE);
+
+       dev_priv->gtt.base.start = start;
+       dev_priv->gtt.base.total = end - start;
+
+       if (intel_vgpu_active(dev)) {
+               ret = intel_vgt_balloon(dev);
+               if (ret)
+                       return ret;
+       }
+
        if (!HAS_LLC(dev))
                dev_priv->gtt.base.mm.color_adjust = i915_gtt_color_adjust;
 
@@ -1772,9 +2065,6 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
                vma->bound |= GLOBAL_BIND;
        }
 
-       dev_priv->gtt.base.start = start;
-       dev_priv->gtt.base.total = end - start;
-
        /* Clear any non-preallocated blocks */
        drm_mm_for_each_hole(entry, &ggtt_vm->mm, hole_start, hole_end) {
                DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
@@ -1793,9 +2083,11 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
                if (!ppgtt)
                        return -ENOMEM;
 
-               ret = __hw_ppgtt_init(dev, ppgtt);
-               if (ret != 0)
+               ret = __hw_ppgtt_init(dev, ppgtt, true);
+               if (ret) {
+                       kfree(ppgtt);
                        return ret;
+               }
 
                dev_priv->mm.aliasing_ppgtt = ppgtt;
        }
@@ -1826,6 +2118,9 @@ void i915_global_gtt_cleanup(struct drm_device *dev)
        }
 
        if (drm_mm_initialized(&vm->mm)) {
+               if (intel_vgpu_active(dev))
+                       intel_vgt_deballoon();
+
                drm_mm_takedown(&vm->mm);
                list_del(&vm->global_link);
        }
@@ -2078,7 +2373,7 @@ static int gen8_gmch_probe(struct drm_device *dev,
                gtt_size = gen8_get_total_gtt_size(snb_gmch_ctl);
        }
 
-       *gtt_total = (gtt_size / sizeof(gen8_gtt_pte_t)) << PAGE_SHIFT;
+       *gtt_total = (gtt_size / sizeof(gen8_pte_t)) << PAGE_SHIFT;
 
        if (IS_CHERRYVIEW(dev))
                chv_setup_private_ppat(dev_priv);
@@ -2123,7 +2418,7 @@ static int gen6_gmch_probe(struct drm_device *dev,
        *stolen = gen6_get_stolen_size(snb_gmch_ctl);
 
        gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl);
-       *gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT;
+       *gtt_total = (gtt_size / sizeof(gen6_pte_t)) << PAGE_SHIFT;
 
        ret = ggtt_probe_common(dev, gtt_size);
 
@@ -2228,11 +2523,16 @@ int i915_gem_gtt_init(struct drm_device *dev)
        return 0;
 }
 
-static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
-                                             struct i915_address_space *vm,
-                                             const struct i915_ggtt_view *view)
+static struct i915_vma *
+__i915_gem_vma_create(struct drm_i915_gem_object *obj,
+                     struct i915_address_space *vm,
+                     const struct i915_ggtt_view *ggtt_view)
 {
-       struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
+       struct i915_vma *vma;
+
+       if (WARN_ON(i915_is_ggtt(vm) != !!ggtt_view))
+               return ERR_PTR(-EINVAL);
+       vma = kzalloc(sizeof(*vma), GFP_KERNEL);
        if (vma == NULL)
                return ERR_PTR(-ENOMEM);
 
@@ -2241,10 +2541,11 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
        INIT_LIST_HEAD(&vma->exec_list);
        vma->vm = vm;
        vma->obj = obj;
-       vma->ggtt_view = *view;
 
        if (INTEL_INFO(vm->dev)->gen >= 6) {
                if (i915_is_ggtt(vm)) {
+                       vma->ggtt_view = *ggtt_view;
+
                        vma->unbind_vma = ggtt_unbind_vma;
                        vma->bind_vma = ggtt_bind_vma;
                } else {
@@ -2253,6 +2554,7 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
                }
        } else {
                BUG_ON(!i915_is_ggtt(vm));
+               vma->ggtt_view = *ggtt_view;
                vma->unbind_vma = i915_ggtt_unbind_vma;
                vma->bind_vma = i915_ggtt_bind_vma;
        }
@@ -2265,38 +2567,170 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
 }
 
 struct i915_vma *
-i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
-                                      struct i915_address_space *vm,
+i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
+                                 struct i915_address_space *vm)
+{
+       struct i915_vma *vma;
+
+       vma = i915_gem_obj_to_vma(obj, vm);
+       if (!vma)
+               vma = __i915_gem_vma_create(obj, vm,
+                                           i915_is_ggtt(vm) ? &i915_ggtt_view_normal : NULL);
+
+       return vma;
+}
+
+struct i915_vma *
+i915_gem_obj_lookup_or_create_ggtt_vma(struct drm_i915_gem_object *obj,
                                       const struct i915_ggtt_view *view)
 {
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
        struct i915_vma *vma;
 
-       vma = i915_gem_obj_to_vma_view(obj, vm, view);
+       if (WARN_ON(!view))
+               return ERR_PTR(-EINVAL);
+
+       vma = i915_gem_obj_to_ggtt_view(obj, view);
+
+       if (IS_ERR(vma))
+               return vma;
+
        if (!vma)
-               vma = __i915_gem_vma_create(obj, vm, view);
+               vma = __i915_gem_vma_create(obj, ggtt, view);
 
        return vma;
+
+}
+
+static void
+rotate_pages(dma_addr_t *in, unsigned int width, unsigned int height,
+            struct sg_table *st)
+{
+       unsigned int column, row;
+       unsigned int src_idx;
+       struct scatterlist *sg = st->sgl;
+
+       st->nents = 0;
+
+       for (column = 0; column < width; column++) {
+               src_idx = width * (height - 1) + column;
+               for (row = 0; row < height; row++) {
+                       st->nents++;
+                       /* We don't need the pages, but need to initialize
+                        * the entries so the sg list can be happily traversed.
+                        * The only thing we need are DMA addresses.
+                        */
+                       sg_set_page(sg, NULL, PAGE_SIZE, 0);
+                       sg_dma_address(sg) = in[src_idx];
+                       sg_dma_len(sg) = PAGE_SIZE;
+                       sg = sg_next(sg);
+                       src_idx -= width;
+               }
+       }
+}
+
+static struct sg_table *
+intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
+                         struct drm_i915_gem_object *obj)
+{
+       struct drm_device *dev = obj->base.dev;
+       struct intel_rotation_info *rot_info = &ggtt_view->rotation_info;
+       unsigned long size, pages, rot_pages;
+       struct sg_page_iter sg_iter;
+       unsigned long i;
+       dma_addr_t *page_addr_list;
+       struct sg_table *st;
+       unsigned int tile_pitch, tile_height;
+       unsigned int width_pages, height_pages;
+       int ret = -ENOMEM;
+
+       pages = obj->base.size / PAGE_SIZE;
+
+       /* Calculate tiling geometry. */
+       tile_height = intel_tile_height(dev, rot_info->pixel_format,
+                                       rot_info->fb_modifier);
+       tile_pitch = PAGE_SIZE / tile_height;
+       width_pages = DIV_ROUND_UP(rot_info->pitch, tile_pitch);
+       height_pages = DIV_ROUND_UP(rot_info->height, tile_height);
+       rot_pages = width_pages * height_pages;
+       size = rot_pages * PAGE_SIZE;
+
+       /* Allocate a temporary list of source pages for random access. */
+       page_addr_list = drm_malloc_ab(pages, sizeof(dma_addr_t));
+       if (!page_addr_list)
+               return ERR_PTR(ret);
+
+       /* Allocate target SG list. */
+       st = kmalloc(sizeof(*st), GFP_KERNEL);
+       if (!st)
+               goto err_st_alloc;
+
+       ret = sg_alloc_table(st, rot_pages, GFP_KERNEL);
+       if (ret)
+               goto err_sg_alloc;
+
+       /* Populate source page list from the object. */
+       i = 0;
+       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
+               page_addr_list[i] = sg_page_iter_dma_address(&sg_iter);
+               i++;
+       }
+
+       /* Rotate the pages. */
+       rotate_pages(page_addr_list, width_pages, height_pages, st);
+
+       DRM_DEBUG_KMS(
+                     "Created rotated page mapping for object size %lu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages).\n",
+                     size, rot_info->pitch, rot_info->height,
+                     rot_info->pixel_format, width_pages, height_pages,
+                     rot_pages);
+
+       drm_free_large(page_addr_list);
+
+       return st;
+
+err_sg_alloc:
+       kfree(st);
+err_st_alloc:
+       drm_free_large(page_addr_list);
+
+       DRM_DEBUG_KMS(
+                     "Failed to create rotated mapping for object size %lu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages)\n",
+                     size, ret, rot_info->pitch, rot_info->height,
+                     rot_info->pixel_format, width_pages, height_pages,
+                     rot_pages);
+       return ERR_PTR(ret);
 }
 
-static inline
-int i915_get_vma_pages(struct i915_vma *vma)
+static inline int
+i915_get_ggtt_vma_pages(struct i915_vma *vma)
 {
+       int ret = 0;
+
        if (vma->ggtt_view.pages)
                return 0;
 
        if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
                vma->ggtt_view.pages = vma->obj->pages;
+       else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
+               vma->ggtt_view.pages =
+                       intel_rotate_fb_obj_pages(&vma->ggtt_view, vma->obj);
        else
                WARN_ONCE(1, "GGTT view %u not implemented!\n",
                          vma->ggtt_view.type);
 
        if (!vma->ggtt_view.pages) {
-               DRM_ERROR("Failed to get pages for VMA view type %u!\n",
+               DRM_ERROR("Failed to get pages for GGTT view type %u!\n",
                          vma->ggtt_view.type);
-               return -EINVAL;
+               ret = -EINVAL;
+       } else if (IS_ERR(vma->ggtt_view.pages)) {
+               ret = PTR_ERR(vma->ggtt_view.pages);
+               vma->ggtt_view.pages = NULL;
+               DRM_ERROR("Failed to get pages for VMA view type %u (%d)!\n",
+                         vma->ggtt_view.type, ret);
        }
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -2312,10 +2746,12 @@ int i915_get_vma_pages(struct i915_vma *vma)
 int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
                  u32 flags)
 {
-       int ret = i915_get_vma_pages(vma);
+       if (i915_is_ggtt(vma->vm)) {
+               int ret = i915_get_ggtt_vma_pages(vma);
 
-       if (ret)
-               return ret;
+               if (ret)
+                       return ret;
+       }
 
        vma->bind_vma(vma, cache_level, flags);
 
index e377c7d27bd42272d9ecf662c4e6e9b80159a6ea..fc03c99317c94af817bc7a17e7ca4663418ec2ec 100644 (file)
 
 struct drm_i915_file_private;
 
-typedef uint32_t gen6_gtt_pte_t;
-typedef uint64_t gen8_gtt_pte_t;
-typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
+typedef uint32_t gen6_pte_t;
+typedef uint64_t gen8_pte_t;
+typedef uint64_t gen8_pde_t;
 
 #define gtt_total_entries(gtt) ((gtt).base.total >> PAGE_SHIFT)
 
-#define I915_PPGTT_PT_ENTRIES          (PAGE_SIZE / sizeof(gen6_gtt_pte_t))
+
 /* gen6-hsw has bit 11-4 for physical addr bit 39-32 */
 #define GEN6_GTT_ADDR_ENCODE(addr)     ((addr) | (((addr) >> 28) & 0xff0))
 #define GEN6_PTE_ADDR_ENCODE(addr)     GEN6_GTT_ADDR_ENCODE(addr)
@@ -51,9 +51,16 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
 #define GEN6_PTE_UNCACHED              (1 << 1)
 #define GEN6_PTE_VALID                 (1 << 0)
 
-#define GEN6_PPGTT_PD_ENTRIES          512
-#define GEN6_PD_SIZE                   (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE)
+#define I915_PTES(pte_len)             (PAGE_SIZE / (pte_len))
+#define I915_PTE_MASK(pte_len)         (I915_PTES(pte_len) - 1)
+#define I915_PDES                      512
+#define I915_PDE_MASK                  (I915_PDES - 1)
+#define NUM_PTE(pde_shift)     (1 << (pde_shift - PAGE_SHIFT))
+
+#define GEN6_PTES                      I915_PTES(sizeof(gen6_pte_t))
+#define GEN6_PD_SIZE                   (I915_PDES * PAGE_SIZE)
 #define GEN6_PD_ALIGN                  (PAGE_SIZE * 16)
+#define GEN6_PDE_SHIFT                 22
 #define GEN6_PDE_VALID                 (1 << 0)
 
 #define GEN7_PTE_CACHE_L3_LLC          (3 << 1)
@@ -88,9 +95,8 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
 #define GEN8_PDE_MASK                  0x1ff
 #define GEN8_PTE_SHIFT                 12
 #define GEN8_PTE_MASK                  0x1ff
-#define GEN8_LEGACY_PDPS               4
-#define GEN8_PTES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_gtt_pte_t))
-#define GEN8_PDES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t))
+#define GEN8_LEGACY_PDPES              4
+#define GEN8_PTES                      I915_PTES(sizeof(gen8_pte_t))
 
 #define PPAT_UNCACHED_INDEX            (_PAGE_PWT | _PAGE_PCD)
 #define PPAT_CACHED_PDE_INDEX          0 /* WB LLC */
@@ -111,15 +117,28 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
 
 enum i915_ggtt_view_type {
        I915_GGTT_VIEW_NORMAL = 0,
+       I915_GGTT_VIEW_ROTATED
+};
+
+struct intel_rotation_info {
+       unsigned int height;
+       unsigned int pitch;
+       uint32_t pixel_format;
+       uint64_t fb_modifier;
 };
 
 struct i915_ggtt_view {
        enum i915_ggtt_view_type type;
 
        struct sg_table *pages;
+
+       union {
+               struct intel_rotation_info rotation_info;
+       };
 };
 
 extern const struct i915_ggtt_view i915_ggtt_view_normal;
+extern const struct i915_ggtt_view i915_ggtt_view_rotated;
 
 enum i915_cache_level;
 
@@ -187,6 +206,28 @@ struct i915_vma {
                         u32 flags);
 };
 
+struct i915_page_table_entry {
+       struct page *page;
+       dma_addr_t daddr;
+
+       unsigned long *used_ptes;
+};
+
+struct i915_page_directory_entry {
+       struct page *page; /* NULL for GEN6-GEN7 */
+       union {
+               uint32_t pd_offset;
+               dma_addr_t daddr;
+       };
+
+       struct i915_page_table_entry *page_table[I915_PDES]; /* PDEs */
+};
+
+struct i915_page_directory_pointer_entry {
+       /* struct page *page; */
+       struct i915_page_directory_entry *page_directory[GEN8_LEGACY_PDPES];
+};
+
 struct i915_address_space {
        struct drm_mm mm;
        struct drm_device *dev;
@@ -223,9 +264,12 @@ struct i915_address_space {
        struct list_head inactive_list;
 
        /* FIXME: Need a more generic return type */
-       gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid, u32 flags); /* Create a valid PTE */
+       gen6_pte_t (*pte_encode)(dma_addr_t addr,
+                                enum i915_cache_level level,
+                                bool valid, u32 flags); /* Create a valid PTE */
+       int (*allocate_va_range)(struct i915_address_space *vm,
+                                uint64_t start,
+                                uint64_t length);
        void (*clear_range)(struct i915_address_space *vm,
                            uint64_t start,
                            uint64_t length,
@@ -269,30 +313,90 @@ struct i915_hw_ppgtt {
        struct i915_address_space base;
        struct kref ref;
        struct drm_mm_node node;
+       unsigned long pd_dirty_rings;
        unsigned num_pd_entries;
        unsigned num_pd_pages; /* gen8+ */
        union {
-               struct page **pt_pages;
-               struct page **gen8_pt_pages[GEN8_LEGACY_PDPS];
-       };
-       struct page *pd_pages;
-       union {
-               uint32_t pd_offset;
-               dma_addr_t pd_dma_addr[GEN8_LEGACY_PDPS];
-       };
-       union {
-               dma_addr_t *pt_dma_addr;
-               dma_addr_t *gen8_pt_dma_addr[4];
+               struct i915_page_directory_pointer_entry pdp;
+               struct i915_page_directory_entry pd;
        };
 
+       struct i915_page_table_entry *scratch_pt;
+
        struct drm_i915_file_private *file_priv;
 
+       gen6_pte_t __iomem *pd_addr;
+
        int (*enable)(struct i915_hw_ppgtt *ppgtt);
        int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
                         struct intel_engine_cs *ring);
        void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m);
 };
 
+/* For each pde iterates over every pde between from start until start + length.
+ * If start, and start+length are not perfectly divisible, the macro will round
+ * down, and up as needed. The macro modifies pde, start, and length. Dev is
+ * only used to differentiate shift values. Temp is temp.  On gen6/7, start = 0,
+ * and length = 2G effectively iterates over every PDE in the system.
+ *
+ * XXX: temp is not actually needed, but it saves doing the ALIGN operation.
+ */
+#define gen6_for_each_pde(pt, pd, start, length, temp, iter) \
+       for (iter = gen6_pde_index(start); \
+            pt = (pd)->page_table[iter], length > 0 && iter < I915_PDES; \
+            iter++, \
+            temp = ALIGN(start+1, 1 << GEN6_PDE_SHIFT) - start, \
+            temp = min_t(unsigned, temp, length), \
+            start += temp, length -= temp)
+
+static inline uint32_t i915_pte_index(uint64_t address, uint32_t pde_shift)
+{
+       const uint32_t mask = NUM_PTE(pde_shift) - 1;
+
+       return (address >> PAGE_SHIFT) & mask;
+}
+
+/* Helper to counts the number of PTEs within the given length. This count
+ * does not cross a page table boundary, so the max value would be
+ * GEN6_PTES for GEN6, and GEN8_PTES for GEN8.
+*/
+static inline uint32_t i915_pte_count(uint64_t addr, size_t length,
+                                     uint32_t pde_shift)
+{
+       const uint64_t mask = ~((1 << pde_shift) - 1);
+       uint64_t end;
+
+       WARN_ON(length == 0);
+       WARN_ON(offset_in_page(addr|length));
+
+       end = addr + length;
+
+       if ((addr & mask) != (end & mask))
+               return NUM_PTE(pde_shift) - i915_pte_index(addr, pde_shift);
+
+       return i915_pte_index(end, pde_shift) - i915_pte_index(addr, pde_shift);
+}
+
+static inline uint32_t i915_pde_index(uint64_t addr, uint32_t shift)
+{
+       return (addr >> shift) & I915_PDE_MASK;
+}
+
+static inline uint32_t gen6_pte_index(uint32_t addr)
+{
+       return i915_pte_index(addr, GEN6_PDE_SHIFT);
+}
+
+static inline size_t gen6_pte_count(uint32_t addr, uint32_t length)
+{
+       return i915_pte_count(addr, length, GEN6_PDE_SHIFT);
+}
+
+static inline uint32_t gen6_pde_index(uint32_t addr)
+{
+       return i915_pde_index(addr, GEN6_PDE_SHIFT);
+}
+
 int i915_gem_gtt_init(struct drm_device *dev);
 void i915_gem_init_global_gtt(struct drm_device *dev);
 void i915_global_gtt_cleanup(struct drm_device *dev);
@@ -321,4 +425,14 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev);
 int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj);
 void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj);
 
+static inline bool
+i915_ggtt_view_equal(const struct i915_ggtt_view *a,
+                     const struct i915_ggtt_view *b)
+{
+       if (WARN_ON(!a || !b))
+               return false;
+
+       return a->type == b->type;
+}
+
 #endif
diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c
new file mode 100644 (file)
index 0000000..f7929e7
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright Â© 2008-2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/oom.h>
+#include <linux/shmem_fs.h>
+#include <linux/slab.h>
+#include <linux/swap.h>
+#include <linux/pci.h>
+#include <linux/dma-buf.h>
+#include <drm/drmP.h>
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "i915_trace.h"
+
+static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
+{
+       if (!mutex_is_locked(mutex))
+               return false;
+
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
+       return mutex->owner == task;
+#else
+       /* Since UP may be pre-empted, we cannot assume that we own the lock */
+       return false;
+#endif
+}
+
+/**
+ * i915_gem_shrink - Shrink buffer object caches
+ * @dev_priv: i915 device
+ * @target: amount of memory to make available, in pages
+ * @flags: control flags for selecting cache types
+ *
+ * This function is the main interface to the shrinker. It will try to release
+ * up to @target pages of main memory backing storage from buffer objects.
+ * Selection of the specific caches can be done with @flags. This is e.g. useful
+ * when purgeable objects should be removed from caches preferentially.
+ *
+ * Note that it's not guaranteed that released amount is actually available as
+ * free system memory - the pages might still be in-used to due to other reasons
+ * (like cpu mmaps) or the mm core has reused them before we could grab them.
+ * Therefore code that needs to explicitly shrink buffer objects caches (e.g. to
+ * avoid deadlocks in memory reclaim) must fall back to i915_gem_shrink_all().
+ *
+ * Also note that any kind of pinning (both per-vma address space pins and
+ * backing storage pins at the buffer object level) result in the shrinker code
+ * having to skip the object.
+ *
+ * Returns:
+ * The number of pages of backing storage actually released.
+ */
+unsigned long
+i915_gem_shrink(struct drm_i915_private *dev_priv,
+               long target, unsigned flags)
+{
+       const struct {
+               struct list_head *list;
+               unsigned int bit;
+       } phases[] = {
+               { &dev_priv->mm.unbound_list, I915_SHRINK_UNBOUND },
+               { &dev_priv->mm.bound_list, I915_SHRINK_BOUND },
+               { NULL, 0 },
+       }, *phase;
+       unsigned long count = 0;
+
+       /*
+        * As we may completely rewrite the (un)bound list whilst unbinding
+        * (due to retiring requests) we have to strictly process only
+        * one element of the list at the time, and recheck the list
+        * on every iteration.
+        *
+        * In particular, we must hold a reference whilst removing the
+        * object as we may end up waiting for and/or retiring the objects.
+        * This might release the final reference (held by the active list)
+        * and result in the object being freed from under us. This is
+        * similar to the precautions the eviction code must take whilst
+        * removing objects.
+        *
+        * Also note that although these lists do not hold a reference to
+        * the object we can safely grab one here: The final object
+        * unreferencing and the bound_list are both protected by the
+        * dev->struct_mutex and so we won't ever be able to observe an
+        * object on the bound_list with a reference count equals 0.
+        */
+       for (phase = phases; phase->list; phase++) {
+               struct list_head still_in_list;
+
+               if ((flags & phase->bit) == 0)
+                       continue;
+
+               INIT_LIST_HEAD(&still_in_list);
+               while (count < target && !list_empty(phase->list)) {
+                       struct drm_i915_gem_object *obj;
+                       struct i915_vma *vma, *v;
+
+                       obj = list_first_entry(phase->list,
+                                              typeof(*obj), global_list);
+                       list_move_tail(&obj->global_list, &still_in_list);
+
+                       if (flags & I915_SHRINK_PURGEABLE &&
+                           obj->madv != I915_MADV_DONTNEED)
+                               continue;
+
+                       drm_gem_object_reference(&obj->base);
+
+                       /* For the unbound phase, this should be a no-op! */
+                       list_for_each_entry_safe(vma, v,
+                                                &obj->vma_list, vma_link)
+                               if (i915_vma_unbind(vma))
+                                       break;
+
+                       if (i915_gem_object_put_pages(obj) == 0)
+                               count += obj->base.size >> PAGE_SHIFT;
+
+                       drm_gem_object_unreference(&obj->base);
+               }
+               list_splice(&still_in_list, phase->list);
+       }
+
+       return count;
+}
+
+/**
+ * i915_gem_shrink - Shrink buffer object caches completely
+ * @dev_priv: i915 device
+ *
+ * This is a simple wraper around i915_gem_shrink() to aggressively shrink all
+ * caches completely. It also first waits for and retires all outstanding
+ * requests to also be able to release backing storage for active objects.
+ *
+ * This should only be used in code to intentionally quiescent the gpu or as a
+ * last-ditch effort when memory seems to have run out.
+ *
+ * Returns:
+ * The number of pages of backing storage actually released.
+ */
+unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv)
+{
+       i915_gem_evict_everything(dev_priv->dev);
+       return i915_gem_shrink(dev_priv, LONG_MAX,
+                              I915_SHRINK_BOUND | I915_SHRINK_UNBOUND);
+}
+
+static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock)
+{
+       if (!mutex_trylock(&dev->struct_mutex)) {
+               if (!mutex_is_locked_by(&dev->struct_mutex, current))
+                       return false;
+
+               if (to_i915(dev)->mm.shrinker_no_lock_stealing)
+                       return false;
+
+               *unlock = false;
+       } else
+               *unlock = true;
+
+       return true;
+}
+
+static int num_vma_bound(struct drm_i915_gem_object *obj)
+{
+       struct i915_vma *vma;
+       int count = 0;
+
+       list_for_each_entry(vma, &obj->vma_list, vma_link)
+               if (drm_mm_node_allocated(&vma->node))
+                       count++;
+
+       return count;
+}
+
+static unsigned long
+i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(shrinker, struct drm_i915_private, mm.shrinker);
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_i915_gem_object *obj;
+       unsigned long count;
+       bool unlock;
+
+       if (!i915_gem_shrinker_lock(dev, &unlock))
+               return 0;
+
+       count = 0;
+       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
+               if (obj->pages_pin_count == 0)
+                       count += obj->base.size >> PAGE_SHIFT;
+
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
+               if (!i915_gem_obj_is_pinned(obj) &&
+                   obj->pages_pin_count == num_vma_bound(obj))
+                       count += obj->base.size >> PAGE_SHIFT;
+       }
+
+       if (unlock)
+               mutex_unlock(&dev->struct_mutex);
+
+       return count;
+}
+
+static unsigned long
+i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(shrinker, struct drm_i915_private, mm.shrinker);
+       struct drm_device *dev = dev_priv->dev;
+       unsigned long freed;
+       bool unlock;
+
+       if (!i915_gem_shrinker_lock(dev, &unlock))
+               return SHRINK_STOP;
+
+       freed = i915_gem_shrink(dev_priv,
+                               sc->nr_to_scan,
+                               I915_SHRINK_BOUND |
+                               I915_SHRINK_UNBOUND |
+                               I915_SHRINK_PURGEABLE);
+       if (freed < sc->nr_to_scan)
+               freed += i915_gem_shrink(dev_priv,
+                                        sc->nr_to_scan - freed,
+                                        I915_SHRINK_BOUND |
+                                        I915_SHRINK_UNBOUND);
+       if (unlock)
+               mutex_unlock(&dev->struct_mutex);
+
+       return freed;
+}
+
+static int
+i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(nb, struct drm_i915_private, mm.oom_notifier);
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_i915_gem_object *obj;
+       unsigned long timeout = msecs_to_jiffies(5000) + 1;
+       unsigned long pinned, bound, unbound, freed_pages;
+       bool was_interruptible;
+       bool unlock;
+
+       while (!i915_gem_shrinker_lock(dev, &unlock) && --timeout) {
+               schedule_timeout_killable(1);
+               if (fatal_signal_pending(current))
+                       return NOTIFY_DONE;
+       }
+       if (timeout == 0) {
+               pr_err("Unable to purge GPU memory due lock contention.\n");
+               return NOTIFY_DONE;
+       }
+
+       was_interruptible = dev_priv->mm.interruptible;
+       dev_priv->mm.interruptible = false;
+
+       freed_pages = i915_gem_shrink_all(dev_priv);
+
+       dev_priv->mm.interruptible = was_interruptible;
+
+       /* Because we may be allocating inside our own driver, we cannot
+        * assert that there are no objects with pinned pages that are not
+        * being pointed to by hardware.
+        */
+       unbound = bound = pinned = 0;
+       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
+               if (!obj->base.filp) /* not backed by a freeable object */
+                       continue;
+
+               if (obj->pages_pin_count)
+                       pinned += obj->base.size;
+               else
+                       unbound += obj->base.size;
+       }
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
+               if (!obj->base.filp)
+                       continue;
+
+               if (obj->pages_pin_count)
+                       pinned += obj->base.size;
+               else
+                       bound += obj->base.size;
+       }
+
+       if (unlock)
+               mutex_unlock(&dev->struct_mutex);
+
+       if (freed_pages || unbound || bound)
+               pr_info("Purging GPU memory, %lu bytes freed, %lu bytes still pinned.\n",
+                       freed_pages << PAGE_SHIFT, pinned);
+       if (unbound || bound)
+               pr_err("%lu and %lu bytes still available in the "
+                      "bound and unbound GPU page lists.\n",
+                      bound, unbound);
+
+       *(unsigned long *)ptr += freed_pages;
+       return NOTIFY_DONE;
+}
+
+/**
+ * i915_gem_shrinker_init - Initialize i915 shrinker
+ * @dev_priv: i915 device
+ *
+ * This function registers and sets up the i915 shrinker and OOM handler.
+ */
+void i915_gem_shrinker_init(struct drm_i915_private *dev_priv)
+{
+       dev_priv->mm.shrinker.scan_objects = i915_gem_shrinker_scan;
+       dev_priv->mm.shrinker.count_objects = i915_gem_shrinker_count;
+       dev_priv->mm.shrinker.seeks = DEFAULT_SEEKS;
+       register_shrinker(&dev_priv->mm.shrinker);
+
+       dev_priv->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom;
+       register_oom_notifier(&dev_priv->mm.oom_notifier);
+}
index a2045848bd1a3d5d37c299d34b7e19dce50173d7..f8da71682c965758985192d861a3e09b0b5157ab 100644 (file)
@@ -231,7 +231,7 @@ static int i915_setup_compression(struct drm_device *dev, int size, int fb_cpp)
                           dev_priv->mm.stolen_base + compressed_llb->start);
        }
 
-       dev_priv->fbc.size = size / dev_priv->fbc.threshold;
+       dev_priv->fbc.uncompressed_size = size;
 
        DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n",
                      size);
@@ -253,7 +253,7 @@ int i915_gem_stolen_setup_compression(struct drm_device *dev, int size, int fb_c
        if (!drm_mm_initialized(&dev_priv->mm.stolen))
                return -ENODEV;
 
-       if (size < dev_priv->fbc.size)
+       if (size <= dev_priv->fbc.uncompressed_size)
                return 0;
 
        /* Release any current block */
@@ -266,7 +266,7 @@ void i915_gem_stolen_cleanup_compression(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (dev_priv->fbc.size == 0)
+       if (dev_priv->fbc.uncompressed_size == 0)
                return;
 
        drm_mm_remove_node(&dev_priv->fbc.compressed_fb);
@@ -276,7 +276,7 @@ void i915_gem_stolen_cleanup_compression(struct drm_device *dev)
                kfree(dev_priv->fbc.compressed_llb);
        }
 
-       dev_priv->fbc.size = 0;
+       dev_priv->fbc.uncompressed_size = 0;
 }
 
 void i915_gem_cleanup_stolen(struct drm_device *dev)
@@ -485,10 +485,8 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
                        stolen_offset, gtt_offset, size);
 
        /* KISS and expect everything to be page-aligned */
-       BUG_ON(stolen_offset & 4095);
-       BUG_ON(size & 4095);
-
-       if (WARN_ON(size == 0))
+       if (WARN_ON(size == 0) || WARN_ON(size & 4095) ||
+           WARN_ON(stolen_offset & 4095))
                return NULL;
 
        stolen = kzalloc(sizeof(*stolen), GFP_KERNEL);
index 7a24bd1a51f648b340ce15d5ee98771cd1fd77d9..6377b22269ad1e7157058baf1447cb548362306c 100644 (file)
@@ -335,9 +335,10 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
+       mutex_lock(&dev->struct_mutex);
        if (i915_gem_obj_is_pinned(obj) || obj->framebuffer_references) {
-               drm_gem_object_unreference_unlocked(&obj->base);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto err;
        }
 
        if (args->tiling_mode == I915_TILING_NONE) {
@@ -369,7 +370,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                }
        }
 
-       mutex_lock(&dev->struct_mutex);
        if (args->tiling_mode != obj->tiling_mode ||
            args->stride != obj->stride) {
                /* We need to rebind the object if its current allocation
@@ -424,6 +424,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                obj->bit_17 = NULL;
        }
 
+err:
        drm_gem_object_unreference(&obj->base);
        mutex_unlock(&dev->struct_mutex);
 
index 48ddbf44c8629f34eb570a94e3e9d8572ae1511f..1d4e60df88836761098e8a2ce391382d2b7d867d 100644 (file)
@@ -386,6 +386,11 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 
        if (INTEL_INFO(dev)->gen >= 6) {
                err_printf(m, "ERROR: 0x%08x\n", error->error);
+
+               if (INTEL_INFO(dev)->gen >= 8)
+                       err_printf(m, "FAULT_TLB_DATA: 0x%08x 0x%08x\n",
+                                  error->fault_data1, error->fault_data0);
+
                err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
        }
 
@@ -555,7 +560,14 @@ static void i915_error_state_free(struct kref *error_ref)
        }
 
        i915_error_object_free(error->semaphore_obj);
+
+       for (i = 0; i < error->vm_count; i++)
+               kfree(error->active_bo[i]);
+
        kfree(error->active_bo);
+       kfree(error->active_bo_count);
+       kfree(error->pinned_bo);
+       kfree(error->pinned_bo_count);
        kfree(error->overlay);
        kfree(error->display);
        kfree(error);
@@ -994,12 +1006,11 @@ static void i915_gem_record_rings(struct drm_device *dev,
                                        i915_error_ggtt_object_create(dev_priv,
                                                             ring->scratch.obj);
 
-                       if (request->file_priv) {
+                       if (request->pid) {
                                struct task_struct *task;
 
                                rcu_read_lock();
-                               task = pid_task(request->file_priv->file->pid,
-                                               PIDTYPE_PID);
+                               task = pid_task(request->pid, PIDTYPE_PID);
                                if (task) {
                                        strcpy(error->ring[i].comm, task->comm);
                                        error->ring[i].pid = task->pid;
@@ -1165,6 +1176,11 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
        if (IS_GEN7(dev))
                error->err_int = I915_READ(GEN7_ERR_INT);
 
+       if (INTEL_INFO(dev)->gen >= 8) {
+               error->fault_data0 = I915_READ(GEN8_FAULT_TLB_DATA0);
+               error->fault_data1 = I915_READ(GEN8_FAULT_TLB_DATA1);
+       }
+
        if (IS_GEN6(dev)) {
                error->forcewake = I915_READ(FORCEWAKE);
                error->gab_ctl = I915_READ(GAB_CTL);
index 4145d95902f54fbd9fb4f92668fe10fde2b330a0..14ecb4d13a1aa2b24ca102097c90811bddc8c190 100644 (file)
@@ -277,6 +277,7 @@ void gen6_reset_rps_interrupts(struct drm_device *dev)
        I915_WRITE(reg, dev_priv->pm_rps_events);
        I915_WRITE(reg, dev_priv->pm_rps_events);
        POSTING_READ(reg);
+       dev_priv->rps.pm_iir = 0;
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
@@ -330,12 +331,10 @@ void gen6_disable_rps_interrupts(struct drm_device *dev)
        __gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
        I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) &
                                ~dev_priv->pm_rps_events);
-       I915_WRITE(gen6_pm_iir(dev_priv), dev_priv->pm_rps_events);
-       I915_WRITE(gen6_pm_iir(dev_priv), dev_priv->pm_rps_events);
-
-       dev_priv->rps.pm_iir = 0;
 
        spin_unlock_irq(&dev_priv->irq_lock);
+
+       synchronize_irq(dev->irq);
 }
 
 /**
@@ -492,31 +491,6 @@ static void i915_enable_asle_pipestat(struct drm_device *dev)
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
-/**
- * i915_pipe_enabled - check if a pipe is enabled
- * @dev: DRM device
- * @pipe: pipe to check
- *
- * Reading certain registers when the pipe is disabled can hang the chip.
- * Use this routine to make sure the PLL is running and the pipe is active
- * before reading such registers if unsure.
- */
-static int
-i915_pipe_enabled(struct drm_device *dev, int pipe)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               /* Locking is horribly broken here, but whatever. */
-               struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-               return intel_crtc->active;
-       } else {
-               return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
-       }
-}
-
 /*
  * This timing diagram depicts the video signal in and
  * around the vertical blanking period.
@@ -582,34 +556,16 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
        unsigned long high_frame;
        unsigned long low_frame;
        u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
+       struct intel_crtc *intel_crtc =
+               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+       const struct drm_display_mode *mode =
+               &intel_crtc->config->base.adjusted_mode;
 
-       if (!i915_pipe_enabled(dev, pipe)) {
-               DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
-                               "pipe %c\n", pipe_name(pipe));
-               return 0;
-       }
-
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               struct intel_crtc *intel_crtc =
-                       to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-               const struct drm_display_mode *mode =
-                       &intel_crtc->config->base.adjusted_mode;
-
-               htotal = mode->crtc_htotal;
-               hsync_start = mode->crtc_hsync_start;
-               vbl_start = mode->crtc_vblank_start;
-               if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-                       vbl_start = DIV_ROUND_UP(vbl_start, 2);
-       } else {
-               enum transcoder cpu_transcoder = (enum transcoder) pipe;
-
-               htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1;
-               hsync_start = (I915_READ(HSYNC(cpu_transcoder))  & 0x1fff) + 1;
-               vbl_start = (I915_READ(VBLANK(cpu_transcoder)) & 0x1fff) + 1;
-               if ((I915_READ(PIPECONF(cpu_transcoder)) &
-                    PIPECONF_INTERLACE_MASK) != PIPECONF_PROGRESSIVE)
-                       vbl_start = DIV_ROUND_UP(vbl_start, 2);
-       }
+       htotal = mode->crtc_htotal;
+       hsync_start = mode->crtc_hsync_start;
+       vbl_start = mode->crtc_vblank_start;
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               vbl_start = DIV_ROUND_UP(vbl_start, 2);
 
        /* Convert to pixel count */
        vbl_start *= htotal;
@@ -648,12 +604,6 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int reg = PIPE_FRMCOUNT_GM45(pipe);
 
-       if (!i915_pipe_enabled(dev, pipe)) {
-               DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
-                                "pipe %c\n", pipe_name(pipe));
-               return 0;
-       }
-
        return I915_READ(reg);
 }
 
@@ -840,7 +790,7 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
                return -EINVAL;
        }
 
-       if (!crtc->enabled) {
+       if (!crtc->state->enable) {
                DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
                return -EBUSY;
        }
@@ -1046,129 +996,73 @@ static void notify_ring(struct drm_device *dev,
        wake_up_all(&ring->irq_queue);
 }
 
-static u32 vlv_c0_residency(struct drm_i915_private *dev_priv,
-                           struct intel_rps_ei *rps_ei)
+static void vlv_c0_read(struct drm_i915_private *dev_priv,
+                       struct intel_rps_ei *ei)
 {
-       u32 cz_ts, cz_freq_khz;
-       u32 render_count, media_count;
-       u32 elapsed_render, elapsed_media, elapsed_time;
-       u32 residency = 0;
-
-       cz_ts = vlv_punit_read(dev_priv, PUNIT_REG_CZ_TIMESTAMP);
-       cz_freq_khz = DIV_ROUND_CLOSEST(dev_priv->mem_freq * 1000, 4);
-
-       render_count = I915_READ(VLV_RENDER_C0_COUNT_REG);
-       media_count = I915_READ(VLV_MEDIA_C0_COUNT_REG);
-
-       if (rps_ei->cz_clock == 0) {
-               rps_ei->cz_clock = cz_ts;
-               rps_ei->render_c0 = render_count;
-               rps_ei->media_c0 = media_count;
-
-               return dev_priv->rps.cur_freq;
-       }
-
-       elapsed_time = cz_ts - rps_ei->cz_clock;
-       rps_ei->cz_clock = cz_ts;
+       ei->cz_clock = vlv_punit_read(dev_priv, PUNIT_REG_CZ_TIMESTAMP);
+       ei->render_c0 = I915_READ(VLV_RENDER_C0_COUNT);
+       ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT);
+}
 
-       elapsed_render = render_count - rps_ei->render_c0;
-       rps_ei->render_c0 = render_count;
+static bool vlv_c0_above(struct drm_i915_private *dev_priv,
+                        const struct intel_rps_ei *old,
+                        const struct intel_rps_ei *now,
+                        int threshold)
+{
+       u64 time, c0;
 
-       elapsed_media = media_count - rps_ei->media_c0;
-       rps_ei->media_c0 = media_count;
+       if (old->cz_clock == 0)
+               return false;
 
-       /* Convert all the counters into common unit of milli sec */
-       elapsed_time /= VLV_CZ_CLOCK_TO_MILLI_SEC;
-       elapsed_render /=  cz_freq_khz;
-       elapsed_media /= cz_freq_khz;
+       time = now->cz_clock - old->cz_clock;
+       time *= threshold * dev_priv->mem_freq;
 
-       /*
-        * Calculate overall C0 residency percentage
-        * only if elapsed time is non zero
+       /* Workload can be split between render + media, e.g. SwapBuffers
+        * being blitted in X after being rendered in mesa. To account for
+        * this we need to combine both engines into our activity counter.
         */
-       if (elapsed_time) {
-               residency =
-                       ((max(elapsed_render, elapsed_media) * 100)
-                               / elapsed_time);
-       }
+       c0 = now->render_c0 - old->render_c0;
+       c0 += now->media_c0 - old->media_c0;
+       c0 *= 100 * VLV_CZ_CLOCK_TO_MILLI_SEC * 4 / 1000;
 
-       return residency;
+       return c0 >= time;
 }
 
-/**
- * vlv_calc_delay_from_C0_counters - Increase/Decrease freq based on GPU
- * busy-ness calculated from C0 counters of render & media power wells
- * @dev_priv: DRM device private
- *
- */
-static int vlv_calc_delay_from_C0_counters(struct drm_i915_private *dev_priv)
+void gen6_rps_reset_ei(struct drm_i915_private *dev_priv)
 {
-       u32 residency_C0_up = 0, residency_C0_down = 0;
-       int new_delay, adj;
-
-       dev_priv->rps.ei_interrupt_count++;
-
-       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-
-
-       if (dev_priv->rps.up_ei.cz_clock == 0) {
-               vlv_c0_residency(dev_priv, &dev_priv->rps.up_ei);
-               vlv_c0_residency(dev_priv, &dev_priv->rps.down_ei);
-               return dev_priv->rps.cur_freq;
-       }
+       vlv_c0_read(dev_priv, &dev_priv->rps.down_ei);
+       dev_priv->rps.up_ei = dev_priv->rps.down_ei;
+}
 
+static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
+{
+       struct intel_rps_ei now;
+       u32 events = 0;
 
-       /*
-        * To down throttle, C0 residency should be less than down threshold
-        * for continous EI intervals. So calculate down EI counters
-        * once in VLV_INT_COUNT_FOR_DOWN_EI
-        */
-       if (dev_priv->rps.ei_interrupt_count == VLV_INT_COUNT_FOR_DOWN_EI) {
+       if ((pm_iir & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED)) == 0)
+               return 0;
 
-               dev_priv->rps.ei_interrupt_count = 0;
+       vlv_c0_read(dev_priv, &now);
+       if (now.cz_clock == 0)
+               return 0;
 
-               residency_C0_down = vlv_c0_residency(dev_priv,
-                                                    &dev_priv->rps.down_ei);
-       } else {
-               residency_C0_up = vlv_c0_residency(dev_priv,
-                                                  &dev_priv->rps.up_ei);
+       if (pm_iir & GEN6_PM_RP_DOWN_EI_EXPIRED) {
+               if (!vlv_c0_above(dev_priv,
+                                 &dev_priv->rps.down_ei, &now,
+                                 VLV_RP_DOWN_EI_THRESHOLD))
+                       events |= GEN6_PM_RP_DOWN_THRESHOLD;
+               dev_priv->rps.down_ei = now;
        }
 
-       new_delay = dev_priv->rps.cur_freq;
-
-       adj = dev_priv->rps.last_adj;
-       /* C0 residency is greater than UP threshold. Increase Frequency */
-       if (residency_C0_up >= VLV_RP_UP_EI_THRESHOLD) {
-               if (adj > 0)
-                       adj *= 2;
-               else
-                       adj = 1;
-
-               if (dev_priv->rps.cur_freq < dev_priv->rps.max_freq_softlimit)
-                       new_delay = dev_priv->rps.cur_freq + adj;
-
-               /*
-                * For better performance, jump directly
-                * to RPe if we're below it.
-                */
-               if (new_delay < dev_priv->rps.efficient_freq)
-                       new_delay = dev_priv->rps.efficient_freq;
-
-       } else if (!dev_priv->rps.ei_interrupt_count &&
-                       (residency_C0_down < VLV_RP_DOWN_EI_THRESHOLD)) {
-               if (adj < 0)
-                       adj *= 2;
-               else
-                       adj = -1;
-               /*
-                * This means, C0 residency is less than down threshold over
-                * a period of VLV_INT_COUNT_FOR_DOWN_EI. So, reduce the freq
-                */
-               if (dev_priv->rps.cur_freq > dev_priv->rps.min_freq_softlimit)
-                       new_delay = dev_priv->rps.cur_freq + adj;
+       if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) {
+               if (vlv_c0_above(dev_priv,
+                                &dev_priv->rps.up_ei, &now,
+                                VLV_RP_UP_EI_THRESHOLD))
+                       events |= GEN6_PM_RP_UP_THRESHOLD;
+               dev_priv->rps.up_ei = now;
        }
 
-       return new_delay;
+       return events;
 }
 
 static void gen6_pm_rps_work(struct work_struct *work)
@@ -1198,6 +1092,8 @@ static void gen6_pm_rps_work(struct work_struct *work)
 
        mutex_lock(&dev_priv->rps.hw_lock);
 
+       pm_iir |= vlv_wa_c0_ei(dev_priv, pm_iir);
+
        adj = dev_priv->rps.last_adj;
        if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
                if (adj > 0)
@@ -1220,8 +1116,6 @@ static void gen6_pm_rps_work(struct work_struct *work)
                else
                        new_delay = dev_priv->rps.min_freq_softlimit;
                adj = 0;
-       } else if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) {
-               new_delay = vlv_calc_delay_from_C0_counters(dev_priv);
        } else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
                if (adj < 0)
                        adj *= 2;
@@ -1243,10 +1137,7 @@ static void gen6_pm_rps_work(struct work_struct *work)
 
        dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_freq;
 
-       if (IS_VALLEYVIEW(dev_priv->dev))
-               valleyview_set_rps(dev_priv->dev, new_delay);
-       else
-               gen6_set_rps(dev_priv->dev, new_delay);
+       intel_set_rps(dev_priv->dev, new_delay);
 
        mutex_unlock(&dev_priv->rps.hw_lock);
 }
@@ -1748,11 +1639,6 @@ static void i9xx_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
  * the work queue. */
 static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
 {
-       /* TODO: RPS on GEN9+ is not supported yet. */
-       if (WARN_ONCE(INTEL_INFO(dev_priv)->gen >= 9,
-                     "GEN9+: unexpected RPS IRQ\n"))
-               return;
-
        if (pm_iir & dev_priv->pm_rps_events) {
                spin_lock(&dev_priv->irq_lock);
                gen6_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
@@ -1892,6 +1778,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
        u32 iir, gt_iir, pm_iir;
        irqreturn_t ret = IRQ_NONE;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        while (true) {
                /* Find, clear, then process each source of interrupt */
 
@@ -1936,6 +1825,9 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
        u32 master_ctl, iir;
        irqreturn_t ret = IRQ_NONE;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        for (;;) {
                master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
                iir = I915_READ(VLV_IIR);
@@ -2208,6 +2100,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        u32 de_iir, gt_iir, de_ier, sde_ier = 0;
        irqreturn_t ret = IRQ_NONE;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        /* We get interrupts on unclaimed registers, so check for this before we
         * do any I915_{READ,WRITE}. */
        intel_uncore_check_errors(dev);
@@ -2279,6 +2174,9 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
        enum pipe pipe;
        u32 aux_mask = GEN8_AUX_CHANNEL_A;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        if (IS_GEN9(dev))
                aux_mask |=  GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
                        GEN9_AUX_CHANNEL_D;
@@ -2650,9 +2548,6 @@ static int i915_enable_vblank(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
-       if (!i915_pipe_enabled(dev, pipe))
-               return -EINVAL;
-
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, pipe,
@@ -2672,9 +2567,6 @@ static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
        uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
                                                     DE_PIPE_VBLANK(pipe);
 
-       if (!i915_pipe_enabled(dev, pipe))
-               return -EINVAL;
-
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        ironlake_enable_display_irq(dev_priv, bit);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@@ -2687,9 +2579,6 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
-       if (!i915_pipe_enabled(dev, pipe))
-               return -EINVAL;
-
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        i915_enable_pipestat(dev_priv, pipe,
                             PIPE_START_VBLANK_INTERRUPT_STATUS);
@@ -2703,9 +2592,6 @@ static int gen8_enable_vblank(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
-       if (!i915_pipe_enabled(dev, pipe))
-               return -EINVAL;
-
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_VBLANK;
        I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
@@ -2757,9 +2643,6 @@ static void gen8_disable_vblank(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
-       if (!i915_pipe_enabled(dev, pipe))
-               return;
-
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_VBLANK;
        I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
@@ -3224,15 +3107,24 @@ static void gen8_irq_reset(struct drm_device *dev)
        ibx_irq_reset(dev);
 }
 
-void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv)
+void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
+                                    unsigned int pipe_mask)
 {
        uint32_t extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN;
 
        spin_lock_irq(&dev_priv->irq_lock);
-       GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_B, dev_priv->de_irq_mask[PIPE_B],
-                         ~dev_priv->de_irq_mask[PIPE_B] | extra_ier);
-       GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_C, dev_priv->de_irq_mask[PIPE_C],
-                         ~dev_priv->de_irq_mask[PIPE_C] | extra_ier);
+       if (pipe_mask & 1 << PIPE_A)
+               GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_A,
+                                 dev_priv->de_irq_mask[PIPE_A],
+                                 ~dev_priv->de_irq_mask[PIPE_A] | extra_ier);
+       if (pipe_mask & 1 << PIPE_B)
+               GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_B,
+                                 dev_priv->de_irq_mask[PIPE_B],
+                                 ~dev_priv->de_irq_mask[PIPE_B] | extra_ier);
+       if (pipe_mask & 1 << PIPE_C)
+               GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_C,
+                                 dev_priv->de_irq_mask[PIPE_C],
+                                 ~dev_priv->de_irq_mask[PIPE_C] | extra_ier);
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
@@ -3771,6 +3663,9 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        iir = I915_READ16(IIR);
        if (iir == 0)
                return IRQ_NONE;
@@ -3951,6 +3846,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
        int pipe, ret = IRQ_NONE;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        iir = I915_READ(IIR);
        do {
                bool irq_received = (iir & ~flip_mask) != 0;
@@ -4171,6 +4069,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        iir = I915_READ(IIR);
 
        for (;;) {
@@ -4341,7 +4242,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
        /* Let's track the enabled rps events */
        if (IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
                /* WaGsvRC0ResidencyMethod:vlv */
-               dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
+               dev_priv->pm_rps_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED;
        else
                dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
 
@@ -4371,10 +4272,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
        if (!IS_GEN2(dev_priv))
                dev->vblank_disable_immediate = true;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
-               dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
-       }
+       dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
+       dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
 
        if (IS_CHERRYVIEW(dev_priv)) {
                dev->driver->irq_handler = cherryview_irq_handler;
@@ -4520,6 +4419,7 @@ void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
 {
        dev_priv->dev->driver->irq_uninstall(dev_priv->dev);
        dev_priv->pm.irqs_enabled = false;
+       synchronize_irq(dev_priv->dev->irq);
 }
 
 /**
index 44f2262a555335ec6c0d6fe86e78537098ebc6ae..bb64415a1c3ec42b594b547e8d48734b4aab188f 100644 (file)
@@ -27,7 +27,6 @@
 struct i915_params i915 __read_mostly = {
        .modeset = -1,
        .panel_ignore_lid = 1,
-       .powersave = 1,
        .semaphores = -1,
        .lvds_downclock = 0,
        .lvds_channel_mode = 0,
@@ -44,6 +43,7 @@ struct i915_params i915 __read_mostly = {
        .enable_ips = 1,
        .fastboot = 0,
        .prefault_disable = 0,
+       .load_detect_test = 0,
        .reset = true,
        .invert_brightness = 0,
        .disable_display = 0,
@@ -65,10 +65,6 @@ MODULE_PARM_DESC(panel_ignore_lid,
        "Override lid status (0=autodetect, 1=autodetect disabled [default], "
        "-1=force lid closed, -2=force lid open)");
 
-module_param_named(powersave, i915.powersave, int, 0600);
-MODULE_PARM_DESC(powersave,
-       "Enable powersavings, fbc, downclocking, etc. (default: true)");
-
 module_param_named_unsafe(semaphores, i915.semaphores, int, 0400);
 MODULE_PARM_DESC(semaphores,
        "Use semaphores for inter-ring sync "
@@ -144,11 +140,16 @@ module_param_named(fastboot, i915.fastboot, bool, 0600);
 MODULE_PARM_DESC(fastboot,
        "Try to skip unnecessary mode sets at boot time (default: false)");
 
-module_param_named(prefault_disable, i915.prefault_disable, bool, 0600);
+module_param_named_unsafe(prefault_disable, i915.prefault_disable, bool, 0600);
 MODULE_PARM_DESC(prefault_disable,
        "Disable page prefaulting for pread/pwrite/reloc (default:false). "
        "For developers only.");
 
+module_param_named_unsafe(load_detect_test, i915.load_detect_test, bool, 0600);
+MODULE_PARM_DESC(load_detect_test,
+       "Force-enable the VGA load detect code for testing (default:false). "
+       "For developers only.");
+
 module_param_named(invert_brightness, i915.invert_brightness, int, 0600);
 MODULE_PARM_DESC(invert_brightness,
        "Invert backlight brightness "
@@ -171,10 +172,10 @@ module_param_named(use_mmio_flip, i915.use_mmio_flip, int, 0600);
 MODULE_PARM_DESC(use_mmio_flip,
                 "use MMIO flips (-1=never, 0=driver discretion [default], 1=always)");
 
-module_param_named(mmio_debug, i915.mmio_debug, bool, 0600);
+module_param_named(mmio_debug, i915.mmio_debug, int, 0600);
 MODULE_PARM_DESC(mmio_debug,
-       "Enable the MMIO debug code (default: false). This may negatively "
-       "affect performance.");
+       "Enable the MMIO debug code for the first N failures (default: off). "
+       "This may negatively affect performance.");
 
 module_param_named(verbose_state_checks, i915.verbose_state_checks, bool, 0600);
 MODULE_PARM_DESC(verbose_state_checks,
index 33b3d0a24071af0a4a59b50c1ad1c2fd195ee505..b522eb6e59a486d2305aec3f2a7982473f322753 100644 (file)
 #define GEN8_RING_PDP_UDW(ring, n)     ((ring)->mmio_base+0x270 + ((n) * 8 + 4))
 #define GEN8_RING_PDP_LDW(ring, n)     ((ring)->mmio_base+0x270 + (n) * 8)
 
+#define GEN8_R_PWR_CLK_STATE           0x20C8
+#define   GEN8_RPCS_ENABLE             (1 << 31)
+#define   GEN8_RPCS_S_CNT_ENABLE       (1 << 18)
+#define   GEN8_RPCS_S_CNT_SHIFT                15
+#define   GEN8_RPCS_S_CNT_MASK         (0x7 << GEN8_RPCS_S_CNT_SHIFT)
+#define   GEN8_RPCS_SS_CNT_ENABLE      (1 << 11)
+#define   GEN8_RPCS_SS_CNT_SHIFT       8
+#define   GEN8_RPCS_SS_CNT_MASK                (0x7 << GEN8_RPCS_SS_CNT_SHIFT)
+#define   GEN8_RPCS_EU_MAX_SHIFT       4
+#define   GEN8_RPCS_EU_MAX_MASK                (0xf << GEN8_RPCS_EU_MAX_SHIFT)
+#define   GEN8_RPCS_EU_MIN_SHIFT       0
+#define   GEN8_RPCS_EU_MIN_MASK                (0xf << GEN8_RPCS_EU_MIN_SHIFT)
+
 #define GAM_ECOCHK                     0x4090
+#define   BDW_DISABLE_HDC_INVALIDATION (1<<25)
 #define   ECOCHK_SNB_BIT               (1<<10)
 #define   HSW_ECOCHK_ARB_PRIO_SOL      (1<<6)
 #define   ECOCHK_PPGTT_CACHE64B                (0x3<<3)
 #define   DSPFREQSTAT_MASK                     (0x3 << DSPFREQSTAT_SHIFT)
 #define   DSPFREQGUAR_SHIFT                    14
 #define   DSPFREQGUAR_MASK                     (0x3 << DSPFREQGUAR_SHIFT)
+#define   DSP_MAXFIFO_PM5_STATUS               (1 << 22) /* chv */
+#define   DSP_AUTO_CDCLK_GATE_DISABLE          (1 << 7) /* chv */
+#define   DSP_MAXFIFO_PM5_ENABLE               (1 << 6) /* chv */
 #define   _DP_SSC(val, pipe)                   ((val) << (2 * (pipe)))
 #define   DP_SSC_MASK(pipe)                    _DP_SSC(0x3, (pipe))
 #define   DP_SSC_PWR_ON(pipe)                  _DP_SSC(0x0, (pipe))
@@ -586,6 +603,19 @@ enum punit_power_well {
        PUNIT_POWER_WELL_NUM,
 };
 
+enum skl_disp_power_wells {
+       SKL_DISP_PW_MISC_IO,
+       SKL_DISP_PW_DDI_A_E,
+       SKL_DISP_PW_DDI_B,
+       SKL_DISP_PW_DDI_C,
+       SKL_DISP_PW_DDI_D,
+       SKL_DISP_PW_1 = 14,
+       SKL_DISP_PW_2,
+};
+
+#define SKL_POWER_WELL_STATE(pw) (1 << ((pw) * 2))
+#define SKL_POWER_WELL_REQ(pw) (1 << (((pw) * 2) + 1))
+
 #define PUNIT_REG_PWRGT_CTRL                   0x60
 #define PUNIT_REG_PWRGT_STATUS                 0x61
 #define   PUNIT_PWRGT_MASK(power_well)         (3 << ((power_well) * 2))
@@ -614,6 +644,11 @@ enum punit_power_well {
 #define FB_GFX_FMIN_AT_VMIN_FUSE               0x137
 #define FB_GFX_FMIN_AT_VMIN_FUSE_SHIFT         8
 
+#define PUNIT_REG_DDR_SETUP2                   0x139
+#define   FORCE_DDR_FREQ_REQ_ACK               (1 << 8)
+#define   FORCE_DDR_LOW_FREQ                   (1 << 1)
+#define   FORCE_DDR_HIGH_FREQ                  (1 << 0)
+
 #define PUNIT_GPU_STATUS_REG                   0xdb
 #define PUNIT_GPU_STATUS_MAX_FREQ_SHIFT        16
 #define PUNIT_GPU_STATUS_MAX_FREQ_MASK         0xff
@@ -638,7 +673,6 @@ enum punit_power_well {
 #define VLV_CZ_CLOCK_TO_MILLI_SEC              100000
 #define VLV_RP_UP_EI_THRESHOLD                 90
 #define VLV_RP_DOWN_EI_THRESHOLD               70
-#define VLV_INT_COUNT_FOR_DOWN_EI              5
 
 /* vlv2 north clock has */
 #define CCK_FUSE_REG                           0x8
@@ -1002,6 +1036,7 @@ enum punit_power_well {
 #define  DPIO_CHV_FIRST_MOD            (0 << 8)
 #define  DPIO_CHV_SECOND_MOD           (1 << 8)
 #define  DPIO_CHV_FEEDFWD_GAIN_SHIFT   0
+#define  DPIO_CHV_FEEDFWD_GAIN_MASK            (0xF << 0)
 #define CHV_PLL_DW3(ch) _PIPE(ch, _CHV_PLL_DW3_CH0, _CHV_PLL_DW3_CH1)
 
 #define _CHV_PLL_DW6_CH0               0x8018
@@ -1011,6 +1046,19 @@ enum punit_power_well {
 #define   DPIO_CHV_PROP_COEFF_SHIFT    0
 #define CHV_PLL_DW6(ch) _PIPE(ch, _CHV_PLL_DW6_CH0, _CHV_PLL_DW6_CH1)
 
+#define _CHV_PLL_DW8_CH0               0x8020
+#define _CHV_PLL_DW8_CH1               0x81A0
+#define   DPIO_CHV_TDC_TARGET_CNT_SHIFT 0
+#define   DPIO_CHV_TDC_TARGET_CNT_MASK  (0x3FF << 0)
+#define CHV_PLL_DW8(ch) _PIPE(ch, _CHV_PLL_DW8_CH0, _CHV_PLL_DW8_CH1)
+
+#define _CHV_PLL_DW9_CH0               0x8024
+#define _CHV_PLL_DW9_CH1               0x81A4
+#define  DPIO_CHV_INT_LOCK_THRESHOLD_SHIFT             1 /* 3 bits */
+#define  DPIO_CHV_INT_LOCK_THRESHOLD_MASK              (7 << 1)
+#define  DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE        1 /* 1: coarse & 0 : fine  */
+#define CHV_PLL_DW9(ch) _PIPE(ch, _CHV_PLL_DW9_CH0, _CHV_PLL_DW9_CH1)
+
 #define _CHV_CMN_DW5_CH0               0x8114
 #define   CHV_BUFRIGHTENA1_DISABLE     (0 << 20)
 #define   CHV_BUFRIGHTENA1_NORMAL      (1 << 20)
@@ -1258,6 +1306,9 @@ enum punit_power_well {
 #define   ERR_INT_FIFO_UNDERRUN_A      (1<<0)
 #define   ERR_INT_FIFO_UNDERRUN(pipe)  (1<<(pipe*3))
 
+#define GEN8_FAULT_TLB_DATA0           0x04b10
+#define GEN8_FAULT_TLB_DATA1           0x04b14
+
 #define FPGA_DBG               0x42300
 #define   FPGA_DBG_RM_NOCLAIM  (1<<31)
 
@@ -1314,6 +1365,8 @@ enum punit_power_well {
 #define   GEN6_WIZ_HASHING_16x4                                GEN6_WIZ_HASHING(1, 0)
 #define   GEN6_WIZ_HASHING_MASK                                GEN6_WIZ_HASHING(1, 1)
 #define   GEN6_TD_FOUR_ROW_DISPATCH_DISABLE            (1 << 5)
+#define   GEN9_IZ_HASHING_MASK(slice)                  (0x3 << (slice * 2))
+#define   GEN9_IZ_HASHING(slice, val)                  ((val) << (slice * 2))
 
 #define GFX_MODE       0x02520
 #define GFX_MODE_GEN7  0x0229c
@@ -1470,6 +1523,7 @@ enum punit_power_well {
 #define CACHE_MODE_1           0x7004 /* IVB+ */
 #define   PIXEL_SUBSPAN_COLLECT_OPT_DISABLE    (1<<6)
 #define   GEN8_4x4_STC_OPTIMIZATION_DISABLE    (1<<6)
+#define   GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE   (1<<1)
 
 #define GEN6_BLITTER_ECOSKPD   0x221d0
 #define   GEN6_BLITTER_LOCK_SHIFT                      16
@@ -1482,6 +1536,8 @@ enum punit_power_well {
 
 /* Fuse readout registers for GT */
 #define CHV_FUSE_GT                    (VLV_DISPLAY_BASE + 0x2168)
+#define   CHV_FGT_DISABLE_SS0          (1 << 10)
+#define   CHV_FGT_DISABLE_SS1          (1 << 11)
 #define   CHV_FGT_EU_DIS_SS0_R0_SHIFT  16
 #define   CHV_FGT_EU_DIS_SS0_R0_MASK   (0xf << CHV_FGT_EU_DIS_SS0_R0_SHIFT)
 #define   CHV_FGT_EU_DIS_SS0_R1_SHIFT  20
@@ -1491,6 +1547,17 @@ enum punit_power_well {
 #define   CHV_FGT_EU_DIS_SS1_R1_SHIFT  28
 #define   CHV_FGT_EU_DIS_SS1_R1_MASK   (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT)
 
+#define GEN8_FUSE2                     0x9120
+#define   GEN8_F2_S_ENA_SHIFT          25
+#define   GEN8_F2_S_ENA_MASK           (0x7 << GEN8_F2_S_ENA_SHIFT)
+
+#define   GEN9_F2_SS_DIS_SHIFT         20
+#define   GEN9_F2_SS_DIS_MASK          (0xf << GEN9_F2_SS_DIS_SHIFT)
+
+#define GEN8_EU_DISABLE0               0x9134
+#define GEN8_EU_DISABLE1               0x9138
+#define GEN8_EU_DISABLE2               0x913c
+
 #define GEN6_BSD_SLEEP_PSMI_CONTROL    0x12050
 #define   GEN6_BSD_SLEEP_MSG_DISABLE   (1 << 0)
 #define   GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2)
@@ -2048,6 +2115,14 @@ enum punit_power_well {
 #define   CDCLK_FREQ_SHIFT     4
 #define   CDCLK_FREQ_MASK      (0x1f << CDCLK_FREQ_SHIFT)
 #define   CZCLK_FREQ_MASK      0xf
+
+#define GCI_CONTROL            (VLV_DISPLAY_BASE + 0x650C)
+#define   PFI_CREDIT_63                (9 << 28)               /* chv only */
+#define   PFI_CREDIT_31                (8 << 28)               /* chv only */
+#define   PFI_CREDIT(x)                (((x) - 8) << 28)       /* 8-15 */
+#define   PFI_CREDIT_RESEND    (1 << 27)
+#define   VGA_FAST_MODE_DISABLE        (1 << 14)
+
 #define GMBUSFREQ_VLV          (VLV_DISPLAY_BASE + 0x6510)
 
 /*
@@ -2376,6 +2451,12 @@ enum punit_power_well {
 #define GEN6_RP_STATE_LIMITS   (MCHBAR_MIRROR_BASE_SNB + 0x5994)
 #define GEN6_RP_STATE_CAP      (MCHBAR_MIRROR_BASE_SNB + 0x5998)
 
+#define INTERVAL_1_28_US(us)   (((us) * 100) >> 7)
+#define INTERVAL_1_33_US(us)   (((us) * 3)   >> 2)
+#define GT_INTERVAL_FROM_US(dev_priv, us) (IS_GEN9(dev_priv) ? \
+                               INTERVAL_1_33_US(us) : \
+                               INTERVAL_1_28_US(us))
+
 /*
  * Logical Context regs
  */
@@ -2968,7 +3049,7 @@ enum punit_power_well {
 
 /* Video Data Island Packet control */
 #define VIDEO_DIP_DATA         0x61178
-/* Read the description of VIDEO_DIP_DATA (before Haswel) or VIDEO_DIP_ECC
+/* Read the description of VIDEO_DIP_DATA (before Haswell) or VIDEO_DIP_ECC
  * (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte
  * of the infoframe structure specified by CEA-861. */
 #define   VIDEO_DIP_DATA_SIZE  32
@@ -3865,6 +3946,7 @@ enum punit_power_well {
 #define   PIPECONF_INTERLACE_MODE_MASK         (7 << 21)
 #define   PIPECONF_EDP_RR_MODE_SWITCH          (1 << 20)
 #define   PIPECONF_CXSR_DOWNCLOCK      (1<<16)
+#define   PIPECONF_EDP_RR_MODE_SWITCH_VLV      (1 << 14)
 #define   PIPECONF_COLOR_RANGE_SELECT  (1 << 13)
 #define   PIPECONF_BPC_MASK    (0x7 << 5)
 #define   PIPECONF_8BPC                (0<<5)
@@ -4013,7 +4095,7 @@ enum punit_power_well {
 #define   DPINVGTT_STATUS_MASK                 0xff
 #define   DPINVGTT_STATUS_MASK_CHV             0xfff
 
-#define DSPARB                 0x70030
+#define DSPARB                 (dev_priv->info.display_mmio_offset + 0x70030)
 #define   DSPARB_CSTART_MASK   (0x7f << 7)
 #define   DSPARB_CSTART_SHIFT  7
 #define   DSPARB_BSTART_MASK   (0x7f)
@@ -4021,6 +4103,9 @@ enum punit_power_well {
 #define   DSPARB_BEND_SHIFT    9 /* on 855 */
 #define   DSPARB_AEND_SHIFT    0
 
+#define DSPARB2                        (VLV_DISPLAY_BASE + 0x70060) /* vlv/chv */
+#define DSPARB3                        (VLV_DISPLAY_BASE + 0x7006c) /* chv */
+
 /* pnv/gen4/g4x/vlv/chv */
 #define DSPFW1                 (dev_priv->info.display_mmio_offset + 0x70034)
 #define   DSPFW_SR_SHIFT               23
@@ -4044,8 +4129,8 @@ enum punit_power_well {
 #define   DSPFW_SPRITEB_MASK_VLV       (0xff<<16) /* vlv/chv */
 #define   DSPFW_CURSORA_SHIFT          8
 #define   DSPFW_CURSORA_MASK           (0x3f<<8)
-#define   DSPFW_PLANEC_SHIFT_OLD       0
-#define   DSPFW_PLANEC_MASK_OLD                (0x7f<<0) /* pre-gen4 sprite C */
+#define   DSPFW_PLANEC_OLD_SHIFT       0
+#define   DSPFW_PLANEC_OLD_MASK                (0x7f<<0) /* pre-gen4 sprite C */
 #define   DSPFW_SPRITEA_SHIFT          0
 #define   DSPFW_SPRITEA_MASK           (0x7f<<0) /* g4x */
 #define   DSPFW_SPRITEA_MASK_VLV       (0xff<<0) /* vlv/chv */
@@ -4084,25 +4169,25 @@ enum punit_power_well {
 #define   DSPFW_SPRITED_WM1_SHIFT      24
 #define   DSPFW_SPRITED_WM1_MASK       (0xff<<24)
 #define   DSPFW_SPRITED_SHIFT          16
-#define   DSPFW_SPRITED_MASK           (0xff<<16)
+#define   DSPFW_SPRITED_MASK_VLV       (0xff<<16)
 #define   DSPFW_SPRITEC_WM1_SHIFT      8
 #define   DSPFW_SPRITEC_WM1_MASK       (0xff<<8)
 #define   DSPFW_SPRITEC_SHIFT          0
-#define   DSPFW_SPRITEC_MASK           (0xff<<0)
+#define   DSPFW_SPRITEC_MASK_VLV       (0xff<<0)
 #define DSPFW8_CHV             (VLV_DISPLAY_BASE + 0x700b8)
 #define   DSPFW_SPRITEF_WM1_SHIFT      24
 #define   DSPFW_SPRITEF_WM1_MASK       (0xff<<24)
 #define   DSPFW_SPRITEF_SHIFT          16
-#define   DSPFW_SPRITEF_MASK           (0xff<<16)
+#define   DSPFW_SPRITEF_MASK_VLV       (0xff<<16)
 #define   DSPFW_SPRITEE_WM1_SHIFT      8
 #define   DSPFW_SPRITEE_WM1_MASK       (0xff<<8)
 #define   DSPFW_SPRITEE_SHIFT          0
-#define   DSPFW_SPRITEE_MASK           (0xff<<0)
+#define   DSPFW_SPRITEE_MASK_VLV       (0xff<<0)
 #define DSPFW9_CHV             (VLV_DISPLAY_BASE + 0x7007c) /* wtf #2? */
 #define   DSPFW_PLANEC_WM1_SHIFT       24
 #define   DSPFW_PLANEC_WM1_MASK                (0xff<<24)
 #define   DSPFW_PLANEC_SHIFT           16
-#define   DSPFW_PLANEC_MASK            (0xff<<16)
+#define   DSPFW_PLANEC_MASK_VLV                (0xff<<16)
 #define   DSPFW_CURSORC_WM1_SHIFT      8
 #define   DSPFW_CURSORC_WM1_MASK       (0x3f<<16)
 #define   DSPFW_CURSORC_SHIFT          0
@@ -4111,7 +4196,7 @@ enum punit_power_well {
 /* vlv/chv high order bits */
 #define DSPHOWM                        (VLV_DISPLAY_BASE + 0x70064)
 #define   DSPFW_SR_HI_SHIFT            24
-#define   DSPFW_SR_HI_MASK             (1<<24)
+#define   DSPFW_SR_HI_MASK             (3<<24) /* 2 bits for chv, 1 for vlv */
 #define   DSPFW_SPRITEF_HI_SHIFT       23
 #define   DSPFW_SPRITEF_HI_MASK                (1<<23)
 #define   DSPFW_SPRITEE_HI_SHIFT       22
@@ -4132,7 +4217,7 @@ enum punit_power_well {
 #define   DSPFW_PLANEA_HI_MASK         (1<<0)
 #define DSPHOWM1               (VLV_DISPLAY_BASE + 0x70068)
 #define   DSPFW_SR_WM1_HI_SHIFT                24
-#define   DSPFW_SR_WM1_HI_MASK         (1<<24)
+#define   DSPFW_SR_WM1_HI_MASK         (3<<24) /* 2 bits for chv, 1 for vlv */
 #define   DSPFW_SPRITEF_WM1_HI_SHIFT   23
 #define   DSPFW_SPRITEF_WM1_HI_MASK    (1<<23)
 #define   DSPFW_SPRITEE_WM1_HI_SHIFT   22
@@ -4153,21 +4238,17 @@ enum punit_power_well {
 #define   DSPFW_PLANEA_WM1_HI_MASK     (1<<0)
 
 /* drain latency register values*/
-#define DRAIN_LATENCY_PRECISION_16     16
-#define DRAIN_LATENCY_PRECISION_32     32
-#define DRAIN_LATENCY_PRECISION_64     64
 #define VLV_DDL(pipe)                  (VLV_DISPLAY_BASE + 0x70050 + 4 * (pipe))
-#define DDL_CURSOR_PRECISION_HIGH      (1<<31)
-#define DDL_CURSOR_PRECISION_LOW       (0<<31)
 #define DDL_CURSOR_SHIFT               24
-#define DDL_SPRITE_PRECISION_HIGH(sprite)      (1<<(15+8*(sprite)))
-#define DDL_SPRITE_PRECISION_LOW(sprite)       (0<<(15+8*(sprite)))
 #define DDL_SPRITE_SHIFT(sprite)       (8+8*(sprite))
-#define DDL_PLANE_PRECISION_HIGH       (1<<7)
-#define DDL_PLANE_PRECISION_LOW                (0<<7)
 #define DDL_PLANE_SHIFT                        0
+#define DDL_PRECISION_HIGH             (1<<7)
+#define DDL_PRECISION_LOW              (0<<7)
 #define DRAIN_LATENCY_MASK             0x7f
 
+#define CBR1_VLV                       (VLV_DISPLAY_BASE + 0x70400)
+#define  CBR_PND_DEADLINE_DISABLE      (1<<31)
+
 /* FIFO watermark sizes etc */
 #define G4X_FIFO_LINE_SIZE     64
 #define I915_FIFO_LINE_SIZE    64
@@ -5221,14 +5302,22 @@ enum punit_power_well {
 #define HSW_NDE_RSTWRN_OPT     0x46408
 #define  RESET_PCH_HANDSHAKE_ENABLE    (1<<4)
 
+#define FF_SLICE_CS_CHICKEN2                   0x02e4
+#define  GEN9_TSG_BARRIER_ACK_DISABLE          (1<<8)
+
 /* GEN7 chicken */
 #define GEN7_COMMON_SLICE_CHICKEN1             0x7010
 # define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC     ((1<<10) | (1<<26))
+# define GEN9_RHWO_OPTIMIZATION_DISABLE                (1<<14)
 #define COMMON_SLICE_CHICKEN2                  0x7014
 # define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE  (1<<0)
 
-#define HIZ_CHICKEN                            0x7018
-# define CHV_HZ_8X8_MODE_IN_1X                 (1<<15)
+#define HIZ_CHICKEN                                    0x7018
+# define CHV_HZ_8X8_MODE_IN_1X                         (1<<15)
+# define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE   (1<<3)
+
+#define GEN9_SLICE_COMMON_ECO_CHICKEN0         0x7308
+#define  DISABLE_PIXEL_MASK_CAMMING            (1<<14)
 
 #define GEN7_L3SQCREG1                         0xB010
 #define  VLV_B0_WA_L3SQCREG1_VALUE             0x00D30000
@@ -5245,11 +5334,16 @@ enum punit_power_well {
 #define GEN7_L3SQCREG4                         0xb034
 #define  L3SQ_URB_READ_CAM_MATCH_DISABLE       (1<<27)
 
+#define GEN8_L3SQCREG4                         0xb118
+#define  GEN8_LQSC_RO_PERF_DIS                 (1<<27)
+
 /* GEN8 chicken */
 #define HDC_CHICKEN0                           0x7300
-#define  HDC_FORCE_NON_COHERENT                        (1<<4)
-#define  HDC_DONOT_FETCH_MEM_WHEN_MASKED       (1<<11)
 #define  HDC_FENCE_DEST_SLM_DISABLE            (1<<14)
+#define  HDC_DONOT_FETCH_MEM_WHEN_MASKED       (1<<11)
+#define  HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT   (1<<5)
+#define  HDC_FORCE_NON_COHERENT                        (1<<4)
+#define  HDC_BARRIER_PERFORMANCE_DISABLE       (1<<10)
 
 /* WaCatErrorRejectionIssue */
 #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG         0x9030
@@ -5258,6 +5352,9 @@ enum punit_power_well {
 #define HSW_SCRATCH1                           0xb038
 #define  HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE  (1<<27)
 
+#define BDW_SCRATCH1                                   0xb11c
+#define  GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE     (1<<2)
+
 /* PCH */
 
 /* south display engine interrupt: IBX */
@@ -5980,6 +6077,7 @@ enum punit_power_well {
 #define  HSW_IDICR                             0x9008
 #define    IDIHASHMSK(x)                       (((x) & 0x3f) << 16)
 #define  HSW_EDRAM_PRESENT                     0x120010
+#define    EDRAM_ENABLED                       0x1
 
 #define GEN6_UCGCTL1                           0x9400
 # define GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE             (1 << 16)
@@ -6003,6 +6101,7 @@ enum punit_power_well {
 #define GEN6_RSTCTL                            0x9420
 
 #define GEN8_UCGCTL6                           0x9430
+#define   GEN8_GAPSUNIT_CLOCK_GATE_DISABLE     (1<<24)
 #define   GEN8_SDEUNIT_CLOCK_GATE_DISABLE      (1<<14)
 
 #define GEN6_GFXPAUSE                          0xA000
@@ -6010,6 +6109,7 @@ enum punit_power_well {
 #define   GEN6_TURBO_DISABLE                   (1<<31)
 #define   GEN6_FREQUENCY(x)                    ((x)<<25)
 #define   HSW_FREQUENCY(x)                     ((x)<<24)
+#define   GEN9_FREQUENCY(x)                    ((x)<<23)
 #define   GEN6_OFFSET(x)                       ((x)<<19)
 #define   GEN6_AGGRESSIVE_TURBO                        (0<<15)
 #define GEN6_RC_VIDEO_FREQ                     0xA00C
@@ -6028,8 +6128,10 @@ enum punit_power_well {
 #define GEN6_RPSTAT1                           0xA01C
 #define   GEN6_CAGF_SHIFT                      8
 #define   HSW_CAGF_SHIFT                       7
+#define   GEN9_CAGF_SHIFT                      23
 #define   GEN6_CAGF_MASK                       (0x7f << GEN6_CAGF_SHIFT)
 #define   HSW_CAGF_MASK                                (0x7f << HSW_CAGF_SHIFT)
+#define   GEN9_CAGF_MASK                       (0x1ff << GEN9_CAGF_SHIFT)
 #define GEN6_RP_CONTROL                                0xA024
 #define   GEN6_RP_MEDIA_TURBO                  (1<<11)
 #define   GEN6_RP_MEDIA_MODE_MASK              (3<<9)
@@ -6120,8 +6222,8 @@ enum punit_power_well {
 
 #define GEN6_GT_GFX_RC6p                       0x13810C
 #define GEN6_GT_GFX_RC6pp                      0x138110
-#define VLV_RENDER_C0_COUNT_REG                0x138118
-#define VLV_MEDIA_C0_COUNT_REG                 0x13811C
+#define VLV_RENDER_C0_COUNT                    0x138118
+#define VLV_MEDIA_C0_COUNT                     0x13811C
 
 #define GEN6_PCODE_MAILBOX                     0x138124
 #define   GEN6_PCODE_READY                     (1<<31)
@@ -6155,6 +6257,37 @@ enum punit_power_well {
 #define   GEN6_RC6                     3
 #define   GEN6_RC7                     4
 
+#define CHV_POWER_SS0_SIG1             0xa720
+#define CHV_POWER_SS1_SIG1             0xa728
+#define   CHV_SS_PG_ENABLE             (1<<1)
+#define   CHV_EU08_PG_ENABLE           (1<<9)
+#define   CHV_EU19_PG_ENABLE           (1<<17)
+#define   CHV_EU210_PG_ENABLE          (1<<25)
+
+#define CHV_POWER_SS0_SIG2             0xa724
+#define CHV_POWER_SS1_SIG2             0xa72c
+#define   CHV_EU311_PG_ENABLE          (1<<1)
+
+#define GEN9_SLICE0_PGCTL_ACK          0x804c
+#define GEN9_SLICE1_PGCTL_ACK          0x8050
+#define GEN9_SLICE2_PGCTL_ACK          0x8054
+#define   GEN9_PGCTL_SLICE_ACK         (1 << 0)
+
+#define GEN9_SLICE0_SS01_EU_PGCTL_ACK  0x805c
+#define GEN9_SLICE0_SS23_EU_PGCTL_ACK  0x8060
+#define GEN9_SLICE1_SS01_EU_PGCTL_ACK  0x8064
+#define GEN9_SLICE1_SS23_EU_PGCTL_ACK  0x8068
+#define GEN9_SLICE2_SS01_EU_PGCTL_ACK  0x806c
+#define GEN9_SLICE2_SS23_EU_PGCTL_ACK  0x8070
+#define   GEN9_PGCTL_SSA_EU08_ACK      (1 << 0)
+#define   GEN9_PGCTL_SSA_EU19_ACK      (1 << 2)
+#define   GEN9_PGCTL_SSA_EU210_ACK     (1 << 4)
+#define   GEN9_PGCTL_SSA_EU311_ACK     (1 << 6)
+#define   GEN9_PGCTL_SSB_EU08_ACK      (1 << 8)
+#define   GEN9_PGCTL_SSB_EU19_ACK      (1 << 10)
+#define   GEN9_PGCTL_SSB_EU210_ACK     (1 << 12)
+#define   GEN9_PGCTL_SSB_EU311_ACK     (1 << 14)
+
 #define GEN7_MISCCPCTL                 (0x9424)
 #define   GEN7_DOP_CLOCK_GATE_ENABLE   (1<<0)
 
@@ -6185,6 +6318,7 @@ enum punit_power_well {
 
 #define GEN9_HALF_SLICE_CHICKEN5       0xe188
 #define   GEN9_DG_MIRROR_FIX_ENABLE    (1<<5)
+#define   GEN9_CCS_TLB_PREFETCH_ENABLE (1<<3)
 
 #define GEN8_ROW_CHICKEN               0xe4f0
 #define   PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE        (1<<8)
@@ -6200,8 +6334,12 @@ enum punit_power_well {
 #define HALF_SLICE_CHICKEN3            0xe184
 #define   HSW_SAMPLE_C_PERFORMANCE     (1<<9)
 #define   GEN8_CENTROID_PIXEL_OPT_DIS  (1<<8)
+#define   GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC  (1<<5)
 #define   GEN8_SAMPLER_POWER_BYPASS_DIS        (1<<1)
 
+#define GEN9_HALF_SLICE_CHICKEN7       0xe194
+#define   GEN9_ENABLE_YV12_BUGFIX      (1<<4)
+
 /* Audio */
 #define G4X_AUD_VID_DID                        (dev_priv->info.display_mmio_offset + 0x62020)
 #define   INTEL_AUDIO_DEVCL            0x808629FB
@@ -6351,6 +6489,13 @@ enum punit_power_well {
 #define   HSW_PWR_WELL_FORCE_ON                        (1<<19)
 #define HSW_PWR_WELL_CTL6                      0x45414
 
+/* SKL Fuse Status */
+#define SKL_FUSE_STATUS                                0x42000
+#define  SKL_FUSE_DOWNLOAD_STATUS              (1<<31)
+#define  SKL_FUSE_PG0_DIST_STATUS              (1<<27)
+#define  SKL_FUSE_PG1_DIST_STATUS              (1<<26)
+#define  SKL_FUSE_PG2_DIST_STATUS              (1<<25)
+
 /* Per-pipe DDI Function Control */
 #define TRANS_DDI_FUNC_CTL_A           0x60400
 #define TRANS_DDI_FUNC_CTL_B           0x61400
index 9f19ed38cdc346e9731996461b18801b63f9b7ea..cf67f82f7b7fc18ecb392c9ae26b0da3d36e97a3 100644 (file)
 #include "intel_drv.h"
 #include "i915_reg.h"
 
-static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       I915_WRITE8(index_port, reg);
-       return I915_READ8(data_port);
-}
-
-static u8 i915_read_ar(struct drm_device *dev, u16 st01, u8 reg, u16 palette_enable)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       I915_READ8(st01);
-       I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
-       return I915_READ8(VGA_AR_DATA_READ);
-}
-
-static void i915_write_ar(struct drm_device *dev, u16 st01, u8 reg, u8 val, u16 palette_enable)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       I915_READ8(st01);
-       I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
-       I915_WRITE8(VGA_AR_DATA_WRITE, val);
-}
-
-static void i915_write_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg, u8 val)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       I915_WRITE8(index_port, reg);
-       I915_WRITE8(data_port, val);
-}
-
-static void i915_save_vga(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-       u16 cr_index, cr_data, st01;
-
-       /* VGA state */
-       dev_priv->regfile.saveVGA0 = I915_READ(VGA0);
-       dev_priv->regfile.saveVGA1 = I915_READ(VGA1);
-       dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD);
-       dev_priv->regfile.saveVGACNTRL = I915_READ(i915_vgacntrl_reg(dev));
-
-       /* VGA color palette registers */
-       dev_priv->regfile.saveDACMASK = I915_READ8(VGA_DACMASK);
-
-       /* MSR bits */
-       dev_priv->regfile.saveMSR = I915_READ8(VGA_MSR_READ);
-       if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) {
-               cr_index = VGA_CR_INDEX_CGA;
-               cr_data = VGA_CR_DATA_CGA;
-               st01 = VGA_ST01_CGA;
-       } else {
-               cr_index = VGA_CR_INDEX_MDA;
-               cr_data = VGA_CR_DATA_MDA;
-               st01 = VGA_ST01_MDA;
-       }
-
-       /* CRT controller regs */
-       i915_write_indexed(dev, cr_index, cr_data, 0x11,
-                          i915_read_indexed(dev, cr_index, cr_data, 0x11) &
-                          (~0x80));
-       for (i = 0; i <= 0x24; i++)
-               dev_priv->regfile.saveCR[i] =
-                       i915_read_indexed(dev, cr_index, cr_data, i);
-       /* Make sure we don't turn off CR group 0 writes */
-       dev_priv->regfile.saveCR[0x11] &= ~0x80;
-
-       /* Attribute controller registers */
-       I915_READ8(st01);
-       dev_priv->regfile.saveAR_INDEX = I915_READ8(VGA_AR_INDEX);
-       for (i = 0; i <= 0x14; i++)
-               dev_priv->regfile.saveAR[i] = i915_read_ar(dev, st01, i, 0);
-       I915_READ8(st01);
-       I915_WRITE8(VGA_AR_INDEX, dev_priv->regfile.saveAR_INDEX);
-       I915_READ8(st01);
-
-       /* Graphics controller registers */
-       for (i = 0; i < 9; i++)
-               dev_priv->regfile.saveGR[i] =
-                       i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i);
-
-       dev_priv->regfile.saveGR[0x10] =
-               i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10);
-       dev_priv->regfile.saveGR[0x11] =
-               i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11);
-       dev_priv->regfile.saveGR[0x18] =
-               i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18);
-
-       /* Sequencer registers */
-       for (i = 0; i < 8; i++)
-               dev_priv->regfile.saveSR[i] =
-                       i915_read_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i);
-}
-
-static void i915_restore_vga(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-       u16 cr_index, cr_data, st01;
-
-       /* VGA state */
-       I915_WRITE(i915_vgacntrl_reg(dev), dev_priv->regfile.saveVGACNTRL);
-
-       I915_WRITE(VGA0, dev_priv->regfile.saveVGA0);
-       I915_WRITE(VGA1, dev_priv->regfile.saveVGA1);
-       I915_WRITE(VGA_PD, dev_priv->regfile.saveVGA_PD);
-       POSTING_READ(VGA_PD);
-       udelay(150);
-
-       /* MSR bits */
-       I915_WRITE8(VGA_MSR_WRITE, dev_priv->regfile.saveMSR);
-       if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) {
-               cr_index = VGA_CR_INDEX_CGA;
-               cr_data = VGA_CR_DATA_CGA;
-               st01 = VGA_ST01_CGA;
-       } else {
-               cr_index = VGA_CR_INDEX_MDA;
-               cr_data = VGA_CR_DATA_MDA;
-               st01 = VGA_ST01_MDA;
-       }
-
-       /* Sequencer registers, don't write SR07 */
-       for (i = 0; i < 7; i++)
-               i915_write_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i,
-                                  dev_priv->regfile.saveSR[i]);
-
-       /* CRT controller regs */
-       /* Enable CR group 0 writes */
-       i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->regfile.saveCR[0x11]);
-       for (i = 0; i <= 0x24; i++)
-               i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->regfile.saveCR[i]);
-
-       /* Graphics controller regs */
-       for (i = 0; i < 9; i++)
-               i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i,
-                                  dev_priv->regfile.saveGR[i]);
-
-       i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10,
-                          dev_priv->regfile.saveGR[0x10]);
-       i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11,
-                          dev_priv->regfile.saveGR[0x11]);
-       i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18,
-                          dev_priv->regfile.saveGR[0x18]);
-
-       /* Attribute controller registers */
-       I915_READ8(st01); /* switch back to index mode */
-       for (i = 0; i <= 0x14; i++)
-               i915_write_ar(dev, st01, i, dev_priv->regfile.saveAR[i], 0);
-       I915_READ8(st01); /* switch back to index mode */
-       I915_WRITE8(VGA_AR_INDEX, dev_priv->regfile.saveAR_INDEX | 0x20);
-       I915_READ8(st01);
-
-       /* VGA color palette registers */
-       I915_WRITE8(VGA_DACMASK, dev_priv->regfile.saveDACMASK);
-}
-
 static void i915_save_display(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -197,11 +37,6 @@ static void i915_save_display(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen <= 4)
                dev_priv->regfile.saveDSPARB = I915_READ(DSPARB);
 
-       /* This is only meaningful in non-KMS mode */
-       /* Don't regfile.save them in KMS mode */
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               i915_save_display_reg(dev);
-
        /* LVDS state */
        if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
                dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS);
@@ -224,9 +59,6 @@ static void i915_save_display(struct drm_device *dev)
        /* save FBC interval */
        if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
                dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL);
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               i915_save_vga(dev);
 }
 
 static void i915_restore_display(struct drm_device *dev)
@@ -238,11 +70,7 @@ static void i915_restore_display(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen <= 4)
                I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB);
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               i915_restore_display_reg(dev);
-
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               mask = ~LVDS_PORT_EN;
+       mask = ~LVDS_PORT_EN;
 
        /* LVDS state */
        if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
@@ -270,10 +98,7 @@ static void i915_restore_display(struct drm_device *dev)
        if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
                I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL);
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               i915_restore_vga(dev);
-       else
-               i915_redisable_vga(dev);
+       i915_redisable_vga(dev);
 }
 
 int i915_save_state(struct drm_device *dev)
@@ -285,24 +110,6 @@ int i915_save_state(struct drm_device *dev)
 
        i915_save_display(dev);
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
-               /* Interrupt state */
-               if (HAS_PCH_SPLIT(dev)) {
-                       dev_priv->regfile.saveDEIER = I915_READ(DEIER);
-                       dev_priv->regfile.saveDEIMR = I915_READ(DEIMR);
-                       dev_priv->regfile.saveGTIER = I915_READ(GTIER);
-                       dev_priv->regfile.saveGTIMR = I915_READ(GTIMR);
-                       dev_priv->regfile.saveFDI_RXA_IMR = I915_READ(_FDI_RXA_IMR);
-                       dev_priv->regfile.saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR);
-                       dev_priv->regfile.saveMCHBAR_RENDER_STANDBY =
-                               I915_READ(RSTDBYCTL);
-                       dev_priv->regfile.savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG);
-               } else {
-                       dev_priv->regfile.saveIER = I915_READ(IER);
-                       dev_priv->regfile.saveIMR = I915_READ(IMR);
-               }
-       }
-
        if (IS_GEN4(dev))
                pci_read_config_word(dev->pdev, GCDGMBUS,
                                     &dev_priv->regfile.saveGCDGMBUS);
@@ -341,24 +148,6 @@ int i915_restore_state(struct drm_device *dev)
                                      dev_priv->regfile.saveGCDGMBUS);
        i915_restore_display(dev);
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
-               /* Interrupt state */
-               if (HAS_PCH_SPLIT(dev)) {
-                       I915_WRITE(DEIER, dev_priv->regfile.saveDEIER);
-                       I915_WRITE(DEIMR, dev_priv->regfile.saveDEIMR);
-                       I915_WRITE(GTIER, dev_priv->regfile.saveGTIER);
-                       I915_WRITE(GTIMR, dev_priv->regfile.saveGTIMR);
-                       I915_WRITE(_FDI_RXA_IMR, dev_priv->regfile.saveFDI_RXA_IMR);
-                       I915_WRITE(_FDI_RXB_IMR, dev_priv->regfile.saveFDI_RXB_IMR);
-                       I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->regfile.savePCH_PORT_HOTPLUG);
-                       I915_WRITE(RSTDBYCTL,
-                                  dev_priv->regfile.saveMCHBAR_RENDER_STANDBY);
-               } else {
-                       I915_WRITE(IER, dev_priv->regfile.saveIER);
-                       I915_WRITE(IMR, dev_priv->regfile.saveIMR);
-               }
-       }
-
        /* Cache mode state */
        if (INTEL_INFO(dev)->gen < 7)
                I915_WRITE(CACHE_MODE_0, dev_priv->regfile.saveCACHE_MODE_0 |
index 49f5ade0edb70ba4fab2cb227bb1c78fabcd94a8..247626885f49d22cfb94f6f89b1a459c4b0500a8 100644 (file)
@@ -127,10 +127,19 @@ show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf)
        return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency);
 }
 
+static ssize_t
+show_media_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf)
+{
+       struct drm_minor *dminor = dev_get_drvdata(kdev);
+       u32 rc6_residency = calc_residency(dminor->dev, VLV_GT_MEDIA_RC6);
+       return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency);
+}
+
 static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL);
 static DEVICE_ATTR(rc6_residency_ms, S_IRUGO, show_rc6_ms, NULL);
 static DEVICE_ATTR(rc6p_residency_ms, S_IRUGO, show_rc6p_ms, NULL);
 static DEVICE_ATTR(rc6pp_residency_ms, S_IRUGO, show_rc6pp_ms, NULL);
+static DEVICE_ATTR(media_rc6_residency_ms, S_IRUGO, show_media_rc6_ms, NULL);
 
 static struct attribute *rc6_attrs[] = {
        &dev_attr_rc6_enable.attr,
@@ -153,6 +162,16 @@ static struct attribute_group rc6p_attr_group = {
        .name = power_group_name,
        .attrs =  rc6p_attrs
 };
+
+static struct attribute *media_rc6_attrs[] = {
+       &dev_attr_media_rc6_residency_ms.attr,
+       NULL
+};
+
+static struct attribute_group media_rc6_attr_group = {
+       .name = power_group_name,
+       .attrs =  media_rc6_attrs
+};
 #endif
 
 static int l3_access_valid(struct drm_device *dev, loff_t offset)
@@ -300,7 +319,9 @@ static ssize_t gt_act_freq_mhz_show(struct device *kdev,
                ret = intel_gpu_freq(dev_priv, (freq >> 8) & 0xff);
        } else {
                u32 rpstat = I915_READ(GEN6_RPSTAT1);
-               if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+               if (IS_GEN9(dev_priv))
+                       ret = (rpstat & GEN9_CAGF_MASK) >> GEN9_CAGF_SHIFT;
+               else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
                        ret = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT;
                else
                        ret = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
@@ -402,10 +423,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
        /* We still need *_set_rps to process the new max_delay and
         * update the interrupt limits and PMINTRMSK even though
         * frequency request may be unchanged. */
-       if (IS_VALLEYVIEW(dev))
-               valleyview_set_rps(dev, val);
-       else
-               gen6_set_rps(dev, val);
+       intel_set_rps(dev, val);
 
        mutex_unlock(&dev_priv->rps.hw_lock);
 
@@ -464,10 +482,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
        /* We still need *_set_rps to process the new min_delay and
         * update the interrupt limits and PMINTRMSK even though
         * frequency request may be unchanged. */
-       if (IS_VALLEYVIEW(dev))
-               valleyview_set_rps(dev, val);
-       else
-               gen6_set_rps(dev, val);
+       intel_set_rps(dev, val);
 
        mutex_unlock(&dev_priv->rps.hw_lock);
 
@@ -493,38 +508,17 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr
        struct drm_minor *minor = dev_to_drm_minor(kdev);
        struct drm_device *dev = minor->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 val, rp_state_cap;
-       ssize_t ret;
-
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
-       if (ret)
-               return ret;
-       intel_runtime_pm_get(dev_priv);
-       rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
-       intel_runtime_pm_put(dev_priv);
-       mutex_unlock(&dev->struct_mutex);
+       u32 val;
 
-       if (attr == &dev_attr_gt_RP0_freq_mhz) {
-               if (IS_VALLEYVIEW(dev))
-                       val = intel_gpu_freq(dev_priv, dev_priv->rps.rp0_freq);
-               else
-                       val = intel_gpu_freq(dev_priv,
-                                            ((rp_state_cap & 0x0000ff) >> 0));
-       } else if (attr == &dev_attr_gt_RP1_freq_mhz) {
-               if (IS_VALLEYVIEW(dev))
-                       val = intel_gpu_freq(dev_priv, dev_priv->rps.rp1_freq);
-               else
-                       val = intel_gpu_freq(dev_priv,
-                                            ((rp_state_cap & 0x00ff00) >> 8));
-       } else if (attr == &dev_attr_gt_RPn_freq_mhz) {
-               if (IS_VALLEYVIEW(dev))
-                       val = intel_gpu_freq(dev_priv, dev_priv->rps.min_freq);
-               else
-                       val = intel_gpu_freq(dev_priv,
-                                            ((rp_state_cap & 0xff0000) >> 16));
-       } else {
+       if (attr == &dev_attr_gt_RP0_freq_mhz)
+               val = intel_gpu_freq(dev_priv, dev_priv->rps.rp0_freq);
+       else if (attr == &dev_attr_gt_RP1_freq_mhz)
+               val = intel_gpu_freq(dev_priv, dev_priv->rps.rp1_freq);
+       else if (attr == &dev_attr_gt_RPn_freq_mhz)
+               val = intel_gpu_freq(dev_priv, dev_priv->rps.min_freq);
+       else
                BUG();
-       }
+
        return snprintf(buf, PAGE_SIZE, "%d\n", val);
 }
 
@@ -633,6 +627,12 @@ void i915_setup_sysfs(struct drm_device *dev)
                if (ret)
                        DRM_ERROR("RC6p residency sysfs setup failed\n");
        }
+       if (IS_VALLEYVIEW(dev)) {
+               ret = sysfs_merge_group(&dev->primary->kdev->kobj,
+                                       &media_rc6_attr_group);
+               if (ret)
+                       DRM_ERROR("Media RC6 residency sysfs setup failed\n");
+       }
 #endif
        if (HAS_L3_DPF(dev)) {
                ret = device_create_bin_file(dev->primary->kdev, &dpf_attrs);
index 6058a01b444334472d7023661bb6a37b551dbf1c..b3070a4501ab59e3009758cb9ab624af8343a258 100644 (file)
@@ -115,7 +115,7 @@ TRACE_EVENT(i915_vma_bind,
            TP_STRUCT__entry(
                             __field(struct drm_i915_gem_object *, obj)
                             __field(struct i915_address_space *, vm)
-                            __field(u32, offset)
+                            __field(u64, offset)
                             __field(u32, size)
                             __field(unsigned, flags)
                             ),
@@ -128,7 +128,7 @@ TRACE_EVENT(i915_vma_bind,
                           __entry->flags = flags;
                           ),
 
-           TP_printk("obj=%p, offset=%08x size=%x%s vm=%p",
+           TP_printk("obj=%p, offset=%016llx size=%x%s vm=%p",
                      __entry->obj, __entry->offset, __entry->size,
                      __entry->flags & PIN_MAPPABLE ? ", mappable" : "",
                      __entry->vm)
@@ -141,7 +141,7 @@ TRACE_EVENT(i915_vma_unbind,
            TP_STRUCT__entry(
                             __field(struct drm_i915_gem_object *, obj)
                             __field(struct i915_address_space *, vm)
-                            __field(u32, offset)
+                            __field(u64, offset)
                             __field(u32, size)
                             ),
 
@@ -152,10 +152,109 @@ TRACE_EVENT(i915_vma_unbind,
                           __entry->size = vma->node.size;
                           ),
 
-           TP_printk("obj=%p, offset=%08x size=%x vm=%p",
+           TP_printk("obj=%p, offset=%016llx size=%x vm=%p",
                      __entry->obj, __entry->offset, __entry->size, __entry->vm)
 );
 
+#define VM_TO_TRACE_NAME(vm) \
+       (i915_is_ggtt(vm) ? "G" : \
+                     "P")
+
+DECLARE_EVENT_CLASS(i915_va,
+       TP_PROTO(struct i915_address_space *vm, u64 start, u64 length, const char *name),
+       TP_ARGS(vm, start, length, name),
+
+       TP_STRUCT__entry(
+               __field(struct i915_address_space *, vm)
+               __field(u64, start)
+               __field(u64, end)
+               __string(name, name)
+       ),
+
+       TP_fast_assign(
+               __entry->vm = vm;
+               __entry->start = start;
+               __entry->end = start + length - 1;
+               __assign_str(name, name);
+       ),
+
+       TP_printk("vm=%p (%s), 0x%llx-0x%llx",
+                 __entry->vm, __get_str(name),  __entry->start, __entry->end)
+);
+
+DEFINE_EVENT(i915_va, i915_va_alloc,
+            TP_PROTO(struct i915_address_space *vm, u64 start, u64 length, const char *name),
+            TP_ARGS(vm, start, length, name)
+);
+
+DECLARE_EVENT_CLASS(i915_page_table_entry,
+       TP_PROTO(struct i915_address_space *vm, u32 pde, u64 start, u64 pde_shift),
+       TP_ARGS(vm, pde, start, pde_shift),
+
+       TP_STRUCT__entry(
+               __field(struct i915_address_space *, vm)
+               __field(u32, pde)
+               __field(u64, start)
+               __field(u64, end)
+       ),
+
+       TP_fast_assign(
+               __entry->vm = vm;
+               __entry->pde = pde;
+               __entry->start = start;
+               __entry->end = ((start + (1ULL << pde_shift)) & ~((1ULL << pde_shift)-1)) - 1;
+       ),
+
+       TP_printk("vm=%p, pde=%d (0x%llx-0x%llx)",
+                 __entry->vm, __entry->pde, __entry->start, __entry->end)
+);
+
+DEFINE_EVENT(i915_page_table_entry, i915_page_table_entry_alloc,
+            TP_PROTO(struct i915_address_space *vm, u32 pde, u64 start, u64 pde_shift),
+            TP_ARGS(vm, pde, start, pde_shift)
+);
+
+/* Avoid extra math because we only support two sizes. The format is defined by
+ * bitmap_scnprintf. Each 32 bits is 8 HEX digits followed by comma */
+#define TRACE_PT_SIZE(bits) \
+       ((((bits) == 1024) ? 288 : 144) + 1)
+
+DECLARE_EVENT_CLASS(i915_page_table_entry_update,
+       TP_PROTO(struct i915_address_space *vm, u32 pde,
+                struct i915_page_table_entry *pt, u32 first, u32 count, u32 bits),
+       TP_ARGS(vm, pde, pt, first, count, bits),
+
+       TP_STRUCT__entry(
+               __field(struct i915_address_space *, vm)
+               __field(u32, pde)
+               __field(u32, first)
+               __field(u32, last)
+               __dynamic_array(char, cur_ptes, TRACE_PT_SIZE(bits))
+       ),
+
+       TP_fast_assign(
+               __entry->vm = vm;
+               __entry->pde = pde;
+               __entry->first = first;
+               __entry->last = first + count - 1;
+               scnprintf(__get_str(cur_ptes),
+                         TRACE_PT_SIZE(bits),
+                         "%*pb",
+                         bits,
+                         pt->used_ptes);
+       ),
+
+       TP_printk("vm=%p, pde=%d, updating %u:%u\t%s",
+                 __entry->vm, __entry->pde, __entry->last, __entry->first,
+                 __get_str(cur_ptes))
+);
+
+DEFINE_EVENT(i915_page_table_entry_update, i915_page_table_entry_map,
+       TP_PROTO(struct i915_address_space *vm, u32 pde,
+                struct i915_page_table_entry *pt, u32 first, u32 count, u32 bits),
+       TP_ARGS(vm, pde, pt, first, count, bits)
+);
+
 TRACE_EVENT(i915_gem_object_change_domain,
            TP_PROTO(struct drm_i915_gem_object *obj, u32 old_read, u32 old_write),
            TP_ARGS(obj, old_read, old_write),
diff --git a/drivers/gpu/drm/i915/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c
deleted file mode 100644 (file)
index d10fe3e..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-/*
- *
- * Copyright 2008 (c) Intel Corporation
- *   Jesse Barnes <jbarnes@virtuousgeek.org>
- * Copyright 2013 (c) Intel Corporation
- *   Daniel Vetter <daniel.vetter@ffwll.ch>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <drm/drmP.h>
-#include <drm/i915_drm.h>
-#include "intel_drv.h"
-#include "i915_reg.h"
-
-static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32     dpll_reg;
-
-       /* On IVB, 3rd pipe shares PLL with another one */
-       if (pipe > 1)
-               return false;
-
-       if (HAS_PCH_SPLIT(dev))
-               dpll_reg = PCH_DPLL(pipe);
-       else
-               dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B;
-
-       return (I915_READ(dpll_reg) & DPLL_VCO_ENABLE);
-}
-
-static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B);
-       u32 *array;
-       int i;
-
-       if (!i915_pipe_enabled(dev, pipe))
-               return;
-
-       if (HAS_PCH_SPLIT(dev))
-               reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B;
-
-       if (pipe == PIPE_A)
-               array = dev_priv->regfile.save_palette_a;
-       else
-               array = dev_priv->regfile.save_palette_b;
-
-       for (i = 0; i < 256; i++)
-               array[i] = I915_READ(reg + (i << 2));
-}
-
-static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B);
-       u32 *array;
-       int i;
-
-       if (!i915_pipe_enabled(dev, pipe))
-               return;
-
-       if (HAS_PCH_SPLIT(dev))
-               reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B;
-
-       if (pipe == PIPE_A)
-               array = dev_priv->regfile.save_palette_a;
-       else
-               array = dev_priv->regfile.save_palette_b;
-
-       for (i = 0; i < 256; i++)
-               I915_WRITE(reg + (i << 2), array[i]);
-}
-
-void i915_save_display_reg(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-
-       /* Cursor state */
-       dev_priv->regfile.saveCURACNTR = I915_READ(_CURACNTR);
-       dev_priv->regfile.saveCURAPOS = I915_READ(_CURAPOS);
-       dev_priv->regfile.saveCURABASE = I915_READ(_CURABASE);
-       dev_priv->regfile.saveCURBCNTR = I915_READ(_CURBCNTR);
-       dev_priv->regfile.saveCURBPOS = I915_READ(_CURBPOS);
-       dev_priv->regfile.saveCURBBASE = I915_READ(_CURBBASE);
-       if (IS_GEN2(dev))
-               dev_priv->regfile.saveCURSIZE = I915_READ(CURSIZE);
-
-       if (HAS_PCH_SPLIT(dev)) {
-               dev_priv->regfile.savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL);
-               dev_priv->regfile.saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL);
-       }
-
-       /* Pipe & plane A info */
-       dev_priv->regfile.savePIPEACONF = I915_READ(_PIPEACONF);
-       dev_priv->regfile.savePIPEASRC = I915_READ(_PIPEASRC);
-       if (HAS_PCH_SPLIT(dev)) {
-               dev_priv->regfile.saveFPA0 = I915_READ(_PCH_FPA0);
-               dev_priv->regfile.saveFPA1 = I915_READ(_PCH_FPA1);
-               dev_priv->regfile.saveDPLL_A = I915_READ(_PCH_DPLL_A);
-       } else {
-               dev_priv->regfile.saveFPA0 = I915_READ(_FPA0);
-               dev_priv->regfile.saveFPA1 = I915_READ(_FPA1);
-               dev_priv->regfile.saveDPLL_A = I915_READ(_DPLL_A);
-       }
-       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
-               dev_priv->regfile.saveDPLL_A_MD = I915_READ(_DPLL_A_MD);
-       dev_priv->regfile.saveHTOTAL_A = I915_READ(_HTOTAL_A);
-       dev_priv->regfile.saveHBLANK_A = I915_READ(_HBLANK_A);
-       dev_priv->regfile.saveHSYNC_A = I915_READ(_HSYNC_A);
-       dev_priv->regfile.saveVTOTAL_A = I915_READ(_VTOTAL_A);
-       dev_priv->regfile.saveVBLANK_A = I915_READ(_VBLANK_A);
-       dev_priv->regfile.saveVSYNC_A = I915_READ(_VSYNC_A);
-       if (!HAS_PCH_SPLIT(dev))
-               dev_priv->regfile.saveBCLRPAT_A = I915_READ(_BCLRPAT_A);
-
-       if (HAS_PCH_SPLIT(dev)) {
-               dev_priv->regfile.savePIPEA_DATA_M1 = I915_READ(_PIPEA_DATA_M1);
-               dev_priv->regfile.savePIPEA_DATA_N1 = I915_READ(_PIPEA_DATA_N1);
-               dev_priv->regfile.savePIPEA_LINK_M1 = I915_READ(_PIPEA_LINK_M1);
-               dev_priv->regfile.savePIPEA_LINK_N1 = I915_READ(_PIPEA_LINK_N1);
-
-               dev_priv->regfile.saveFDI_TXA_CTL = I915_READ(_FDI_TXA_CTL);
-               dev_priv->regfile.saveFDI_RXA_CTL = I915_READ(_FDI_RXA_CTL);
-
-               dev_priv->regfile.savePFA_CTL_1 = I915_READ(_PFA_CTL_1);
-               dev_priv->regfile.savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ);
-               dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS);
-
-               dev_priv->regfile.saveTRANSACONF = I915_READ(_PCH_TRANSACONF);
-               dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_PCH_TRANS_HTOTAL_A);
-               dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_PCH_TRANS_HBLANK_A);
-               dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_PCH_TRANS_HSYNC_A);
-               dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_PCH_TRANS_VTOTAL_A);
-               dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_PCH_TRANS_VBLANK_A);
-               dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_PCH_TRANS_VSYNC_A);
-       }
-
-       dev_priv->regfile.saveDSPACNTR = I915_READ(_DSPACNTR);
-       dev_priv->regfile.saveDSPASTRIDE = I915_READ(_DSPASTRIDE);
-       dev_priv->regfile.saveDSPASIZE = I915_READ(_DSPASIZE);
-       dev_priv->regfile.saveDSPAPOS = I915_READ(_DSPAPOS);
-       dev_priv->regfile.saveDSPAADDR = I915_READ(_DSPAADDR);
-       if (INTEL_INFO(dev)->gen >= 4) {
-               dev_priv->regfile.saveDSPASURF = I915_READ(_DSPASURF);
-               dev_priv->regfile.saveDSPATILEOFF = I915_READ(_DSPATILEOFF);
-       }
-       i915_save_palette(dev, PIPE_A);
-       dev_priv->regfile.savePIPEASTAT = I915_READ(_PIPEASTAT);
-
-       /* Pipe & plane B info */
-       dev_priv->regfile.savePIPEBCONF = I915_READ(_PIPEBCONF);
-       dev_priv->regfile.savePIPEBSRC = I915_READ(_PIPEBSRC);
-       if (HAS_PCH_SPLIT(dev)) {
-               dev_priv->regfile.saveFPB0 = I915_READ(_PCH_FPB0);
-               dev_priv->regfile.saveFPB1 = I915_READ(_PCH_FPB1);
-               dev_priv->regfile.saveDPLL_B = I915_READ(_PCH_DPLL_B);
-       } else {
-               dev_priv->regfile.saveFPB0 = I915_READ(_FPB0);
-               dev_priv->regfile.saveFPB1 = I915_READ(_FPB1);
-               dev_priv->regfile.saveDPLL_B = I915_READ(_DPLL_B);
-       }
-       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
-               dev_priv->regfile.saveDPLL_B_MD = I915_READ(_DPLL_B_MD);
-       dev_priv->regfile.saveHTOTAL_B = I915_READ(_HTOTAL_B);
-       dev_priv->regfile.saveHBLANK_B = I915_READ(_HBLANK_B);
-       dev_priv->regfile.saveHSYNC_B = I915_READ(_HSYNC_B);
-       dev_priv->regfile.saveVTOTAL_B = I915_READ(_VTOTAL_B);
-       dev_priv->regfile.saveVBLANK_B = I915_READ(_VBLANK_B);
-       dev_priv->regfile.saveVSYNC_B = I915_READ(_VSYNC_B);
-       if (!HAS_PCH_SPLIT(dev))
-               dev_priv->regfile.saveBCLRPAT_B = I915_READ(_BCLRPAT_B);
-
-       if (HAS_PCH_SPLIT(dev)) {
-               dev_priv->regfile.savePIPEB_DATA_M1 = I915_READ(_PIPEB_DATA_M1);
-               dev_priv->regfile.savePIPEB_DATA_N1 = I915_READ(_PIPEB_DATA_N1);
-               dev_priv->regfile.savePIPEB_LINK_M1 = I915_READ(_PIPEB_LINK_M1);
-               dev_priv->regfile.savePIPEB_LINK_N1 = I915_READ(_PIPEB_LINK_N1);
-
-               dev_priv->regfile.saveFDI_TXB_CTL = I915_READ(_FDI_TXB_CTL);
-               dev_priv->regfile.saveFDI_RXB_CTL = I915_READ(_FDI_RXB_CTL);
-
-               dev_priv->regfile.savePFB_CTL_1 = I915_READ(_PFB_CTL_1);
-               dev_priv->regfile.savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ);
-               dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS);
-
-               dev_priv->regfile.saveTRANSBCONF = I915_READ(_PCH_TRANSBCONF);
-               dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_PCH_TRANS_HTOTAL_B);
-               dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_PCH_TRANS_HBLANK_B);
-               dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_PCH_TRANS_HSYNC_B);
-               dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_PCH_TRANS_VTOTAL_B);
-               dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_PCH_TRANS_VBLANK_B);
-               dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_PCH_TRANS_VSYNC_B);
-       }
-
-       dev_priv->regfile.saveDSPBCNTR = I915_READ(_DSPBCNTR);
-       dev_priv->regfile.saveDSPBSTRIDE = I915_READ(_DSPBSTRIDE);
-       dev_priv->regfile.saveDSPBSIZE = I915_READ(_DSPBSIZE);
-       dev_priv->regfile.saveDSPBPOS = I915_READ(_DSPBPOS);
-       dev_priv->regfile.saveDSPBADDR = I915_READ(_DSPBADDR);
-       if (INTEL_INFO(dev)->gen >= 4) {
-               dev_priv->regfile.saveDSPBSURF = I915_READ(_DSPBSURF);
-               dev_priv->regfile.saveDSPBTILEOFF = I915_READ(_DSPBTILEOFF);
-       }
-       i915_save_palette(dev, PIPE_B);
-       dev_priv->regfile.savePIPEBSTAT = I915_READ(_PIPEBSTAT);
-
-       /* Fences */
-       switch (INTEL_INFO(dev)->gen) {
-       case 7:
-       case 6:
-               for (i = 0; i < 16; i++)
-                       dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
-               break;
-       case 5:
-       case 4:
-               for (i = 0; i < 16; i++)
-                       dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
-               break;
-       case 3:
-               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-                       for (i = 0; i < 8; i++)
-                               dev_priv->regfile.saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
-       case 2:
-               for (i = 0; i < 8; i++)
-                       dev_priv->regfile.saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
-               break;
-       }
-
-       /* CRT state */
-       if (HAS_PCH_SPLIT(dev))
-               dev_priv->regfile.saveADPA = I915_READ(PCH_ADPA);
-       else
-               dev_priv->regfile.saveADPA = I915_READ(ADPA);
-
-       /* Display Port state */
-       if (SUPPORTS_INTEGRATED_DP(dev)) {
-               dev_priv->regfile.saveDP_B = I915_READ(DP_B);
-               dev_priv->regfile.saveDP_C = I915_READ(DP_C);
-               dev_priv->regfile.saveDP_D = I915_READ(DP_D);
-               dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_DATA_M_G4X);
-               dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_DATA_M_G4X);
-               dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_DATA_N_G4X);
-               dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_DATA_N_G4X);
-               dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_LINK_M_G4X);
-               dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_LINK_M_G4X);
-               dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_LINK_N_G4X);
-               dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_LINK_N_G4X);
-       }
-       /* FIXME: regfile.save TV & SDVO state */
-
-       /* Panel fitter */
-       if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) {
-               dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
-               dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
-       }
-
-       /* Backlight */
-       if (INTEL_INFO(dev)->gen <= 4)
-               pci_read_config_byte(dev->pdev, PCI_LBPC,
-                                    &dev_priv->regfile.saveLBB);
-
-       if (HAS_PCH_SPLIT(dev)) {
-               dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1);
-               dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2);
-               dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL);
-               dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2);
-       } else {
-               dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
-               if (INTEL_INFO(dev)->gen >= 4)
-                       dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
-               dev_priv->regfile.saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL);
-       }
-
-       return;
-}
-
-void i915_restore_display_reg(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int dpll_a_reg, fpa0_reg, fpa1_reg;
-       int dpll_b_reg, fpb0_reg, fpb1_reg;
-       int i;
-
-       /* Backlight */
-       if (INTEL_INFO(dev)->gen <= 4)
-               pci_write_config_byte(dev->pdev, PCI_LBPC,
-                                     dev_priv->regfile.saveLBB);
-
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL);
-               I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
-               /* NOTE: BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2;
-                * otherwise we get blank eDP screen after S3 on some machines
-                */
-               I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->regfile.saveBLC_CPU_PWM_CTL2);
-               I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->regfile.saveBLC_CPU_PWM_CTL);
-       } else {
-               if (INTEL_INFO(dev)->gen >= 4)
-                       I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
-               I915_WRITE(BLC_PWM_CTL, dev_priv->regfile.saveBLC_PWM_CTL);
-               I915_WRITE(BLC_HIST_CTL, dev_priv->regfile.saveBLC_HIST_CTL);
-       }
-
-       /* Panel fitter */
-       if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PFIT_PGM_RATIOS, dev_priv->regfile.savePFIT_PGM_RATIOS);
-               I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL);
-       }
-
-       /* Display port ratios (must be done before clock is set) */
-       if (SUPPORTS_INTEGRATED_DP(dev)) {
-               I915_WRITE(_PIPEA_DATA_M_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_M);
-               I915_WRITE(_PIPEB_DATA_M_G4X, dev_priv->regfile.savePIPEB_GMCH_DATA_M);
-               I915_WRITE(_PIPEA_DATA_N_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_N);
-               I915_WRITE(_PIPEB_DATA_N_G4X, dev_priv->regfile.savePIPEB_GMCH_DATA_N);
-               I915_WRITE(_PIPEA_LINK_M_G4X, dev_priv->regfile.savePIPEA_DP_LINK_M);
-               I915_WRITE(_PIPEB_LINK_M_G4X, dev_priv->regfile.savePIPEB_DP_LINK_M);
-               I915_WRITE(_PIPEA_LINK_N_G4X, dev_priv->regfile.savePIPEA_DP_LINK_N);
-               I915_WRITE(_PIPEB_LINK_N_G4X, dev_priv->regfile.savePIPEB_DP_LINK_N);
-       }
-
-       /* Fences */
-       switch (INTEL_INFO(dev)->gen) {
-       case 7:
-       case 6:
-               for (i = 0; i < 16; i++)
-                       I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->regfile.saveFENCE[i]);
-               break;
-       case 5:
-       case 4:
-               for (i = 0; i < 16; i++)
-                       I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->regfile.saveFENCE[i]);
-               break;
-       case 3:
-       case 2:
-               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-                       for (i = 0; i < 8; i++)
-                               I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->regfile.saveFENCE[i+8]);
-               for (i = 0; i < 8; i++)
-                       I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->regfile.saveFENCE[i]);
-               break;
-       }
-
-
-       if (HAS_PCH_SPLIT(dev)) {
-               dpll_a_reg = _PCH_DPLL_A;
-               dpll_b_reg = _PCH_DPLL_B;
-               fpa0_reg = _PCH_FPA0;
-               fpb0_reg = _PCH_FPB0;
-               fpa1_reg = _PCH_FPA1;
-               fpb1_reg = _PCH_FPB1;
-       } else {
-               dpll_a_reg = _DPLL_A;
-               dpll_b_reg = _DPLL_B;
-               fpa0_reg = _FPA0;
-               fpb0_reg = _FPB0;
-               fpa1_reg = _FPA1;
-               fpb1_reg = _FPB1;
-       }
-
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PCH_DREF_CONTROL, dev_priv->regfile.savePCH_DREF_CONTROL);
-               I915_WRITE(DISP_ARB_CTL, dev_priv->regfile.saveDISP_ARB_CTL);
-       }
-
-       /* Pipe & plane A info */
-       /* Prime the clock */
-       if (dev_priv->regfile.saveDPLL_A & DPLL_VCO_ENABLE) {
-               I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A &
-                          ~DPLL_VCO_ENABLE);
-               POSTING_READ(dpll_a_reg);
-               udelay(150);
-       }
-       I915_WRITE(fpa0_reg, dev_priv->regfile.saveFPA0);
-       I915_WRITE(fpa1_reg, dev_priv->regfile.saveFPA1);
-       /* Actually enable it */
-       I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A);
-       POSTING_READ(dpll_a_reg);
-       udelay(150);
-       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(_DPLL_A_MD, dev_priv->regfile.saveDPLL_A_MD);
-               POSTING_READ(_DPLL_A_MD);
-       }
-       udelay(150);
-
-       /* Restore mode */
-       I915_WRITE(_HTOTAL_A, dev_priv->regfile.saveHTOTAL_A);
-       I915_WRITE(_HBLANK_A, dev_priv->regfile.saveHBLANK_A);
-       I915_WRITE(_HSYNC_A, dev_priv->regfile.saveHSYNC_A);
-       I915_WRITE(_VTOTAL_A, dev_priv->regfile.saveVTOTAL_A);
-       I915_WRITE(_VBLANK_A, dev_priv->regfile.saveVBLANK_A);
-       I915_WRITE(_VSYNC_A, dev_priv->regfile.saveVSYNC_A);
-       if (!HAS_PCH_SPLIT(dev))
-               I915_WRITE(_BCLRPAT_A, dev_priv->regfile.saveBCLRPAT_A);
-
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(_PIPEA_DATA_M1, dev_priv->regfile.savePIPEA_DATA_M1);
-               I915_WRITE(_PIPEA_DATA_N1, dev_priv->regfile.savePIPEA_DATA_N1);
-               I915_WRITE(_PIPEA_LINK_M1, dev_priv->regfile.savePIPEA_LINK_M1);
-               I915_WRITE(_PIPEA_LINK_N1, dev_priv->regfile.savePIPEA_LINK_N1);
-
-               I915_WRITE(_FDI_RXA_CTL, dev_priv->regfile.saveFDI_RXA_CTL);
-               I915_WRITE(_FDI_TXA_CTL, dev_priv->regfile.saveFDI_TXA_CTL);
-
-               I915_WRITE(_PFA_CTL_1, dev_priv->regfile.savePFA_CTL_1);
-               I915_WRITE(_PFA_WIN_SZ, dev_priv->regfile.savePFA_WIN_SZ);
-               I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS);
-
-               I915_WRITE(_PCH_TRANSACONF, dev_priv->regfile.saveTRANSACONF);
-               I915_WRITE(_PCH_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A);
-               I915_WRITE(_PCH_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A);
-               I915_WRITE(_PCH_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A);
-               I915_WRITE(_PCH_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A);
-               I915_WRITE(_PCH_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A);
-               I915_WRITE(_PCH_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A);
-       }
-
-       /* Restore plane info */
-       I915_WRITE(_DSPASIZE, dev_priv->regfile.saveDSPASIZE);
-       I915_WRITE(_DSPAPOS, dev_priv->regfile.saveDSPAPOS);
-       I915_WRITE(_PIPEASRC, dev_priv->regfile.savePIPEASRC);
-       I915_WRITE(_DSPAADDR, dev_priv->regfile.saveDSPAADDR);
-       I915_WRITE(_DSPASTRIDE, dev_priv->regfile.saveDSPASTRIDE);
-       if (INTEL_INFO(dev)->gen >= 4) {
-               I915_WRITE(_DSPASURF, dev_priv->regfile.saveDSPASURF);
-               I915_WRITE(_DSPATILEOFF, dev_priv->regfile.saveDSPATILEOFF);
-       }
-
-       I915_WRITE(_PIPEACONF, dev_priv->regfile.savePIPEACONF);
-
-       i915_restore_palette(dev, PIPE_A);
-       /* Enable the plane */
-       I915_WRITE(_DSPACNTR, dev_priv->regfile.saveDSPACNTR);
-       I915_WRITE(_DSPAADDR, I915_READ(_DSPAADDR));
-
-       /* Pipe & plane B info */
-       if (dev_priv->regfile.saveDPLL_B & DPLL_VCO_ENABLE) {
-               I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B &
-                          ~DPLL_VCO_ENABLE);
-               POSTING_READ(dpll_b_reg);
-               udelay(150);
-       }
-       I915_WRITE(fpb0_reg, dev_priv->regfile.saveFPB0);
-       I915_WRITE(fpb1_reg, dev_priv->regfile.saveFPB1);
-       /* Actually enable it */
-       I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B);
-       POSTING_READ(dpll_b_reg);
-       udelay(150);
-       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(_DPLL_B_MD, dev_priv->regfile.saveDPLL_B_MD);
-               POSTING_READ(_DPLL_B_MD);
-       }
-       udelay(150);
-
-       /* Restore mode */
-       I915_WRITE(_HTOTAL_B, dev_priv->regfile.saveHTOTAL_B);
-       I915_WRITE(_HBLANK_B, dev_priv->regfile.saveHBLANK_B);
-       I915_WRITE(_HSYNC_B, dev_priv->regfile.saveHSYNC_B);
-       I915_WRITE(_VTOTAL_B, dev_priv->regfile.saveVTOTAL_B);
-       I915_WRITE(_VBLANK_B, dev_priv->regfile.saveVBLANK_B);
-       I915_WRITE(_VSYNC_B, dev_priv->regfile.saveVSYNC_B);
-       if (!HAS_PCH_SPLIT(dev))
-               I915_WRITE(_BCLRPAT_B, dev_priv->regfile.saveBCLRPAT_B);
-
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(_PIPEB_DATA_M1, dev_priv->regfile.savePIPEB_DATA_M1);
-               I915_WRITE(_PIPEB_DATA_N1, dev_priv->regfile.savePIPEB_DATA_N1);
-               I915_WRITE(_PIPEB_LINK_M1, dev_priv->regfile.savePIPEB_LINK_M1);
-               I915_WRITE(_PIPEB_LINK_N1, dev_priv->regfile.savePIPEB_LINK_N1);
-
-               I915_WRITE(_FDI_RXB_CTL, dev_priv->regfile.saveFDI_RXB_CTL);
-               I915_WRITE(_FDI_TXB_CTL, dev_priv->regfile.saveFDI_TXB_CTL);
-
-               I915_WRITE(_PFB_CTL_1, dev_priv->regfile.savePFB_CTL_1);
-               I915_WRITE(_PFB_WIN_SZ, dev_priv->regfile.savePFB_WIN_SZ);
-               I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS);
-
-               I915_WRITE(_PCH_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF);
-               I915_WRITE(_PCH_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B);
-               I915_WRITE(_PCH_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B);
-               I915_WRITE(_PCH_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B);
-               I915_WRITE(_PCH_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B);
-               I915_WRITE(_PCH_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B);
-               I915_WRITE(_PCH_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B);
-       }
-
-       /* Restore plane info */
-       I915_WRITE(_DSPBSIZE, dev_priv->regfile.saveDSPBSIZE);
-       I915_WRITE(_DSPBPOS, dev_priv->regfile.saveDSPBPOS);
-       I915_WRITE(_PIPEBSRC, dev_priv->regfile.savePIPEBSRC);
-       I915_WRITE(_DSPBADDR, dev_priv->regfile.saveDSPBADDR);
-       I915_WRITE(_DSPBSTRIDE, dev_priv->regfile.saveDSPBSTRIDE);
-       if (INTEL_INFO(dev)->gen >= 4) {
-               I915_WRITE(_DSPBSURF, dev_priv->regfile.saveDSPBSURF);
-               I915_WRITE(_DSPBTILEOFF, dev_priv->regfile.saveDSPBTILEOFF);
-       }
-
-       I915_WRITE(_PIPEBCONF, dev_priv->regfile.savePIPEBCONF);
-
-       i915_restore_palette(dev, PIPE_B);
-       /* Enable the plane */
-       I915_WRITE(_DSPBCNTR, dev_priv->regfile.saveDSPBCNTR);
-       I915_WRITE(_DSPBADDR, I915_READ(_DSPBADDR));
-
-       /* Cursor state */
-       I915_WRITE(_CURAPOS, dev_priv->regfile.saveCURAPOS);
-       I915_WRITE(_CURACNTR, dev_priv->regfile.saveCURACNTR);
-       I915_WRITE(_CURABASE, dev_priv->regfile.saveCURABASE);
-       I915_WRITE(_CURBPOS, dev_priv->regfile.saveCURBPOS);
-       I915_WRITE(_CURBCNTR, dev_priv->regfile.saveCURBCNTR);
-       I915_WRITE(_CURBBASE, dev_priv->regfile.saveCURBBASE);
-       if (IS_GEN2(dev))
-               I915_WRITE(CURSIZE, dev_priv->regfile.saveCURSIZE);
-
-       /* CRT state */
-       if (HAS_PCH_SPLIT(dev))
-               I915_WRITE(PCH_ADPA, dev_priv->regfile.saveADPA);
-       else
-               I915_WRITE(ADPA, dev_priv->regfile.saveADPA);
-
-       /* Display Port state */
-       if (SUPPORTS_INTEGRATED_DP(dev)) {
-               I915_WRITE(DP_B, dev_priv->regfile.saveDP_B);
-               I915_WRITE(DP_C, dev_priv->regfile.saveDP_C);
-               I915_WRITE(DP_D, dev_priv->regfile.saveDP_D);
-       }
-       /* FIXME: restore TV & SDVO state */
-
-       return;
-}
diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
new file mode 100644 (file)
index 0000000..5eee75b
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright(c) 2011-2015 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, 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 "intel_drv.h"
+#include "i915_vgpu.h"
+
+/**
+ * DOC: Intel GVT-g guest support
+ *
+ * Intel GVT-g is a graphics virtualization technology which shares the
+ * GPU among multiple virtual machines on a time-sharing basis. Each
+ * virtual machine is presented a virtual GPU (vGPU), which has equivalent
+ * features as the underlying physical GPU (pGPU), so i915 driver can run
+ * seamlessly in a virtual machine. This file provides vGPU specific
+ * optimizations when running in a virtual machine, to reduce the complexity
+ * of vGPU emulation and to improve the overall performance.
+ *
+ * A primary function introduced here is so-called "address space ballooning"
+ * technique. Intel GVT-g partitions global graphics memory among multiple VMs,
+ * so each VM can directly access a portion of the memory without hypervisor's
+ * intervention, e.g. filling textures or queuing commands. However with the
+ * partitioning an unmodified i915 driver would assume a smaller graphics
+ * memory starting from address ZERO, then requires vGPU emulation module to
+ * translate the graphics address between 'guest view' and 'host view', for
+ * all registers and command opcodes which contain a graphics memory address.
+ * To reduce the complexity, Intel GVT-g introduces "address space ballooning",
+ * by telling the exact partitioning knowledge to each guest i915 driver, which
+ * then reserves and prevents non-allocated portions from allocation. Thus vGPU
+ * emulation module only needs to scan and validate graphics addresses without
+ * complexity of address translation.
+ *
+ */
+
+/**
+ * i915_check_vgpu - detect virtual GPU
+ * @dev: drm device *
+ *
+ * This function is called at the initialization stage, to detect whether
+ * running on a vGPU.
+ */
+void i915_check_vgpu(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       uint64_t magic;
+       uint32_t version;
+
+       BUILD_BUG_ON(sizeof(struct vgt_if) != VGT_PVINFO_SIZE);
+
+       if (!IS_HASWELL(dev))
+               return;
+
+       magic = readq(dev_priv->regs + vgtif_reg(magic));
+       if (magic != VGT_MAGIC)
+               return;
+
+       version = INTEL_VGT_IF_VERSION_ENCODE(
+               readw(dev_priv->regs + vgtif_reg(version_major)),
+               readw(dev_priv->regs + vgtif_reg(version_minor)));
+       if (version != INTEL_VGT_IF_VERSION) {
+               DRM_INFO("VGT interface version mismatch!\n");
+               return;
+       }
+
+       dev_priv->vgpu.active = true;
+       DRM_INFO("Virtual GPU for Intel GVT-g detected.\n");
+}
+
+struct _balloon_info_ {
+       /*
+        * There are up to 2 regions per mappable/unmappable graphic
+        * memory that might be ballooned. Here, index 0/1 is for mappable
+        * graphic memory, 2/3 for unmappable graphic memory.
+        */
+       struct drm_mm_node space[4];
+};
+
+static struct _balloon_info_ bl_info;
+
+/**
+ * intel_vgt_deballoon - deballoon reserved graphics address trunks
+ *
+ * This function is called to deallocate the ballooned-out graphic memory, when
+ * driver is unloaded or when ballooning fails.
+ */
+void intel_vgt_deballoon(void)
+{
+       int i;
+
+       DRM_DEBUG("VGT deballoon.\n");
+
+       for (i = 0; i < 4; i++) {
+               if (bl_info.space[i].allocated)
+                       drm_mm_remove_node(&bl_info.space[i]);
+       }
+
+       memset(&bl_info, 0, sizeof(bl_info));
+}
+
+static int vgt_balloon_space(struct drm_mm *mm,
+                            struct drm_mm_node *node,
+                            unsigned long start, unsigned long end)
+{
+       unsigned long size = end - start;
+
+       if (start == end)
+               return -EINVAL;
+
+       DRM_INFO("balloon space: range [ 0x%lx - 0x%lx ] %lu KiB.\n",
+                start, end, size / 1024);
+
+       node->start = start;
+       node->size = size;
+
+       return drm_mm_reserve_node(mm, node);
+}
+
+/**
+ * intel_vgt_balloon - balloon out reserved graphics address trunks
+ * @dev: drm device
+ *
+ * This function is called at the initialization stage, to balloon out the
+ * graphic address space allocated to other vGPUs, by marking these spaces as
+ * reserved. The ballooning related knowledge(starting address and size of
+ * the mappable/unmappable graphic memory) is described in the vgt_if structure
+ * in a reserved mmio range.
+ *
+ * To give an example, the drawing below depicts one typical scenario after
+ * ballooning. Here the vGPU1 has 2 pieces of graphic address spaces ballooned
+ * out each for the mappable and the non-mappable part. From the vGPU1 point of
+ * view, the total size is the same as the physical one, with the start address
+ * of its graphic space being zero. Yet there are some portions ballooned out(
+ * the shadow part, which are marked as reserved by drm allocator). From the
+ * host point of view, the graphic address space is partitioned by multiple
+ * vGPUs in different VMs.
+ *
+ *                        vGPU1 view         Host view
+ *             0 ------> +-----------+     +-----------+
+ *               ^       |///////////|     |   vGPU3   |
+ *               |       |///////////|     +-----------+
+ *               |       |///////////|     |   vGPU2   |
+ *               |       +-----------+     +-----------+
+ *        mappable GM    | available | ==> |   vGPU1   |
+ *               |       +-----------+     +-----------+
+ *               |       |///////////|     |           |
+ *               v       |///////////|     |   Host    |
+ *               +=======+===========+     +===========+
+ *               ^       |///////////|     |   vGPU3   |
+ *               |       |///////////|     +-----------+
+ *               |       |///////////|     |   vGPU2   |
+ *               |       +-----------+     +-----------+
+ *      unmappable GM    | available | ==> |   vGPU1   |
+ *               |       +-----------+     +-----------+
+ *               |       |///////////|     |           |
+ *               |       |///////////|     |   Host    |
+ *               v       |///////////|     |           |
+ * total GM size ------> +-----------+     +-----------+
+ *
+ * Returns:
+ * zero on success, non-zero if configuration invalid or ballooning failed
+ */
+int intel_vgt_balloon(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct i915_address_space *ggtt_vm = &dev_priv->gtt.base;
+       unsigned long ggtt_vm_end = ggtt_vm->start + ggtt_vm->total;
+
+       unsigned long mappable_base, mappable_size, mappable_end;
+       unsigned long unmappable_base, unmappable_size, unmappable_end;
+       int ret;
+
+       mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
+       mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
+       unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
+       unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
+
+       mappable_end = mappable_base + mappable_size;
+       unmappable_end = unmappable_base + unmappable_size;
+
+       DRM_INFO("VGT ballooning configuration:\n");
+       DRM_INFO("Mappable graphic memory: base 0x%lx size %ldKiB\n",
+                mappable_base, mappable_size / 1024);
+       DRM_INFO("Unmappable graphic memory: base 0x%lx size %ldKiB\n",
+                unmappable_base, unmappable_size / 1024);
+
+       if (mappable_base < ggtt_vm->start ||
+           mappable_end > dev_priv->gtt.mappable_end ||
+           unmappable_base < dev_priv->gtt.mappable_end ||
+           unmappable_end > ggtt_vm_end) {
+               DRM_ERROR("Invalid ballooning configuration!\n");
+               return -EINVAL;
+       }
+
+       /* Unmappable graphic memory ballooning */
+       if (unmappable_base > dev_priv->gtt.mappable_end) {
+               ret = vgt_balloon_space(&ggtt_vm->mm,
+                                       &bl_info.space[2],
+                                       dev_priv->gtt.mappable_end,
+                                       unmappable_base);
+
+               if (ret)
+                       goto err;
+       }
+
+       /*
+        * No need to partition out the last physical page,
+        * because it is reserved to the guard page.
+        */
+       if (unmappable_end < ggtt_vm_end - PAGE_SIZE) {
+               ret = vgt_balloon_space(&ggtt_vm->mm,
+                                       &bl_info.space[3],
+                                       unmappable_end,
+                                       ggtt_vm_end - PAGE_SIZE);
+               if (ret)
+                       goto err;
+       }
+
+       /* Mappable graphic memory ballooning */
+       if (mappable_base > ggtt_vm->start) {
+               ret = vgt_balloon_space(&ggtt_vm->mm,
+                                       &bl_info.space[0],
+                                       ggtt_vm->start, mappable_base);
+
+               if (ret)
+                       goto err;
+       }
+
+       if (mappable_end < dev_priv->gtt.mappable_end) {
+               ret = vgt_balloon_space(&ggtt_vm->mm,
+                                       &bl_info.space[1],
+                                       mappable_end,
+                                       dev_priv->gtt.mappable_end);
+
+               if (ret)
+                       goto err;
+       }
+
+       DRM_INFO("VGT balloon successfully\n");
+       return 0;
+
+err:
+       DRM_ERROR("VGT balloon fail\n");
+       intel_vgt_deballoon();
+       return ret;
+}
diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
new file mode 100644 (file)
index 0000000..97a88b5
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright(c) 2011-2015 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, 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_VGPU_H_
+#define _I915_VGPU_H_
+
+/* The MMIO offset of the shared info between guest and host emulator */
+#define VGT_PVINFO_PAGE        0x78000
+#define VGT_PVINFO_SIZE        0x1000
+
+/*
+ * The following structure pages are defined in GEN MMIO space
+ * for virtualization. (One page for now)
+ */
+#define VGT_MAGIC         0x4776544776544776ULL        /* 'vGTvGTvG' */
+#define VGT_VERSION_MAJOR 1
+#define VGT_VERSION_MINOR 0
+
+#define INTEL_VGT_IF_VERSION_ENCODE(major, minor) ((major) << 16 | (minor))
+#define INTEL_VGT_IF_VERSION \
+       INTEL_VGT_IF_VERSION_ENCODE(VGT_VERSION_MAJOR, VGT_VERSION_MINOR)
+
+struct vgt_if {
+       uint64_t magic;         /* VGT_MAGIC */
+       uint16_t version_major;
+       uint16_t version_minor;
+       uint32_t vgt_id;        /* ID of vGT instance */
+       uint32_t rsv1[12];      /* pad to offset 0x40 */
+       /*
+        *  Data structure to describe the balooning info of resources.
+        *  Each VM can only have one portion of continuous area for now.
+        *  (May support scattered resource in future)
+        *  (starting from offset 0x40)
+        */
+       struct {
+               /* Aperture register balooning */
+               struct {
+                       uint32_t base;
+                       uint32_t size;
+               } mappable_gmadr;       /* aperture */
+               /* GMADR register balooning */
+               struct {
+                       uint32_t base;
+                       uint32_t size;
+               } nonmappable_gmadr;    /* non aperture */
+               /* allowed fence registers */
+               uint32_t fence_num;
+               uint32_t rsv2[3];
+       } avail_rs;             /* available/assigned resource */
+       uint32_t rsv3[0x200 - 24];      /* pad to half page */
+       /*
+        * The bottom half page is for response from Gfx driver to hypervisor.
+        * Set to reserved fields temporarily by now.
+        */
+       uint32_t rsv4;
+       uint32_t display_ready; /* ready for display owner switch */
+       uint32_t rsv5[0x200 - 2];       /* pad to one page */
+} __packed;
+
+#define vgtif_reg(x) \
+       (VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x)
+
+/* vGPU display status to be used by the host side */
+#define VGT_DRV_DISPLAY_NOT_READY 0
+#define VGT_DRV_DISPLAY_READY     1  /* ready for display switch */
+
+extern void i915_check_vgpu(struct drm_device *dev);
+extern int intel_vgt_balloon(struct drm_device *dev);
+extern void intel_vgt_deballoon(void);
+
+#endif /* _I915_VGPU_H_ */
index 19a9dd5408f35ee14998c6aeef9a9bf2af50aa51..3903b90fb64efa80e1906d3ef1c6b4ad75866092 100644 (file)
@@ -134,9 +134,9 @@ int intel_atomic_commit(struct drm_device *dev,
         * FIXME:  The proper sequence here will eventually be:
         *
         * drm_atomic_helper_swap_state(dev, state)
-        * drm_atomic_helper_commit_pre_planes(dev, state);
+        * drm_atomic_helper_commit_modeset_disables(dev, state);
         * drm_atomic_helper_commit_planes(dev, state);
-        * drm_atomic_helper_commit_post_planes(dev, state);
+        * drm_atomic_helper_commit_modeset_enables(dev, state);
         * drm_atomic_helper_wait_for_vblanks(dev, state);
         * drm_atomic_helper_cleanup_planes(dev, state);
         * drm_atomic_state_free(state);
@@ -214,12 +214,18 @@ struct drm_crtc_state *
 intel_crtc_duplicate_state(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_crtc_state *crtc_state;
 
        if (WARN_ON(!intel_crtc->config))
-               return kzalloc(sizeof(*intel_crtc->config), GFP_KERNEL);
+               crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
+       else
+               crtc_state = kmemdup(intel_crtc->config,
+                                    sizeof(*intel_crtc->config), GFP_KERNEL);
 
-       return kmemdup(intel_crtc->config, sizeof(*intel_crtc->config),
-                      GFP_KERNEL);
+       if (crtc_state)
+               crtc_state->base.crtc = crtc;
+
+       return &crtc_state->base;
 }
 
 /**
index 9e6f727dfd19d2fa5a536626db3abd81dbeaa3a9..976b8915657077ac6096151ece85834d638cd521 100644 (file)
@@ -203,16 +203,8 @@ intel_plane_atomic_get_property(struct drm_plane *plane,
                                struct drm_property *property,
                                uint64_t *val)
 {
-       struct drm_mode_config *config = &plane->dev->mode_config;
-
-       if (property == config->rotation_property) {
-               *val = state->rotation;
-       } else {
-               DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
-               return -EINVAL;
-       }
-
-       return 0;
+       DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
+       return -EINVAL;
 }
 
 /**
@@ -233,14 +225,6 @@ intel_plane_atomic_set_property(struct drm_plane *plane,
                                struct drm_property *property,
                                uint64_t val)
 {
-       struct drm_mode_config *config = &plane->dev->mode_config;
-
-       if (property == config->rotation_property) {
-               state->rotation = val;
-       } else {
-               DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
-               return -EINVAL;
-       }
-
-       return 0;
+       DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
+       return -EINVAL;
 }
index 3f178258d9f9ce679044d2775b66359297d68623..c684085cb56ac0d3001ded0c81cbe72da4341a28 100644 (file)
@@ -662,6 +662,13 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
                              edp_link_params->vswing);
                break;
        }
+
+       if (bdb->version >= 173) {
+               uint8_t vswing;
+
+               vswing = (edp->edp_vswing_preemph >> (panel_type * 4)) & 0xF;
+               dev_priv->vbt.edp_low_vswing = vswing == 0;
+       }
 }
 
 static void
index a6a8710f665f5c8b37c28fd3b62ad7d0593a00b4..6afd5be33367615899403892cb9c3626ada051bb 100644 (file)
@@ -554,6 +554,7 @@ struct bdb_edp {
        /* ith bit indicates enabled/disabled for (i+1)th panel */
        u16 edp_s3d_feature;
        u16 edp_t3_optimization;
+       u64 edp_vswing_preemph;         /* v173 */
 } __packed;
 
 struct psr_table {
index e66e17af0a56a12243872704874ccfe2aa72929c..6095a998bdac38d32bc2abb30f8d82ee4bbd7f36 100644 (file)
@@ -690,7 +690,7 @@ intel_crt_detect(struct drm_connector *connector, bool force)
         * broken monitor (without edid) to work behind a broken kvm (that fails
         * to have the right resistors for HP detection) needs to fix this up.
         * For now just bail out. */
-       if (I915_HAS_HOTPLUG(dev)) {
+       if (I915_HAS_HOTPLUG(dev) && !i915.load_detect_test) {
                status = connector_status_disconnected;
                goto out;
        }
@@ -706,9 +706,11 @@ intel_crt_detect(struct drm_connector *connector, bool force)
        if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) {
                if (intel_crt_detect_ddc(connector))
                        status = connector_status_connected;
-               else
+               else if (INTEL_INFO(dev)->gen < 4)
                        status = intel_crt_load_detect(crt);
-               intel_release_load_detect_pipe(connector, &tmp);
+               else
+                       status = connector_status_unknown;
+               intel_release_load_detect_pipe(connector, &tmp, &ctx);
        } else
                status = connector_status_unknown;
 
@@ -794,6 +796,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
        .destroy = intel_crt_destroy,
        .set_property = intel_crt_set_property,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
        .atomic_get_property = intel_connector_atomic_get_property,
 };
 
index f14e8a2a022d81fbbd62b5ae081df9aff83e5ba0..47b9307da24b23c8fe03f9d90381560ad57bf523 100644 (file)
@@ -139,18 +139,24 @@ static const struct ddi_buf_trans skl_ddi_translations_dp[] = {
        { 0x00004014, 0x00000087 },
 };
 
+/* eDP 1.4 low vswing translation parameters */
+static const struct ddi_buf_trans skl_ddi_translations_edp[] = {
+       { 0x00000018, 0x000000a8 },
+       { 0x00002016, 0x000000ab },
+       { 0x00006012, 0x000000a2 },
+       { 0x00008010, 0x00000088 },
+       { 0x00000018, 0x000000ab },
+       { 0x00004014, 0x000000a2 },
+       { 0x00006012, 0x000000a6 },
+       { 0x00000018, 0x000000a2 },
+       { 0x00005013, 0x0000009c },
+       { 0x00000018, 0x00000088 },
+};
+
+
 static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
                                        /* Idx  NT mV   T mV    db  */
-       { 0x00000018, 0x000000a0 },     /* 0:   400     400     0   */
-       { 0x00004014, 0x00000098 },     /* 1:   400     600     3.5 */
-       { 0x00006012, 0x00000088 },     /* 2:   400     800     6   */
-       { 0x00000018, 0x0000003c },     /* 3:   450     450     0   */
-       { 0x00000018, 0x00000098 },     /* 4:   600     600     0   */
-       { 0x00003015, 0x00000088 },     /* 5:   600     800     2.5 */
-       { 0x00005013, 0x00000080 },     /* 6:   600     1000    4.5 */
-       { 0x00000018, 0x00000088 },     /* 7:   800     800     0   */
-       { 0x00000096, 0x00000080 },     /* 8:   800     1000    2   */
-       { 0x00000018, 0x00000080 },     /* 9:   1200    1200    0   */
+       { 0x00004014, 0x00000087 },     /* 0:   800     1000    2   */
 };
 
 enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
@@ -187,7 +193,8 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 reg;
-       int i, n_hdmi_entries, hdmi_800mV_0dB;
+       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;
        const struct ddi_buf_trans *ddi_translations_fdi;
        const struct ddi_buf_trans *ddi_translations_dp;
@@ -198,60 +205,85 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
        if (IS_SKYLAKE(dev)) {
                ddi_translations_fdi = NULL;
                ddi_translations_dp = skl_ddi_translations_dp;
-               ddi_translations_edp = skl_ddi_translations_dp;
+               n_dp_entries = ARRAY_SIZE(skl_ddi_translations_dp);
+               if (dev_priv->vbt.edp_low_vswing) {
+                       ddi_translations_edp = skl_ddi_translations_edp;
+                       n_edp_entries = ARRAY_SIZE(skl_ddi_translations_edp);
+               } else {
+                       ddi_translations_edp = skl_ddi_translations_dp;
+                       n_edp_entries = ARRAY_SIZE(skl_ddi_translations_dp);
+               }
+
+               /*
+                * On SKL, the recommendation from the hw team is to always use
+                * a certain type of level shifter (and thus the corresponding
+                * 800mV+2dB entry). Given that's the only validated entry, we
+                * override what is in the VBT, at least until further notice.
+                */
+               hdmi_level = 0;
                ddi_translations_hdmi = skl_ddi_translations_hdmi;
                n_hdmi_entries = ARRAY_SIZE(skl_ddi_translations_hdmi);
-               hdmi_800mV_0dB = 7;
+               hdmi_default_entry = 0;
        } else if (IS_BROADWELL(dev)) {
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
                ddi_translations_edp = bdw_ddi_translations_edp;
                ddi_translations_hdmi = bdw_ddi_translations_hdmi;
+               n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
+               n_dp_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
                n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
-               hdmi_800mV_0dB = 7;
+               hdmi_default_entry = 7;
        } else if (IS_HASWELL(dev)) {
                ddi_translations_fdi = hsw_ddi_translations_fdi;
                ddi_translations_dp = hsw_ddi_translations_dp;
                ddi_translations_edp = hsw_ddi_translations_dp;
                ddi_translations_hdmi = hsw_ddi_translations_hdmi;
+               n_dp_entries = n_edp_entries = ARRAY_SIZE(hsw_ddi_translations_dp);
                n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi);
-               hdmi_800mV_0dB = 6;
+               hdmi_default_entry = 6;
        } else {
                WARN(1, "ddi translation table missing\n");
                ddi_translations_edp = bdw_ddi_translations_dp;
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
                ddi_translations_hdmi = bdw_ddi_translations_hdmi;
+               n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
+               n_dp_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
                n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
-               hdmi_800mV_0dB = 7;
+               hdmi_default_entry = 7;
        }
 
        switch (port) {
        case PORT_A:
                ddi_translations = ddi_translations_edp;
+               size = n_edp_entries;
                break;
        case PORT_B:
        case PORT_C:
                ddi_translations = ddi_translations_dp;
+               size = n_dp_entries;
                break;
        case PORT_D:
-               if (intel_dp_is_edp(dev, PORT_D))
+               if (intel_dp_is_edp(dev, PORT_D)) {
                        ddi_translations = ddi_translations_edp;
-               else
+                       size = n_edp_entries;
+               } else {
                        ddi_translations = ddi_translations_dp;
+                       size = n_dp_entries;
+               }
                break;
        case PORT_E:
                if (ddi_translations_fdi)
                        ddi_translations = ddi_translations_fdi;
                else
                        ddi_translations = ddi_translations_dp;
+               size = n_dp_entries;
                break;
        default:
                BUG();
        }
 
-       for (i = 0, reg = DDI_BUF_TRANS(port);
-            i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) {
+       for (i = 0, reg = DDI_BUF_TRANS(port); i < size; i++) {
                I915_WRITE(reg, ddi_translations[i].trans1);
                reg += 4;
                I915_WRITE(reg, ddi_translations[i].trans2);
@@ -261,7 +293,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
        /* Choose a good default if VBT is badly populated */
        if (hdmi_level == HDMI_LEVEL_SHIFT_UNKNOWN ||
            hdmi_level >= n_hdmi_entries)
-               hdmi_level = hdmi_800mV_0dB;
+               hdmi_level = hdmi_default_entry;
 
        /* Entry 9 is for HDMI: */
        I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans1);
@@ -460,17 +492,23 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc)
 }
 
 static struct intel_encoder *
-intel_ddi_get_crtc_new_encoder(struct intel_crtc *crtc)
+intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct intel_encoder *intel_encoder, *ret = NULL;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct intel_encoder *ret = NULL;
+       struct drm_atomic_state *state;
        int num_encoders = 0;
+       int i;
 
-       for_each_intel_encoder(dev, intel_encoder) {
-               if (intel_encoder->new_crtc == crtc) {
-                       ret = intel_encoder;
-                       num_encoders++;
-               }
+       state = crtc_state->base.state;
+
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i] ||
+                   state->connector_states[i]->crtc != crtc_state->base.crtc)
+                       continue;
+
+               ret = to_intel_encoder(state->connector_states[i]->best_encoder);
+               num_encoders++;
        }
 
        WARN(num_encoders != 1, "%d encoders on crtc for pipe %c\n", num_encoders,
@@ -752,9 +790,18 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder,
                case DPLL_CRTL1_LINK_RATE_810:
                        link_clock = 81000;
                        break;
+               case DPLL_CRTL1_LINK_RATE_1080:
+                       link_clock = 108000;
+                       break;
                case DPLL_CRTL1_LINK_RATE_1350:
                        link_clock = 135000;
                        break;
+               case DPLL_CRTL1_LINK_RATE_1620:
+                       link_clock = 162000;
+                       break;
+               case DPLL_CRTL1_LINK_RATE_2160:
+                       link_clock = 216000;
+                       break;
                case DPLL_CRTL1_LINK_RATE_2700:
                        link_clock = 270000;
                        break;
@@ -1175,7 +1222,7 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc,
 {
        struct drm_device *dev = intel_crtc->base.dev;
        struct intel_encoder *intel_encoder =
-               intel_ddi_get_crtc_new_encoder(intel_crtc);
+               intel_ddi_get_crtc_new_encoder(crtc_state);
        int clock = crtc_state->port_clock;
 
        if (IS_SKYLAKE(dev))
index 3d220a67f8656ed9173b88672cd114893070aec0..75955fee6d24b1aaa2b622d5c22704c8241b4c53 100644 (file)
@@ -37,6 +37,7 @@
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 #include "i915_trace.h"
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_crtc_helper.h>
@@ -82,7 +83,8 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc,
                                   struct intel_crtc_state *pipe_config);
 
 static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
-                         int x, int y, struct drm_framebuffer *old_fb);
+                         int x, int y, struct drm_framebuffer *old_fb,
+                         struct drm_atomic_state *state);
 static int intel_framebuffer_init(struct drm_device *dev,
                                  struct intel_framebuffer *ifb,
                                  struct drm_mode_fb_cmd2 *mode_cmd,
@@ -390,7 +392,7 @@ static const intel_limit_t intel_limits_chv = {
         * them would make no difference.
         */
        .dot = { .min = 25000 * 5, .max = 540000 * 5},
-       .vco = { .min = 4860000, .max = 6700000 },
+       .vco = { .min = 4800000, .max = 6480000 },
        .n = { .min = 1, .max = 1 },
        .m1 = { .min = 2, .max = 2 },
        .m2 = { .min = 24 << 22, .max = 175 << 22 },
@@ -429,25 +431,41 @@ bool intel_pipe_has_type(struct intel_crtc *crtc, enum intel_output_type type)
  * intel_pipe_has_type() but looking at encoder->new_crtc instead of
  * encoder->crtc.
  */
-static bool intel_pipe_will_have_type(struct intel_crtc *crtc, int type)
+static bool intel_pipe_will_have_type(const struct intel_crtc_state *crtc_state,
+                                     int type)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_atomic_state *state = crtc_state->base.state;
+       struct drm_connector_state *connector_state;
        struct intel_encoder *encoder;
+       int i, num_connectors = 0;
+
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
+                       continue;
+
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != crtc_state->base.crtc)
+                       continue;
+
+               num_connectors++;
 
-       for_each_intel_encoder(dev, encoder)
-               if (encoder->new_crtc == crtc && encoder->type == type)
+               encoder = to_intel_encoder(connector_state->best_encoder);
+               if (encoder->type == type)
                        return true;
+       }
+
+       WARN_ON(num_connectors == 0);
 
        return false;
 }
 
-static const intel_limit_t *intel_ironlake_limit(struct intel_crtc *crtc,
-                                               int refclk)
+static const intel_limit_t *
+intel_ironlake_limit(struct intel_crtc_state *crtc_state, int refclk)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
        const intel_limit_t *limit;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                if (intel_is_dual_link_lvds(dev)) {
                        if (refclk == 100000)
                                limit = &intel_limits_ironlake_dual_lvds_100m;
@@ -465,20 +483,21 @@ static const intel_limit_t *intel_ironlake_limit(struct intel_crtc *crtc,
        return limit;
 }
 
-static const intel_limit_t *intel_g4x_limit(struct intel_crtc *crtc)
+static const intel_limit_t *
+intel_g4x_limit(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
        const intel_limit_t *limit;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                if (intel_is_dual_link_lvds(dev))
                        limit = &intel_limits_g4x_dual_channel_lvds;
                else
                        limit = &intel_limits_g4x_single_channel_lvds;
-       } else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_HDMI) ||
-                  intel_pipe_will_have_type(crtc, INTEL_OUTPUT_ANALOG)) {
+       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_HDMI) ||
+                  intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
                limit = &intel_limits_g4x_hdmi;
-       } else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_SDVO)) {
+       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_SDVO)) {
                limit = &intel_limits_g4x_sdvo;
        } else /* The option is for other outputs */
                limit = &intel_limits_i9xx_sdvo;
@@ -486,17 +505,18 @@ static const intel_limit_t *intel_g4x_limit(struct intel_crtc *crtc)
        return limit;
 }
 
-static const intel_limit_t *intel_limit(struct intel_crtc *crtc, int refclk)
+static const intel_limit_t *
+intel_limit(struct intel_crtc_state *crtc_state, int refclk)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
        const intel_limit_t *limit;
 
        if (HAS_PCH_SPLIT(dev))
-               limit = intel_ironlake_limit(crtc, refclk);
+               limit = intel_ironlake_limit(crtc_state, refclk);
        else if (IS_G4X(dev)) {
-               limit = intel_g4x_limit(crtc);
+               limit = intel_g4x_limit(crtc_state);
        } else if (IS_PINEVIEW(dev)) {
-               if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS))
+               if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_pineview_lvds;
                else
                        limit = &intel_limits_pineview_sdvo;
@@ -505,14 +525,14 @@ static const intel_limit_t *intel_limit(struct intel_crtc *crtc, int refclk)
        } else if (IS_VALLEYVIEW(dev)) {
                limit = &intel_limits_vlv;
        } else if (!IS_GEN2(dev)) {
-               if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS))
+               if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_i9xx_lvds;
                else
                        limit = &intel_limits_i9xx_sdvo;
        } else {
-               if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS))
+               if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_i8xx_lvds;
-               else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_DVO))
+               else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_DVO))
                        limit = &intel_limits_i8xx_dvo;
                else
                        limit = &intel_limits_i8xx_dac;
@@ -599,15 +619,17 @@ static bool intel_PLL_is_valid(struct drm_device *dev,
 }
 
 static bool
-i9xx_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
+i9xx_find_best_dpll(const intel_limit_t *limit,
+                   struct intel_crtc_state *crtc_state,
                    int target, int refclk, intel_clock_t *match_clock,
                    intel_clock_t *best_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        intel_clock_t clock;
        int err = target;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                /*
                 * For LVDS just rely on its current settings for dual-channel.
                 * We haven't figured out how to reliably set up different
@@ -660,15 +682,17 @@ i9xx_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
 }
 
 static bool
-pnv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
+pnv_find_best_dpll(const intel_limit_t *limit,
+                  struct intel_crtc_state *crtc_state,
                   int target, int refclk, intel_clock_t *match_clock,
                   intel_clock_t *best_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        intel_clock_t clock;
        int err = target;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                /*
                 * For LVDS just rely on its current settings for dual-channel.
                 * We haven't figured out how to reliably set up different
@@ -719,10 +743,12 @@ pnv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
 }
 
 static bool
-g4x_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
+g4x_find_best_dpll(const intel_limit_t *limit,
+                  struct intel_crtc_state *crtc_state,
                   int target, int refclk, intel_clock_t *match_clock,
                   intel_clock_t *best_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        intel_clock_t clock;
        int max_n;
@@ -731,7 +757,7 @@ g4x_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
        int err_most = (target >> 8) + (target >> 9);
        found = false;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                if (intel_is_dual_link_lvds(dev))
                        clock.p2 = limit->p2.p2_fast;
                else
@@ -775,11 +801,53 @@ g4x_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
        return found;
 }
 
+/*
+ * Check if the calculated PLL configuration is more optimal compared to the
+ * best configuration and error found so far. Return the calculated error.
+ */
+static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
+                              const intel_clock_t *calculated_clock,
+                              const intel_clock_t *best_clock,
+                              unsigned int best_error_ppm,
+                              unsigned int *error_ppm)
+{
+       /*
+        * For CHV ignore the error and consider only the P value.
+        * Prefer a bigger P value based on HW requirements.
+        */
+       if (IS_CHERRYVIEW(dev)) {
+               *error_ppm = 0;
+
+               return calculated_clock->p > best_clock->p;
+       }
+
+       if (WARN_ON_ONCE(!target_freq))
+               return false;
+
+       *error_ppm = div_u64(1000000ULL *
+                               abs(target_freq - calculated_clock->dot),
+                            target_freq);
+       /*
+        * Prefer a better P value over a better (smaller) error if the error
+        * is small. Ensure this preference for future configurations too by
+        * setting the error to 0.
+        */
+       if (*error_ppm < 100 && calculated_clock->p > best_clock->p) {
+               *error_ppm = 0;
+
+               return true;
+       }
+
+       return *error_ppm + 10 < best_error_ppm;
+}
+
 static bool
-vlv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
+vlv_find_best_dpll(const intel_limit_t *limit,
+                  struct intel_crtc_state *crtc_state,
                   int target, int refclk, intel_clock_t *match_clock,
                   intel_clock_t *best_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        intel_clock_t clock;
        unsigned int bestppm = 1000000;
@@ -799,7 +867,7 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
                                clock.p = clock.p1 * clock.p2;
                                /* based on hardware requirement, prefer bigger m1,m2 values */
                                for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
-                                       unsigned int ppm, diff;
+                                       unsigned int ppm;
 
                                        clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n,
                                                                     refclk * clock.m1);
@@ -810,20 +878,15 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
                                                                &clock))
                                                continue;
 
-                                       diff = abs(clock.dot - target);
-                                       ppm = div_u64(1000000ULL * diff, target);
-
-                                       if (ppm < 100 && clock.p > best_clock->p) {
-                                               bestppm = 0;
-                                               *best_clock = clock;
-                                               found = true;
-                                       }
+                                       if (!vlv_PLL_is_optimal(dev, target,
+                                                               &clock,
+                                                               best_clock,
+                                                               bestppm, &ppm))
+                                               continue;
 
-                                       if (bestppm >= 10 && ppm < bestppm - 10) {
-                                               bestppm = ppm;
-                                               *best_clock = clock;
-                                               found = true;
-                                       }
+                                       *best_clock = clock;
+                                       bestppm = ppm;
+                                       found = true;
                                }
                        }
                }
@@ -833,16 +896,20 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
 }
 
 static bool
-chv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
+chv_find_best_dpll(const intel_limit_t *limit,
+                  struct intel_crtc_state *crtc_state,
                   int target, int refclk, intel_clock_t *match_clock,
                   intel_clock_t *best_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
+       unsigned int best_error_ppm;
        intel_clock_t clock;
        uint64_t m2;
        int found = false;
 
        memset(best_clock, 0, sizeof(*best_clock));
+       best_error_ppm = 1000000;
 
        /*
         * Based on hardware doc, the n always set to 1, and m1 always
@@ -856,6 +923,7 @@ chv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
                for (clock.p2 = limit->p2.p2_fast;
                                clock.p2 >= limit->p2.p2_slow;
                                clock.p2 -= clock.p2 > 10 ? 2 : 1) {
+                       unsigned int error_ppm;
 
                        clock.p = clock.p1 * clock.p2;
 
@@ -872,12 +940,13 @@ chv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc,
                        if (!intel_PLL_is_valid(dev, limit, &clock))
                                continue;
 
-                       /* based on hardware requirement, prefer bigger p
-                        */
-                       if (clock.p > best_clock->p) {
-                               *best_clock = clock;
-                               found = true;
-                       }
+                       if (!vlv_PLL_is_optimal(dev, target, &clock, best_clock,
+                                               best_error_ppm, &error_ppm))
+                               continue;
+
+                       *best_clock = clock;
+                       best_error_ppm = error_ppm;
+                       found = true;
                }
        }
 
@@ -896,8 +965,12 @@ bool intel_crtc_active(struct drm_crtc *crtc)
         *
         * We can ditch the crtc->primary->fb check as soon as we can
         * properly reconstruct framebuffers.
+        *
+        * FIXME: The intel_crtc->active here should be switched to
+        * crtc->state->active once we have proper CRTC states wired up
+        * for atomic.
         */
-       return intel_crtc->active && crtc->primary->fb &&
+       return intel_crtc->active && crtc->primary->state->fb &&
                intel_crtc->config->base.adjusted_mode.crtc_clock;
 }
 
@@ -1300,14 +1373,14 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
        u32 val;
 
        if (INTEL_INFO(dev)->gen >= 9) {
-               for_each_sprite(pipe, sprite) {
+               for_each_sprite(dev_priv, pipe, sprite) {
                        val = I915_READ(PLANE_CTL(pipe, sprite));
                        I915_STATE_WARN(val & PLANE_CTL_ENABLE,
                             "plane %d assertion failure, should be off on pipe %c but is still active\n",
                             sprite, pipe_name(pipe));
                }
        } else if (IS_VALLEYVIEW(dev)) {
-               for_each_sprite(pipe, sprite) {
+               for_each_sprite(dev_priv, pipe, sprite) {
                        reg = SPCNTR(pipe, sprite);
                        val = I915_READ(reg);
                        I915_STATE_WARN(val & SP_ENABLE,
@@ -2189,30 +2262,109 @@ static bool need_vtd_wa(struct drm_device *dev)
        return false;
 }
 
-int
-intel_fb_align_height(struct drm_device *dev, int height, unsigned int tiling)
+unsigned int
+intel_tile_height(struct drm_device *dev, uint32_t pixel_format,
+                 uint64_t fb_format_modifier)
+{
+       unsigned int tile_height;
+       uint32_t pixel_bytes;
+
+       switch (fb_format_modifier) {
+       case DRM_FORMAT_MOD_NONE:
+               tile_height = 1;
+               break;
+       case I915_FORMAT_MOD_X_TILED:
+               tile_height = IS_GEN2(dev) ? 16 : 8;
+               break;
+       case I915_FORMAT_MOD_Y_TILED:
+               tile_height = 32;
+               break;
+       case I915_FORMAT_MOD_Yf_TILED:
+               pixel_bytes = drm_format_plane_cpp(pixel_format, 0);
+               switch (pixel_bytes) {
+               default:
+               case 1:
+                       tile_height = 64;
+                       break;
+               case 2:
+               case 4:
+                       tile_height = 32;
+                       break;
+               case 8:
+                       tile_height = 16;
+                       break;
+               case 16:
+                       WARN_ONCE(1,
+                                 "128-bit pixels are not supported for display!");
+                       tile_height = 16;
+                       break;
+               }
+               break;
+       default:
+               MISSING_CASE(fb_format_modifier);
+               tile_height = 1;
+               break;
+       }
+
+       return tile_height;
+}
+
+unsigned int
+intel_fb_align_height(struct drm_device *dev, unsigned int height,
+                     uint32_t pixel_format, uint64_t fb_format_modifier)
 {
-       int tile_height;
+       return ALIGN(height, intel_tile_height(dev, pixel_format,
+                                              fb_format_modifier));
+}
+
+static int
+intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
+                       const struct drm_plane_state *plane_state)
+{
+       struct intel_rotation_info *info = &view->rotation_info;
+
+       *view = i915_ggtt_view_normal;
+
+       if (!plane_state)
+               return 0;
+
+       if (!intel_rotation_90_or_270(plane_state->rotation))
+               return 0;
+
+       *view = i915_ggtt_view_rotated;
+
+       info->height = fb->height;
+       info->pixel_format = fb->pixel_format;
+       info->pitch = fb->pitches[0];
+       info->fb_modifier = fb->modifier[0];
+
+       if (!(info->fb_modifier == I915_FORMAT_MOD_Y_TILED ||
+             info->fb_modifier == I915_FORMAT_MOD_Yf_TILED)) {
+               DRM_DEBUG_KMS(
+                             "Y or Yf tiling is needed for 90/270 rotation!\n");
+               return -EINVAL;
+       }
 
-       tile_height = tiling ? (IS_GEN2(dev) ? 16 : 8) : 1;
-       return ALIGN(height, tile_height);
+       return 0;
 }
 
 int
 intel_pin_and_fence_fb_obj(struct drm_plane *plane,
                           struct drm_framebuffer *fb,
+                          const struct drm_plane_state *plane_state,
                           struct intel_engine_cs *pipelined)
 {
        struct drm_device *dev = fb->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       struct i915_ggtt_view view;
        u32 alignment;
        int ret;
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
-       switch (obj->tiling_mode) {
-       case I915_TILING_NONE:
+       switch (fb->modifier[0]) {
+       case DRM_FORMAT_MOD_NONE:
                if (INTEL_INFO(dev)->gen >= 9)
                        alignment = 256 * 1024;
                else if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
@@ -2222,7 +2374,7 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
                else
                        alignment = 64 * 1024;
                break;
-       case I915_TILING_X:
+       case I915_FORMAT_MOD_X_TILED:
                if (INTEL_INFO(dev)->gen >= 9)
                        alignment = 256 * 1024;
                else {
@@ -2230,13 +2382,22 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
                        alignment = 0;
                }
                break;
-       case I915_TILING_Y:
-               WARN(1, "Y tiled bo slipped through, driver bug!\n");
-               return -EINVAL;
+       case I915_FORMAT_MOD_Y_TILED:
+       case I915_FORMAT_MOD_Yf_TILED:
+               if (WARN_ONCE(INTEL_INFO(dev)->gen < 9,
+                         "Y tiling bo slipped through, driver bug!\n"))
+                       return -EINVAL;
+               alignment = 1 * 1024 * 1024;
+               break;
        default:
-               BUG();
+               MISSING_CASE(fb->modifier[0]);
+               return -EINVAL;
        }
 
+       ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
+       if (ret)
+               return ret;
+
        /* Note that the w/a also requires 64 PTE of padding following the
         * bo. We currently fill all unused PTE with the shadow page and so
         * we should always have valid PTE following the scanout preventing
@@ -2255,7 +2416,8 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
        intel_runtime_pm_get(dev_priv);
 
        dev_priv->mm.interruptible = false;
-       ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined);
+       ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined,
+                                                  &view);
        if (ret)
                goto err_interruptible;
 
@@ -2275,19 +2437,27 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
        return 0;
 
 err_unpin:
-       i915_gem_object_unpin_from_display_plane(obj);
+       i915_gem_object_unpin_from_display_plane(obj, &view);
 err_interruptible:
        dev_priv->mm.interruptible = true;
        intel_runtime_pm_put(dev_priv);
        return ret;
 }
 
-void intel_unpin_fb_obj(struct drm_i915_gem_object *obj)
+static void intel_unpin_fb_obj(struct drm_framebuffer *fb,
+                              const struct drm_plane_state *plane_state)
 {
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       struct i915_ggtt_view view;
+       int ret;
+
        WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex));
 
+       ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
+       WARN_ONCE(ret, "Couldn't get view from plane state!");
+
        i915_gem_object_unpin_fence(obj);
-       i915_gem_object_unpin_from_display_plane(obj);
+       i915_gem_object_unpin_from_display_plane(obj, &view);
 }
 
 /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel
@@ -2365,43 +2535,49 @@ static int skl_format_to_fourcc(int format, bool rgb_order, bool alpha)
 }
 
 static bool
-intel_alloc_plane_obj(struct intel_crtc *crtc,
-                     struct intel_initial_plane_config *plane_config)
+intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
+                             struct intel_initial_plane_config *plane_config)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_gem_object *obj = NULL;
        struct drm_mode_fb_cmd2 mode_cmd = { 0 };
-       u32 base = plane_config->base;
+       struct drm_framebuffer *fb = &plane_config->fb->base;
+       u32 base_aligned = round_down(plane_config->base, PAGE_SIZE);
+       u32 size_aligned = round_up(plane_config->base + plane_config->size,
+                                   PAGE_SIZE);
+
+       size_aligned -= base_aligned;
 
        if (plane_config->size == 0)
                return false;
 
-       obj = i915_gem_object_create_stolen_for_preallocated(dev, base, base,
-                                                            plane_config->size);
+       obj = i915_gem_object_create_stolen_for_preallocated(dev,
+                                                            base_aligned,
+                                                            base_aligned,
+                                                            size_aligned);
        if (!obj)
                return false;
 
        obj->tiling_mode = plane_config->tiling;
        if (obj->tiling_mode == I915_TILING_X)
-               obj->stride = crtc->base.primary->fb->pitches[0];
+               obj->stride = fb->pitches[0];
 
-       mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format;
-       mode_cmd.width = crtc->base.primary->fb->width;
-       mode_cmd.height = crtc->base.primary->fb->height;
-       mode_cmd.pitches[0] = crtc->base.primary->fb->pitches[0];
+       mode_cmd.pixel_format = fb->pixel_format;
+       mode_cmd.width = fb->width;
+       mode_cmd.height = fb->height;
+       mode_cmd.pitches[0] = fb->pitches[0];
+       mode_cmd.modifier[0] = fb->modifier[0];
+       mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
 
        mutex_lock(&dev->struct_mutex);
-
-       if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.primary->fb),
+       if (intel_framebuffer_init(dev, to_intel_framebuffer(fb),
                                   &mode_cmd, obj)) {
                DRM_DEBUG_KMS("intel fb init failed\n");
                goto out_unref_obj;
        }
-
-       obj->frontbuffer_bits = INTEL_FRONTBUFFER_PRIMARY(crtc->pipe);
        mutex_unlock(&dev->struct_mutex);
 
-       DRM_DEBUG_KMS("plane fb obj %p\n", obj);
+       DRM_DEBUG_KMS("initial plane fb obj %p\n", obj);
        return true;
 
 out_unref_obj:
@@ -2410,24 +2586,41 @@ out_unref_obj:
        return false;
 }
 
+/* Update plane->state->fb to match plane->fb after driver-internal updates */
+static void
+update_state_fb(struct drm_plane *plane)
+{
+       if (plane->fb == plane->state->fb)
+               return;
+
+       if (plane->state->fb)
+               drm_framebuffer_unreference(plane->state->fb);
+       plane->state->fb = plane->fb;
+       if (plane->state->fb)
+               drm_framebuffer_reference(plane->state->fb);
+}
+
 static void
-intel_find_plane_obj(struct intel_crtc *intel_crtc,
-                    struct intel_initial_plane_config *plane_config)
+intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
+                            struct intel_initial_plane_config *plane_config)
 {
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *c;
        struct intel_crtc *i;
        struct drm_i915_gem_object *obj;
+       struct drm_plane *primary = intel_crtc->base.primary;
+       struct drm_framebuffer *fb;
 
-       if (!intel_crtc->base.primary->fb)
+       if (!plane_config->fb)
                return;
 
-       if (intel_alloc_plane_obj(intel_crtc, plane_config))
-               return;
+       if (intel_alloc_initial_plane_obj(intel_crtc, plane_config)) {
+               fb = &plane_config->fb->base;
+               goto valid_fb;
+       }
 
-       kfree(intel_crtc->base.primary->fb);
-       intel_crtc->base.primary->fb = NULL;
+       kfree(plane_config->fb);
 
        /*
         * Failed to alloc the obj, check to see if we should share
@@ -2442,20 +2635,29 @@ intel_find_plane_obj(struct intel_crtc *intel_crtc,
                if (!i->active)
                        continue;
 
-               obj = intel_fb_obj(c->primary->fb);
-               if (obj == NULL)
+               fb = c->primary->fb;
+               if (!fb)
                        continue;
 
+               obj = intel_fb_obj(fb);
                if (i915_gem_obj_ggtt_offset(obj) == plane_config->base) {
-                       if (obj->tiling_mode != I915_TILING_NONE)
-                               dev_priv->preserve_bios_swizzle = true;
-
-                       drm_framebuffer_reference(c->primary->fb);
-                       intel_crtc->base.primary->fb = c->primary->fb;
-                       obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
-                       break;
+                       drm_framebuffer_reference(fb);
+                       goto valid_fb;
                }
        }
+
+       return;
+
+valid_fb:
+       obj = intel_fb_obj(fb);
+       if (obj->tiling_mode != I915_TILING_NONE)
+               dev_priv->preserve_bios_swizzle = true;
+
+       primary->fb = fb;
+       primary->state->crtc = &intel_crtc->base;
+       primary->crtc = &intel_crtc->base;
+       update_state_fb(primary);
+       obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
 }
 
 static void i9xx_update_primary_plane(struct drm_crtc *crtc,
@@ -2576,9 +2778,6 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
 
        I915_WRITE(reg, dspcntr);
 
-       DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
-                     i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
-                     fb->pitches[0]);
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        if (INTEL_INFO(dev)->gen >= 4) {
                I915_WRITE(DSPSURF(plane),
@@ -2680,9 +2879,6 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
 
        I915_WRITE(reg, dspcntr);
 
-       DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
-                     i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
-                     fb->pitches[0]);
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        I915_WRITE(DSPSURF(plane),
                   i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
@@ -2695,6 +2891,51 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
        POSTING_READ(reg);
 }
 
+u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier,
+                             uint32_t pixel_format)
+{
+       u32 bits_per_pixel = drm_format_plane_cpp(pixel_format, 0) * 8;
+
+       /*
+        * The stride is either expressed as a multiple of 64 bytes
+        * chunks for linear buffers or in number of tiles for tiled
+        * buffers.
+        */
+       switch (fb_modifier) {
+       case DRM_FORMAT_MOD_NONE:
+               return 64;
+       case I915_FORMAT_MOD_X_TILED:
+               if (INTEL_INFO(dev)->gen == 2)
+                       return 128;
+               return 512;
+       case I915_FORMAT_MOD_Y_TILED:
+               /* No need to check for old gens and Y tiling since this is
+                * about the display engine and those will be blocked before
+                * we get here.
+                */
+               return 128;
+       case I915_FORMAT_MOD_Yf_TILED:
+               if (bits_per_pixel == 8)
+                       return 64;
+               else
+                       return 128;
+       default:
+               MISSING_CASE(fb_modifier);
+               return 64;
+       }
+}
+
+unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
+                                    struct drm_i915_gem_object *obj)
+{
+       const struct i915_ggtt_view *view = &i915_ggtt_view_normal;
+
+       if (intel_rotation_90_or_270(intel_plane->base.state->rotation))
+               view = &i915_ggtt_view_rotated;
+
+       return i915_gem_obj_ggtt_offset_view(obj, view);
+}
+
 static void skylake_update_primary_plane(struct drm_crtc *crtc,
                                         struct drm_framebuffer *fb,
                                         int x, int y)
@@ -2702,10 +2943,10 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_framebuffer *intel_fb;
        struct drm_i915_gem_object *obj;
        int pipe = intel_crtc->pipe;
-       u32 plane_ctl, stride;
+       u32 plane_ctl, stride_div;
+       unsigned long surf_addr;
 
        if (!intel_crtc->primary_enabled) {
                I915_WRITE(PLANE_CTL(pipe, 0), 0);
@@ -2725,10 +2966,19 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
        case DRM_FORMAT_XRGB8888:
                plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
                break;
+       case DRM_FORMAT_ARGB8888:
+               plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
+               plane_ctl |= PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+               break;
        case DRM_FORMAT_XBGR8888:
                plane_ctl |= PLANE_CTL_ORDER_RGBX;
                plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
                break;
+       case DRM_FORMAT_ABGR8888:
+               plane_ctl |= PLANE_CTL_ORDER_RGBX;
+               plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
+               plane_ctl |= PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+               break;
        case DRM_FORMAT_XRGB2101010:
                plane_ctl |= PLANE_CTL_FORMAT_XRGB_2101010;
                break;
@@ -2740,43 +2990,39 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
                BUG();
        }
 
-       intel_fb = to_intel_framebuffer(fb);
-       obj = intel_fb->obj;
-
-       /*
-        * The stride is either expressed as a multiple of 64 bytes chunks for
-        * linear buffers or in number of tiles for tiled buffers.
-        */
-       switch (obj->tiling_mode) {
-       case I915_TILING_NONE:
-               stride = fb->pitches[0] >> 6;
+       switch (fb->modifier[0]) {
+       case DRM_FORMAT_MOD_NONE:
                break;
-       case I915_TILING_X:
+       case I915_FORMAT_MOD_X_TILED:
                plane_ctl |= PLANE_CTL_TILED_X;
-               stride = fb->pitches[0] >> 9;
+               break;
+       case I915_FORMAT_MOD_Y_TILED:
+               plane_ctl |= PLANE_CTL_TILED_Y;
+               break;
+       case I915_FORMAT_MOD_Yf_TILED:
+               plane_ctl |= PLANE_CTL_TILED_YF;
                break;
        default:
-               BUG();
+               MISSING_CASE(fb->modifier[0]);
        }
 
        plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
        if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180))
                plane_ctl |= PLANE_CTL_ROTATE_180;
 
-       I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
-
-       DRM_DEBUG_KMS("Writing base %08lX %d,%d,%d,%d pitch=%d\n",
-                     i915_gem_obj_ggtt_offset(obj),
-                     x, y, fb->width, fb->height,
-                     fb->pitches[0]);
+       obj = intel_fb_obj(fb);
+       stride_div = intel_fb_stride_alignment(dev, fb->modifier[0],
+                                              fb->pixel_format);
+       surf_addr = intel_plane_obj_offset(to_intel_plane(crtc->primary), obj);
 
+       I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
        I915_WRITE(PLANE_POS(pipe, 0), 0);
        I915_WRITE(PLANE_OFFSET(pipe, 0), (y << 16) | x);
        I915_WRITE(PLANE_SIZE(pipe, 0),
                   (intel_crtc->config->pipe_src_h - 1) << 16 |
                   (intel_crtc->config->pipe_src_w - 1));
-       I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
-       I915_WRITE(PLANE_SURF(pipe, 0), i915_gem_obj_ggtt_offset(obj));
+       I915_WRITE(PLANE_STRIDE(pipe, 0), fb->pitches[0] / stride_div);
+       I915_WRITE(PLANE_SURF(pipe, 0), surf_addr);
 
        POSTING_READ(PLANE_SURF(pipe, 0));
 }
@@ -3027,38 +3273,6 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
                           FDI_FE_ERRC_ENABLE);
 }
 
-static bool pipe_has_enabled_pch(struct intel_crtc *crtc)
-{
-       return crtc->base.enabled && crtc->active &&
-               crtc->config->has_pch_encoder;
-}
-
-static void ivb_modeset_global_resources(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *pipe_B_crtc =
-               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]);
-       struct intel_crtc *pipe_C_crtc =
-               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_C]);
-       uint32_t temp;
-
-       /*
-        * When everything is off disable fdi C so that we could enable fdi B
-        * with all lanes. Note that we don't care about enabled pipes without
-        * an enabled pch encoder.
-        */
-       if (!pipe_has_enabled_pch(pipe_B_crtc) &&
-           !pipe_has_enabled_pch(pipe_C_crtc)) {
-               WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE);
-               WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE);
-
-               temp = I915_READ(SOUTH_CHICKEN1);
-               temp &= ~FDI_BC_BIFURCATION_SELECT;
-               DRM_DEBUG_KMS("disabling fdi C rx\n");
-               I915_WRITE(SOUTH_CHICKEN1, temp);
-       }
-}
-
 /* The FDI link training functions for ILK/Ibexpeak. */
 static void ironlake_fdi_link_train(struct drm_crtc *crtc)
 {
@@ -3714,20 +3928,23 @@ static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
                   I915_READ(VSYNCSHIFT(cpu_transcoder)));
 }
 
-static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev)
+static void cpt_set_fdi_bc_bifurcation(struct drm_device *dev, bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t temp;
 
        temp = I915_READ(SOUTH_CHICKEN1);
-       if (temp & FDI_BC_BIFURCATION_SELECT)
+       if (!!(temp & FDI_BC_BIFURCATION_SELECT) == enable)
                return;
 
        WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE);
        WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE);
 
-       temp |= FDI_BC_BIFURCATION_SELECT;
-       DRM_DEBUG_KMS("enabling fdi C rx\n");
+       temp &= ~FDI_BC_BIFURCATION_SELECT;
+       if (enable)
+               temp |= FDI_BC_BIFURCATION_SELECT;
+
+       DRM_DEBUG_KMS("%sabling fdi C rx\n", enable ? "en" : "dis");
        I915_WRITE(SOUTH_CHICKEN1, temp);
        POSTING_READ(SOUTH_CHICKEN1);
 }
@@ -3735,20 +3952,19 @@ static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev)
 static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc)
 {
        struct drm_device *dev = intel_crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
 
        switch (intel_crtc->pipe) {
        case PIPE_A:
                break;
        case PIPE_B:
                if (intel_crtc->config->fdi_lanes > 2)
-                       WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT);
+                       cpt_set_fdi_bc_bifurcation(dev, false);
                else
-                       cpt_enable_fdi_bc_bifurcation(dev);
+                       cpt_set_fdi_bc_bifurcation(dev, true);
 
                break;
        case PIPE_C:
-               cpt_enable_fdi_bc_bifurcation(dev);
+               cpt_set_fdi_bc_bifurcation(dev, true);
 
                break;
        default:
@@ -4083,6 +4299,24 @@ static void intel_enable_sprite_planes(struct drm_crtc *crtc)
        }
 }
 
+/*
+ * Disable a plane internally without actually modifying the plane's state.
+ * This will allow us to easily restore the plane later by just reprogramming
+ * its state.
+ */
+static void disable_plane_internal(struct drm_plane *plane)
+{
+       struct intel_plane *intel_plane = to_intel_plane(plane);
+       struct drm_plane_state *state =
+               plane->funcs->atomic_duplicate_state(plane);
+       struct intel_plane_state *intel_state = to_intel_plane_state(state);
+
+       intel_state->visible = false;
+       intel_plane->commit_plane(plane, intel_state);
+
+       intel_plane_destroy_state(plane, state);
+}
+
 static void intel_disable_sprite_planes(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -4092,8 +4326,8 @@ static void intel_disable_sprite_planes(struct drm_crtc *crtc)
 
        drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
                intel_plane = to_intel_plane(plane);
-               if (intel_plane->pipe == pipe)
-                       plane->funcs->disable_plane(plane);
+               if (plane->fb && intel_plane->pipe == pipe)
+                       disable_plane_internal(plane);
        }
 }
 
@@ -4167,7 +4401,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
        bool reenable_ips = false;
 
        /* The clocks have to be on to load the palette. */
-       if (!crtc->enabled || !intel_crtc->active)
+       if (!crtc->state->enable || !intel_crtc->active)
                return;
 
        if (!HAS_PCH_SPLIT(dev_priv->dev)) {
@@ -4251,11 +4485,10 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
 
        intel_crtc_wait_for_pending_flips(crtc);
 
-       if (dev_priv->fbc.plane == plane)
+       if (dev_priv->fbc.crtc == intel_crtc)
                intel_fbc_disable(dev);
 
        hsw_disable_ips(intel_crtc);
@@ -4281,7 +4514,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
 
-       WARN_ON(!crtc->enabled);
+       WARN_ON(!crtc->state->enable);
 
        if (intel_crtc->active)
                return;
@@ -4290,7 +4523,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                intel_prepare_shared_dpll(intel_crtc);
 
        if (intel_crtc->config->has_dp_encoder)
-               intel_dp_set_m_n(intel_crtc);
+               intel_dp_set_m_n(intel_crtc, M1_N1);
 
        intel_set_pipe_timings(intel_crtc);
 
@@ -4389,7 +4622,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
 
-       WARN_ON(!crtc->enabled);
+       WARN_ON(!crtc->state->enable);
 
        if (intel_crtc->active)
                return;
@@ -4398,7 +4631,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
                intel_enable_shared_dpll(intel_crtc);
 
        if (intel_crtc->config->has_dp_encoder)
-               intel_dp_set_m_n(intel_crtc);
+               intel_dp_set_m_n(intel_crtc, M1_N1);
 
        intel_set_pipe_timings(intel_crtc);
 
@@ -4723,8 +4956,9 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
        return mask;
 }
 
-static void modeset_update_crtc_power_domains(struct drm_device *dev)
+static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
 {
+       struct drm_device *dev = state->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long pipe_domains[I915_MAX_PIPES] = { 0, };
        struct intel_crtc *crtc;
@@ -4736,7 +4970,7 @@ static void modeset_update_crtc_power_domains(struct drm_device *dev)
        for_each_intel_crtc(dev, crtc) {
                enum intel_display_power_domain domain;
 
-               if (!crtc->base.enabled)
+               if (!crtc->base.state->enable)
                        continue;
 
                pipe_domains[crtc->pipe] = get_crtc_power_domains(&crtc->base);
@@ -4746,7 +4980,7 @@ static void modeset_update_crtc_power_domains(struct drm_device *dev)
        }
 
        if (dev_priv->display.modeset_global_resources)
-               dev_priv->display.modeset_global_resources(dev);
+               dev_priv->display.modeset_global_resources(state);
 
        for_each_intel_crtc(dev, crtc) {
                enum intel_display_power_domain domain;
@@ -4863,24 +5097,23 @@ static void cherryview_set_cdclk(struct drm_device *dev, int cdclk)
        WARN_ON(dev_priv->display.get_display_clock_speed(dev) != dev_priv->vlv_cdclk_freq);
 
        switch (cdclk) {
-       case 400000:
-               cmd = 3;
-               break;
        case 333333:
        case 320000:
-               cmd = 2;
-               break;
        case 266667:
-               cmd = 1;
-               break;
        case 200000:
-               cmd = 0;
                break;
        default:
                MISSING_CASE(cdclk);
                return;
        }
 
+       /*
+        * Specs are full of misinformation, but testing on actual
+        * hardware has shown that we just need to write the desired
+        * CCK divider into the Punit register.
+        */
+       cmd = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1;
+
        mutex_lock(&dev_priv->rps.hw_lock);
        val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
        val &= ~DSPFREQGUAR_MASK_CHV;
@@ -4900,27 +5133,25 @@ static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv,
                                 int max_pixclk)
 {
        int freq_320 = (dev_priv->hpll_freq <<  1) % 320000 != 0 ? 333333 : 320000;
-
-       /* FIXME: Punit isn't quite ready yet */
-       if (IS_CHERRYVIEW(dev_priv->dev))
-               return 400000;
+       int limit = IS_CHERRYVIEW(dev_priv) ? 95 : 90;
 
        /*
         * Really only a few cases to deal with, as only 4 CDclks are supported:
         *   200MHz
         *   267MHz
         *   320/333MHz (depends on HPLL freq)
-        *   400MHz
-        * So we check to see whether we're above 90% of the lower bin and
-        * adjust if needed.
+        *   400MHz (VLV only)
+        * So we check to see whether we're above 90% (VLV) or 95% (CHV)
+        * of the lower bin and adjust if needed.
         *
         * We seem to get an unstable or solid color picture at 200MHz.
         * Not sure what's wrong. For now use 200MHz only when all pipes
         * are off.
         */
-       if (max_pixclk > freq_320*9/10)
+       if (!IS_CHERRYVIEW(dev_priv) &&
+           max_pixclk > freq_320*limit/100)
                return 400000;
-       else if (max_pixclk > 266667*9/10)
+       else if (max_pixclk > 266667*limit/100)
                return freq_320;
        else if (max_pixclk > 0)
                return 266667;
@@ -4957,12 +5188,49 @@ static void valleyview_modeset_global_pipes(struct drm_device *dev,
 
        /* disable/enable all currently active pipes while we change cdclk */
        for_each_intel_crtc(dev, intel_crtc)
-               if (intel_crtc->base.enabled)
+               if (intel_crtc->base.state->enable)
                        *prepare_pipes |= (1 << intel_crtc->pipe);
 }
 
-static void valleyview_modeset_global_resources(struct drm_device *dev)
+static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
+{
+       unsigned int credits, default_credits;
+
+       if (IS_CHERRYVIEW(dev_priv))
+               default_credits = PFI_CREDIT(12);
+       else
+               default_credits = PFI_CREDIT(8);
+
+       if (DIV_ROUND_CLOSEST(dev_priv->vlv_cdclk_freq, 1000) >= dev_priv->rps.cz_freq) {
+               /* CHV suggested value is 31 or 63 */
+               if (IS_CHERRYVIEW(dev_priv))
+                       credits = PFI_CREDIT_31;
+               else
+                       credits = PFI_CREDIT(15);
+       } else {
+               credits = default_credits;
+       }
+
+       /*
+        * WA - write default credits before re-programming
+        * FIXME: should we also set the resend bit here?
+        */
+       I915_WRITE(GCI_CONTROL, VGA_FAST_MODE_DISABLE |
+                  default_credits);
+
+       I915_WRITE(GCI_CONTROL, VGA_FAST_MODE_DISABLE |
+                  credits | PFI_CREDIT_RESEND);
+
+       /*
+        * FIXME is this guaranteed to clear
+        * immediately or should we poll for it?
+        */
+       WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND);
+}
+
+static void valleyview_modeset_global_resources(struct drm_atomic_state *state)
 {
+       struct drm_device *dev = state->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int max_pixclk = intel_mode_max_pixclk(dev_priv);
        int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
@@ -4984,6 +5252,8 @@ static void valleyview_modeset_global_resources(struct drm_device *dev)
                else
                        valleyview_set_cdclk(dev, req_cdclk);
 
+               vlv_program_pfi_credits(dev_priv);
+
                intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
        }
 }
@@ -4997,7 +5267,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
        int pipe = intel_crtc->pipe;
        bool is_dsi;
 
-       WARN_ON(!crtc->enabled);
+       WARN_ON(!crtc->state->enable);
 
        if (intel_crtc->active)
                return;
@@ -5012,7 +5282,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
        }
 
        if (intel_crtc->config->has_dp_encoder)
-               intel_dp_set_m_n(intel_crtc);
+               intel_dp_set_m_n(intel_crtc, M1_N1);
 
        intel_set_pipe_timings(intel_crtc);
 
@@ -5080,7 +5350,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
 
-       WARN_ON(!crtc->enabled);
+       WARN_ON(!crtc->state->enable);
 
        if (intel_crtc->active)
                return;
@@ -5088,7 +5358,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
        i9xx_set_pll_dividers(intel_crtc);
 
        if (intel_crtc->config->has_dp_encoder)
-               intel_dp_set_m_n(intel_crtc);
+               intel_dp_set_m_n(intel_crtc, M1_N1);
 
        intel_set_pipe_timings(intel_crtc);
 
@@ -5279,7 +5549,7 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        /* crtc should still be enabled when we disable it. */
-       WARN_ON(!crtc->enabled);
+       WARN_ON(!crtc->state->enable);
 
        dev_priv->display.crtc_disable(crtc);
        dev_priv->display.off(crtc);
@@ -5357,7 +5627,8 @@ static void intel_connector_check_state(struct intel_connector *connector)
 
                        crtc = encoder->base.crtc;
 
-                       I915_STATE_WARN(!crtc->enabled, "crtc not enabled\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");
@@ -5396,13 +5667,21 @@ bool intel_connector_get_hw_state(struct intel_connector *connector)
        return encoder->get_hw_state(encoder, &pipe);
 }
 
+static int pipe_required_fdi_lanes(struct drm_device *dev, enum pipe pipe)
+{
+       struct intel_crtc *crtc =
+               to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
+
+       if (crtc->base.state->enable &&
+           crtc->config->has_pch_encoder)
+               return crtc->config->fdi_lanes;
+
+       return 0;
+}
+
 static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
                                     struct intel_crtc_state *pipe_config)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *pipe_B_crtc =
-               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]);
-
        DRM_DEBUG_KMS("checking fdi config on pipe %c, lanes %i\n",
                      pipe_name(pipe), pipe_config->fdi_lanes);
        if (pipe_config->fdi_lanes > 4) {
@@ -5429,22 +5708,20 @@ static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
        case PIPE_A:
                return true;
        case PIPE_B:
-               if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled &&
-                   pipe_config->fdi_lanes > 2) {
+               if (pipe_config->fdi_lanes > 2 &&
+                   pipe_required_fdi_lanes(dev, PIPE_C) > 0) {
                        DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n",
                                      pipe_name(pipe), pipe_config->fdi_lanes);
                        return false;
                }
                return true;
        case PIPE_C:
-               if (!pipe_has_enabled_pch(pipe_B_crtc) ||
-                   pipe_B_crtc->config->fdi_lanes <= 2) {
-                       if (pipe_config->fdi_lanes > 2) {
-                               DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n",
-                                             pipe_name(pipe), pipe_config->fdi_lanes);
-                               return false;
-                       }
-               } else {
+               if (pipe_config->fdi_lanes > 2) {
+                       DRM_DEBUG_KMS("only 2 lanes on pipe %c: required %i lanes\n",
+                                     pipe_name(pipe), pipe_config->fdi_lanes);
+                       return false;
+               }
+               if (pipe_required_fdi_lanes(dev, PIPE_B) > 2) {
                        DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n");
                        return false;
                }
@@ -5544,7 +5821,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
         * - LVDS dual channel mode
         * - Double wide pipe
         */
-       if ((intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+       if ((intel_pipe_will_have_type(pipe_config, INTEL_OUTPUT_LVDS) &&
             intel_is_dual_link_lvds(dev)) || pipe_config->double_wide)
                pipe_config->pipe_src_w &= ~1;
 
@@ -5578,10 +5855,6 @@ static int valleyview_get_display_clock_speed(struct drm_device *dev)
        u32 val;
        int divider;
 
-       /* FIXME: Punit isn't quite ready yet */
-       if (IS_CHERRYVIEW(dev))
-               return 400000;
-
        if (dev_priv->hpll_freq == 0)
                dev_priv->hpll_freq = valleyview_get_vco(dev_priv);
 
@@ -5727,15 +6000,18 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
                && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
 }
 
-static int i9xx_get_refclk(struct intel_crtc *crtc, int num_connectors)
+static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
+                          int num_connectors)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int refclk;
 
+       WARN_ON(!crtc_state->base.state);
+
        if (IS_VALLEYVIEW(dev)) {
                refclk = 100000;
-       } else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
+       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
            intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
                refclk = dev_priv->vbt.lvds_ssc_freq;
                DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
@@ -5778,8 +6054,8 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
        crtc_state->dpll_hw_state.fp0 = fp;
 
        crtc->lowfreq_avail = false;
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
-           reduced_clock && i915.powersave) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
+           reduced_clock) {
                crtc_state->dpll_hw_state.fp1 = fp2;
                crtc->lowfreq_avail = true;
        } else {
@@ -5847,7 +6123,7 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
                 * for gen < 8) and if DRRS is supported (to make sure the
                 * registers are not unnecessarily accessed).
                 */
-               if (m2_n2 && INTEL_INFO(dev)->gen < 8 &&
+               if (m2_n2 && (IS_CHERRYVIEW(dev) || INTEL_INFO(dev)->gen < 8) &&
                        crtc->config->has_drrs) {
                        I915_WRITE(PIPE_DATA_M2(transcoder),
                                        TU_SIZE(m2_n2->tu) | m2_n2->gmch_m);
@@ -5863,13 +6139,29 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
        }
 }
 
-void intel_dp_set_m_n(struct intel_crtc *crtc)
+void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n)
 {
+       struct intel_link_m_n *dp_m_n, *dp_m2_n2 = NULL;
+
+       if (m_n == M1_N1) {
+               dp_m_n = &crtc->config->dp_m_n;
+               dp_m2_n2 = &crtc->config->dp_m2_n2;
+       } else if (m_n == M2_N2) {
+
+               /*
+                * M2_N2 registers are not supported. Hence m2_n2 divider value
+                * needs to be programmed into M1_N1.
+                */
+               dp_m_n = &crtc->config->dp_m2_n2;
+       } else {
+               DRM_ERROR("Unsupported divider value\n");
+               return;
+       }
+
        if (crtc->config->has_pch_encoder)
                intel_pch_transcoder_set_m_n(crtc, &crtc->config->dp_m_n);
        else
-               intel_cpu_transcoder_set_m_n(crtc, &crtc->config->dp_m_n,
-                                                  &crtc->config->dp_m2_n2);
+               intel_cpu_transcoder_set_m_n(crtc, dp_m_n, dp_m2_n2);
 }
 
 static void vlv_update_pll(struct intel_crtc *crtc,
@@ -6007,9 +6299,10 @@ static void chv_prepare_pll(struct intel_crtc *crtc,
        int pipe = crtc->pipe;
        int dpll_reg = DPLL(crtc->pipe);
        enum dpio_channel port = vlv_pipe_to_channel(pipe);
-       u32 loopfilter, intcoeff;
+       u32 loopfilter, tribuf_calcntr;
        u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac;
-       int refclk;
+       u32 dpio_val;
+       int vco;
 
        bestn = pipe_config->dpll.n;
        bestm2_frac = pipe_config->dpll.m2 & 0x3fffff;
@@ -6017,6 +6310,9 @@ static void chv_prepare_pll(struct intel_crtc *crtc,
        bestm2 = pipe_config->dpll.m2 >> 22;
        bestp1 = pipe_config->dpll.p1;
        bestp2 = pipe_config->dpll.p2;
+       vco = pipe_config->dpll.vco;
+       dpio_val = 0;
+       loopfilter = 0;
 
        /*
         * Enable Refclk and SSC
@@ -6042,26 +6338,56 @@ static void chv_prepare_pll(struct intel_crtc *crtc,
                        1 << DPIO_CHV_N_DIV_SHIFT);
 
        /* M2 fraction division */
-       vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac);
+       if (bestm2_frac)
+               vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac);
 
        /* M2 fraction division enable */
-       vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW3(port),
-                      DPIO_CHV_FRAC_DIV_EN |
-                      (2 << DPIO_CHV_FEEDFWD_GAIN_SHIFT));
+       dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port));
+       dpio_val &= ~(DPIO_CHV_FEEDFWD_GAIN_MASK | DPIO_CHV_FRAC_DIV_EN);
+       dpio_val |= (2 << DPIO_CHV_FEEDFWD_GAIN_SHIFT);
+       if (bestm2_frac)
+               dpio_val |= DPIO_CHV_FRAC_DIV_EN;
+       vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW3(port), dpio_val);
+
+       /* Program digital lock detect threshold */
+       dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW9(port));
+       dpio_val &= ~(DPIO_CHV_INT_LOCK_THRESHOLD_MASK |
+                                       DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE);
+       dpio_val |= (0x5 << DPIO_CHV_INT_LOCK_THRESHOLD_SHIFT);
+       if (!bestm2_frac)
+               dpio_val |= DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE;
+       vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW9(port), dpio_val);
 
        /* Loop filter */
-       refclk = i9xx_get_refclk(crtc, 0);
-       loopfilter = 5 << DPIO_CHV_PROP_COEFF_SHIFT |
-               2 << DPIO_CHV_GAIN_CTRL_SHIFT;
-       if (refclk == 100000)
-               intcoeff = 11;
-       else if (refclk == 38400)
-               intcoeff = 10;
-       else
-               intcoeff = 9;
-       loopfilter |= intcoeff << DPIO_CHV_INT_COEFF_SHIFT;
+       if (vco == 5400000) {
+               loopfilter |= (0x3 << DPIO_CHV_PROP_COEFF_SHIFT);
+               loopfilter |= (0x8 << DPIO_CHV_INT_COEFF_SHIFT);
+               loopfilter |= (0x1 << DPIO_CHV_GAIN_CTRL_SHIFT);
+               tribuf_calcntr = 0x9;
+       } else if (vco <= 6200000) {
+               loopfilter |= (0x5 << DPIO_CHV_PROP_COEFF_SHIFT);
+               loopfilter |= (0xB << DPIO_CHV_INT_COEFF_SHIFT);
+               loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT);
+               tribuf_calcntr = 0x9;
+       } else if (vco <= 6480000) {
+               loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT);
+               loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT);
+               loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT);
+               tribuf_calcntr = 0x8;
+       } else {
+               /* Not supported. Apply the same limits as in the max case */
+               loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT);
+               loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT);
+               loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT);
+               tribuf_calcntr = 0;
+       }
        vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW6(port), loopfilter);
 
+       dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW8(port));
+       dpio_val &= ~DPIO_CHV_TDC_TARGET_CNT_MASK;
+       dpio_val |= (tribuf_calcntr << DPIO_CHV_TDC_TARGET_CNT_SHIFT);
+       vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW8(port), dpio_val);
+
        /* AFC Recal */
        vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port),
                        vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) |
@@ -6086,6 +6412,7 @@ void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
        struct intel_crtc *crtc =
                to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
        struct intel_crtc_state pipe_config = {
+               .base.crtc = &crtc->base,
                .pixel_multiplier = 1,
                .dpll = *dpll,
        };
@@ -6130,12 +6457,12 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
 
        i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
 
-       is_sdvo = intel_pipe_will_have_type(crtc, INTEL_OUTPUT_SDVO) ||
-               intel_pipe_will_have_type(crtc, INTEL_OUTPUT_HDMI);
+       is_sdvo = intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_SDVO) ||
+               intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_HDMI);
 
        dpll = DPLL_VGA_MODE_DIS;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS))
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
                dpll |= DPLLB_MODE_LVDS;
        else
                dpll |= DPLLB_MODE_DAC_SERIAL;
@@ -6178,7 +6505,7 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
 
        if (crtc_state->sdvo_tv_clock)
                dpll |= PLL_REF_INPUT_TVCLKINBC;
-       else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
+       else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
                 intel_panel_use_ssc(dev_priv) && num_connectors < 2)
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
@@ -6208,7 +6535,7 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
 
        dpll = DPLL_VGA_MODE_DIS;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
                dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
        } else {
                if (clock->p1 == 2)
@@ -6219,10 +6546,10 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
                        dpll |= PLL_P2_DIVIDE_BY_4;
        }
 
-       if (!IS_I830(dev) && intel_pipe_will_have_type(crtc, INTEL_OUTPUT_DVO))
+       if (!IS_I830(dev) && intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_DVO))
                dpll |= DPLL_DVO_2X_MODE;
 
-       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
                 intel_panel_use_ssc(dev_priv) && num_connectors < 2)
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
@@ -6436,11 +6763,20 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
        bool is_lvds = false, is_dsi = false;
        struct intel_encoder *encoder;
        const intel_limit_t *limit;
+       struct drm_atomic_state *state = crtc_state->base.state;
+       struct drm_connector_state *connector_state;
+       int i;
 
-       for_each_intel_encoder(dev, encoder) {
-               if (encoder->new_crtc != crtc)
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
+                       continue;
+
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != &crtc->base)
                        continue;
 
+               encoder = to_intel_encoder(connector_state->best_encoder);
+
                switch (encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
@@ -6459,7 +6795,7 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
                return 0;
 
        if (!crtc_state->clock_set) {
-               refclk = i9xx_get_refclk(crtc, num_connectors);
+               refclk = i9xx_get_refclk(crtc_state, num_connectors);
 
                /*
                 * Returns a set of divisors for the desired target clock with
@@ -6467,8 +6803,8 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
                 * the clock equation: reflck * (5 * (m1 + 2) + (m2 + 2)) / (n +
                 * 2) / p1 / p2.
                 */
-               limit = intel_limit(crtc, refclk);
-               ok = dev_priv->display.find_dpll(limit, crtc,
+               limit = intel_limit(crtc_state, refclk);
+               ok = dev_priv->display.find_dpll(limit, crtc_state,
                                                 crtc_state->port_clock,
                                                 refclk, NULL, &clock);
                if (!ok) {
@@ -6484,7 +6820,7 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
                         * we will disable the LVDS downclock feature.
                         */
                        has_reduced_clock =
-                               dev_priv->display.find_dpll(limit, crtc,
+                               dev_priv->display.find_dpll(limit, crtc_state,
                                                            dev_priv->lvds_downclock,
                                                            refclk, &clock,
                                                            &reduced_clock);
@@ -6583,10 +6919,14 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc,
        u32 val, base, offset;
        int pipe = crtc->pipe, plane = crtc->plane;
        int fourcc, pixel_format;
-       int aligned_height;
+       unsigned int aligned_height;
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
 
+       val = I915_READ(DSPCNTR(plane));
+       if (!(val & DISPLAY_PLANE_ENABLE))
+               return;
+
        intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
        if (!intel_fb) {
                DRM_DEBUG_KMS("failed to alloc fb\n");
@@ -6595,11 +6935,12 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc,
 
        fb = &intel_fb->base;
 
-       val = I915_READ(DSPCNTR(plane));
-
-       if (INTEL_INFO(dev)->gen >= 4)
-               if (val & DISPPLANE_TILED)
+       if (INTEL_INFO(dev)->gen >= 4) {
+               if (val & DISPPLANE_TILED) {
                        plane_config->tiling = I915_TILING_X;
+                       fb->modifier[0] = I915_FORMAT_MOD_X_TILED;
+               }
+       }
 
        pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
        fourcc = i9xx_format_to_fourcc(pixel_format);
@@ -6625,16 +6966,17 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc,
        fb->pitches[0] = val & 0xffffffc0;
 
        aligned_height = intel_fb_align_height(dev, fb->height,
-                                              plane_config->tiling);
+                                              fb->pixel_format,
+                                              fb->modifier[0]);
 
-       plane_config->size = PAGE_ALIGN(fb->pitches[0] * aligned_height);
+       plane_config->size = fb->pitches[0] * aligned_height;
 
        DRM_DEBUG_KMS("pipe/plane %c/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
                      pipe_name(pipe), plane, fb->width, fb->height,
                      fb->bits_per_pixel, base, fb->pitches[0],
                      plane_config->size);
 
-       crtc->base.primary->fb = fb;
+       plane_config->fb = intel_fb;
 }
 
 static void chv_crtc_clock_get(struct intel_crtc *crtc,
@@ -7108,18 +7450,26 @@ void intel_init_pch_refclk(struct drm_device *dev)
                lpt_init_pch_refclk(dev);
 }
 
-static int ironlake_get_refclk(struct drm_crtc *crtc)
+static int ironlake_get_refclk(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_atomic_state *state = crtc_state->base.state;
+       struct drm_connector_state *connector_state;
        struct intel_encoder *encoder;
-       int num_connectors = 0;
+       int num_connectors = 0, i;
        bool is_lvds = false;
 
-       for_each_intel_encoder(dev, encoder) {
-               if (encoder->new_crtc != to_intel_crtc(crtc))
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
                        continue;
 
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != crtc_state->base.crtc)
+                       continue;
+
+               encoder = to_intel_encoder(connector_state->best_encoder);
+
                switch (encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
@@ -7306,22 +7656,21 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int refclk;
        const intel_limit_t *limit;
        bool ret, is_lvds = false;
 
-       is_lvds = intel_pipe_will_have_type(intel_crtc, INTEL_OUTPUT_LVDS);
+       is_lvds = intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS);
 
-       refclk = ironlake_get_refclk(crtc);
+       refclk = ironlake_get_refclk(crtc_state);
 
        /*
         * Returns a set of divisors for the desired target clock with the given
         * refclk, or FALSE.  The returned values represent the clock equation:
         * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
         */
-       limit = intel_limit(intel_crtc, refclk);
-       ret = dev_priv->display.find_dpll(limit, intel_crtc,
+       limit = intel_limit(crtc_state, refclk);
+       ret = dev_priv->display.find_dpll(limit, crtc_state,
                                          crtc_state->port_clock,
                                          refclk, NULL, clock);
        if (!ret)
@@ -7335,7 +7684,7 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
                 * downclock feature.
                */
                *has_reduced_clock =
-                       dev_priv->display.find_dpll(limit, intel_crtc,
+                       dev_priv->display.find_dpll(limit, crtc_state,
                                                    dev_priv->lvds_downclock,
                                                    refclk, clock,
                                                    reduced_clock);
@@ -7368,16 +7717,24 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
        struct drm_crtc *crtc = &intel_crtc->base;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *intel_encoder;
+       struct drm_atomic_state *state = crtc_state->base.state;
+       struct drm_connector_state *connector_state;
+       struct intel_encoder *encoder;
        uint32_t dpll;
-       int factor, num_connectors = 0;
+       int factor, num_connectors = 0, i;
        bool is_lvds = false, is_sdvo = false;
 
-       for_each_intel_encoder(dev, intel_encoder) {
-               if (intel_encoder->new_crtc != to_intel_crtc(crtc))
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
+                       continue;
+
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != crtc_state->base.crtc)
                        continue;
 
-               switch (intel_encoder->type) {
+               encoder = to_intel_encoder(connector_state->best_encoder);
+
+               switch (encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
                        break;
@@ -7506,7 +7863,7 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
                }
        }
 
-       if (is_lvds && has_reduced_clock && i915.powersave)
+       if (is_lvds && has_reduced_clock)
                crtc->lowfreq_avail = true;
        else
                crtc->lowfreq_avail = false;
@@ -7612,10 +7969,10 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 val, base, offset, stride_mult;
+       u32 val, base, offset, stride_mult, tiling;
        int pipe = crtc->pipe;
        int fourcc, pixel_format;
-       int aligned_height;
+       unsigned int aligned_height;
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
 
@@ -7628,8 +7985,8 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
        fb = &intel_fb->base;
 
        val = I915_READ(PLANE_CTL(pipe, 0));
-       if (val & PLANE_CTL_TILED_MASK)
-               plane_config->tiling = I915_TILING_X;
+       if (!(val & PLANE_CTL_ENABLE))
+               goto error;
 
        pixel_format = val & PLANE_CTL_FORMAT_MASK;
        fourcc = skl_format_to_fourcc(pixel_format,
@@ -7638,6 +7995,26 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
        fb->pixel_format = fourcc;
        fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8;
 
+       tiling = val & PLANE_CTL_TILED_MASK;
+       switch (tiling) {
+       case PLANE_CTL_TILED_LINEAR:
+               fb->modifier[0] = DRM_FORMAT_MOD_NONE;
+               break;
+       case PLANE_CTL_TILED_X:
+               plane_config->tiling = I915_TILING_X;
+               fb->modifier[0] = I915_FORMAT_MOD_X_TILED;
+               break;
+       case PLANE_CTL_TILED_Y:
+               fb->modifier[0] = I915_FORMAT_MOD_Y_TILED;
+               break;
+       case PLANE_CTL_TILED_YF:
+               fb->modifier[0] = I915_FORMAT_MOD_Yf_TILED;
+               break;
+       default:
+               MISSING_CASE(tiling);
+               goto error;
+       }
+
        base = I915_READ(PLANE_SURF(pipe, 0)) & 0xfffff000;
        plane_config->base = base;
 
@@ -7648,30 +8025,22 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
        fb->width = ((val >> 0) & 0x1fff) + 1;
 
        val = I915_READ(PLANE_STRIDE(pipe, 0));
-       switch (plane_config->tiling) {
-       case I915_TILING_NONE:
-               stride_mult = 64;
-               break;
-       case I915_TILING_X:
-               stride_mult = 512;
-               break;
-       default:
-               MISSING_CASE(plane_config->tiling);
-               goto error;
-       }
+       stride_mult = intel_fb_stride_alignment(dev, fb->modifier[0],
+                                               fb->pixel_format);
        fb->pitches[0] = (val & 0x3ff) * stride_mult;
 
        aligned_height = intel_fb_align_height(dev, fb->height,
-                                              plane_config->tiling);
+                                              fb->pixel_format,
+                                              fb->modifier[0]);
 
-       plane_config->size = ALIGN(fb->pitches[0] * aligned_height, PAGE_SIZE);
+       plane_config->size = fb->pitches[0] * aligned_height;
 
        DRM_DEBUG_KMS("pipe %c with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
                      pipe_name(pipe), fb->width, fb->height,
                      fb->bits_per_pixel, base, fb->pitches[0],
                      plane_config->size);
 
-       crtc->base.primary->fb = fb;
+       plane_config->fb = intel_fb;
        return;
 
 error:
@@ -7711,10 +8080,14 @@ ironlake_get_initial_plane_config(struct intel_crtc *crtc,
        u32 val, base, offset;
        int pipe = crtc->pipe;
        int fourcc, pixel_format;
-       int aligned_height;
+       unsigned int aligned_height;
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
 
+       val = I915_READ(DSPCNTR(pipe));
+       if (!(val & DISPLAY_PLANE_ENABLE))
+               return;
+
        intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
        if (!intel_fb) {
                DRM_DEBUG_KMS("failed to alloc fb\n");
@@ -7723,11 +8096,12 @@ ironlake_get_initial_plane_config(struct intel_crtc *crtc,
 
        fb = &intel_fb->base;
 
-       val = I915_READ(DSPCNTR(pipe));
-
-       if (INTEL_INFO(dev)->gen >= 4)
-               if (val & DISPPLANE_TILED)
+       if (INTEL_INFO(dev)->gen >= 4) {
+               if (val & DISPPLANE_TILED) {
                        plane_config->tiling = I915_TILING_X;
+                       fb->modifier[0] = I915_FORMAT_MOD_X_TILED;
+               }
+       }
 
        pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
        fourcc = i9xx_format_to_fourcc(pixel_format);
@@ -7753,16 +8127,17 @@ ironlake_get_initial_plane_config(struct intel_crtc *crtc,
        fb->pitches[0] = val & 0xffffffc0;
 
        aligned_height = intel_fb_align_height(dev, fb->height,
-                                              plane_config->tiling);
+                                              fb->pixel_format,
+                                              fb->modifier[0]);
 
-       plane_config->size = PAGE_ALIGN(fb->pitches[0] * aligned_height);
+       plane_config->size = fb->pitches[0] * aligned_height;
 
        DRM_DEBUG_KMS("pipe %c with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
                      pipe_name(pipe), fb->width, fb->height,
                      fb->bits_per_pixel, base, fb->pitches[0],
                      plane_config->size);
 
-       crtc->base.primary->fb = fb;
+       plane_config->fb = intel_fb;
 }
 
 static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
@@ -8248,8 +8623,8 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
        uint32_t cntl = 0, size = 0;
 
        if (base) {
-               unsigned int width = intel_crtc->cursor_width;
-               unsigned int height = intel_crtc->cursor_height;
+               unsigned int width = intel_crtc->base.cursor->state->crtc_w;
+               unsigned int height = intel_crtc->base.cursor->state->crtc_h;
                unsigned int stride = roundup_pow_of_two(width) * 4;
 
                switch (stride) {
@@ -8313,7 +8688,7 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
        cntl = 0;
        if (base) {
                cntl = MCURSOR_GAMMA_ENABLE;
-               switch (intel_crtc->cursor_width) {
+               switch (intel_crtc->base.cursor->state->crtc_w) {
                        case 64:
                                cntl |= CURSOR_MODE_64_ARGB_AX;
                                break;
@@ -8324,7 +8699,7 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
                                cntl |= CURSOR_MODE_256_ARGB_AX;
                                break;
                        default:
-                               MISSING_CASE(intel_crtc->cursor_width);
+                               MISSING_CASE(intel_crtc->base.cursor->state->crtc_w);
                                return;
                }
                cntl |= pipe << 28; /* Connect to correct pipe */
@@ -8371,7 +8746,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
                base = 0;
 
        if (x < 0) {
-               if (x + intel_crtc->cursor_width <= 0)
+               if (x + intel_crtc->base.cursor->state->crtc_w <= 0)
                        base = 0;
 
                pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
@@ -8380,7 +8755,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
        pos |= x << CURSOR_X_SHIFT;
 
        if (y < 0) {
-               if (y + intel_crtc->cursor_height <= 0)
+               if (y + intel_crtc->base.cursor->state->crtc_h <= 0)
                        base = 0;
 
                pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
@@ -8396,8 +8771,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
        /* ILK+ do this automagically */
        if (HAS_GMCH_DISPLAY(dev) &&
            crtc->cursor->state->rotation == BIT(DRM_ROTATE_180)) {
-               base += (intel_crtc->cursor_height *
-                       intel_crtc->cursor_width - 1) * 4;
+               base += (intel_crtc->base.cursor->state->crtc_h *
+                       intel_crtc->base.cursor->state->crtc_w - 1) * 4;
        }
 
        if (IS_845G(dev) || IS_I865G(dev))
@@ -8589,6 +8964,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        struct drm_device *dev = encoder->dev;
        struct drm_framebuffer *fb;
        struct drm_mode_config *config = &dev->mode_config;
+       struct drm_atomic_state *state = NULL;
+       struct drm_connector_state *connector_state;
        int ret, i = -1;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
@@ -8636,7 +9013,7 @@ retry:
                i++;
                if (!(encoder->possible_crtcs & (1 << i)))
                        continue;
-               if (possible_crtc->enabled)
+               if (possible_crtc->state->enable)
                        continue;
                /* This can occur when applying the pipe A quirk on resume. */
                if (to_intel_crtc(possible_crtc)->new_enabled)
@@ -8670,6 +9047,21 @@ retry:
        old->load_detect_temp = true;
        old->release_fb = NULL;
 
+       state = drm_atomic_state_alloc(dev);
+       if (!state)
+               return false;
+
+       state->acquire_ctx = ctx;
+
+       connector_state = drm_atomic_get_connector_state(state, connector);
+       if (IS_ERR(connector_state)) {
+               ret = PTR_ERR(connector_state);
+               goto fail;
+       }
+
+       connector_state->crtc = crtc;
+       connector_state->best_encoder = &intel_encoder->base;
+
        if (!mode)
                mode = &load_detect_mode;
 
@@ -8692,24 +9084,30 @@ retry:
                goto fail;
        }
 
-       if (intel_set_mode(crtc, mode, 0, 0, fb)) {
+       if (intel_set_mode(crtc, mode, 0, 0, fb, state)) {
                DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
                if (old->release_fb)
                        old->release_fb->funcs->destroy(old->release_fb);
                goto fail;
        }
+       crtc->primary->crtc = crtc;
 
        /* let the connector get through one full cycle before testing */
        intel_wait_for_vblank(dev, intel_crtc->pipe);
        return true;
 
  fail:
-       intel_crtc->new_enabled = crtc->enabled;
+       intel_crtc->new_enabled = crtc->state->enable;
        if (intel_crtc->new_enabled)
                intel_crtc->new_config = intel_crtc->config;
        else
                intel_crtc->new_config = NULL;
 fail_unlock:
+       if (state) {
+               drm_atomic_state_free(state);
+               state = NULL;
+       }
+
        if (ret == -EDEADLK) {
                drm_modeset_backoff(ctx);
                goto retry;
@@ -8719,24 +9117,44 @@ fail_unlock:
 }
 
 void intel_release_load_detect_pipe(struct drm_connector *connector,
-                                   struct intel_load_detect_pipe *old)
+                                   struct intel_load_detect_pipe *old,
+                                   struct drm_modeset_acquire_ctx *ctx)
 {
+       struct drm_device *dev = connector->dev;
        struct intel_encoder *intel_encoder =
                intel_attached_encoder(connector);
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = encoder->crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_atomic_state *state;
+       struct drm_connector_state *connector_state;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
                      connector->base.id, connector->name,
                      encoder->base.id, encoder->name);
 
        if (old->load_detect_temp) {
+               state = drm_atomic_state_alloc(dev);
+               if (!state)
+                       goto fail;
+
+               state->acquire_ctx = ctx;
+
+               connector_state = drm_atomic_get_connector_state(state, connector);
+               if (IS_ERR(connector_state))
+                       goto fail;
+
                to_intel_connector(connector)->new_encoder = NULL;
                intel_encoder->new_crtc = NULL;
                intel_crtc->new_enabled = false;
                intel_crtc->new_config = NULL;
-               intel_set_mode(crtc, NULL, 0, 0, NULL);
+
+               connector_state->best_encoder = NULL;
+               connector_state->crtc = NULL;
+
+               intel_set_mode(crtc, NULL, 0, 0, NULL, state);
+
+               drm_atomic_state_free(state);
 
                if (old->release_fb) {
                        drm_framebuffer_unregister_private(old->release_fb);
@@ -8749,6 +9167,11 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
        /* Switch crtc and encoder back off if necessary */
        if (old->dpms_mode != DRM_MODE_DPMS_ON)
                connector->funcs->dpms(connector, old->dpms_mode);
+
+       return;
+fail:
+       DRM_DEBUG_KMS("Couldn't release load detect pipe.\n");
+       drm_atomic_state_free(state);
 }
 
 static int i9xx_pll_refclk(struct drm_device *dev,
@@ -8987,6 +9410,8 @@ void intel_mark_busy(struct drm_device *dev)
 
        intel_runtime_pm_get(dev_priv);
        i915_update_gfx_val(dev_priv);
+       if (INTEL_INFO(dev)->gen >= 6)
+               gen6_rps_busy(dev_priv);
        dev_priv->mm.busy = true;
 }
 
@@ -9000,9 +9425,6 @@ void intel_mark_idle(struct drm_device *dev)
 
        dev_priv->mm.busy = false;
 
-       if (!i915.powersave)
-               goto out;
-
        for_each_crtc(dev, crtc) {
                if (!crtc->primary->fb)
                        continue;
@@ -9013,7 +9435,6 @@ void intel_mark_idle(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen >= 6)
                gen6_rps_idle(dev->dev_private);
 
-out:
        intel_runtime_pm_put(dev_priv);
 }
 
@@ -9055,9 +9476,8 @@ static void intel_unpin_work_fn(struct work_struct *__work)
        enum pipe pipe = to_intel_crtc(work->crtc)->pipe;
 
        mutex_lock(&dev->struct_mutex);
-       intel_unpin_fb_obj(work->old_fb_obj);
+       intel_unpin_fb_obj(work->old_fb, work->crtc->primary->state);
        drm_gem_object_unreference(&work->pending_flip_obj->base);
-       drm_gem_object_unreference(&work->old_fb_obj->base);
 
        intel_fbc_update(dev);
 
@@ -9066,6 +9486,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
        mutex_unlock(&dev->struct_mutex);
 
        intel_frontbuffer_flip_complete(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
+       drm_framebuffer_unreference(work->old_fb);
 
        BUG_ON(atomic_read(&to_intel_crtc(work->crtc)->unpin_work_count) == 0);
        atomic_dec(&to_intel_crtc(work->crtc)->unpin_work_count);
@@ -9582,69 +10003,6 @@ static int intel_queue_mmio_flip(struct drm_device *dev,
        return 0;
 }
 
-static int intel_gen9_queue_flip(struct drm_device *dev,
-                                struct drm_crtc *crtc,
-                                struct drm_framebuffer *fb,
-                                struct drm_i915_gem_object *obj,
-                                struct intel_engine_cs *ring,
-                                uint32_t flags)
-{
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t plane = 0, stride;
-       int ret;
-
-       switch(intel_crtc->pipe) {
-       case PIPE_A:
-               plane = MI_DISPLAY_FLIP_SKL_PLANE_1_A;
-               break;
-       case PIPE_B:
-               plane = MI_DISPLAY_FLIP_SKL_PLANE_1_B;
-               break;
-       case PIPE_C:
-               plane = MI_DISPLAY_FLIP_SKL_PLANE_1_C;
-               break;
-       default:
-               WARN_ONCE(1, "unknown plane in flip command\n");
-               return -ENODEV;
-       }
-
-       switch (obj->tiling_mode) {
-       case I915_TILING_NONE:
-               stride = fb->pitches[0] >> 6;
-               break;
-       case I915_TILING_X:
-               stride = fb->pitches[0] >> 9;
-               break;
-       default:
-               WARN_ONCE(1, "unknown tiling in flip command\n");
-               return -ENODEV;
-       }
-
-       ret = intel_ring_begin(ring, 10);
-       if (ret)
-               return ret;
-
-       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
-       intel_ring_emit(ring, DERRMR);
-       intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
-                               DERRMR_PIPEB_PRI_FLIP_DONE |
-                               DERRMR_PIPEC_PRI_FLIP_DONE));
-       intel_ring_emit(ring, MI_STORE_REGISTER_MEM_GEN8(1) |
-                             MI_SRM_LRM_GLOBAL_GTT);
-       intel_ring_emit(ring, DERRMR);
-       intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
-       intel_ring_emit(ring, 0);
-
-       intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane);
-       intel_ring_emit(ring, stride << 6 | obj->tiling_mode);
-       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
-
-       intel_mark_page_flip_active(intel_crtc);
-       __intel_ring_advance(ring);
-
-       return 0;
-}
-
 static int intel_default_queue_flip(struct drm_device *dev,
                                    struct drm_crtc *crtc,
                                    struct drm_framebuffer *fb,
@@ -9674,10 +10032,10 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
                    !i915_gem_request_completed(work->flip_queued_req, true))
                        return false;
 
-               work->flip_ready_vblank = drm_vblank_count(dev, intel_crtc->pipe);
+               work->flip_ready_vblank = drm_crtc_vblank_count(crtc);
        }
 
-       if (drm_vblank_count(dev, intel_crtc->pipe) - work->flip_ready_vblank < 3)
+       if (drm_crtc_vblank_count(crtc) - work->flip_ready_vblank < 3)
                return false;
 
        /* Potential stall - if we see that the flip has happened,
@@ -9700,7 +10058,7 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       WARN_ON(!in_irq());
+       WARN_ON(!in_interrupt());
 
        if (crtc == NULL)
                return;
@@ -9708,7 +10066,8 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
        spin_lock(&dev->event_lock);
        if (intel_crtc->unpin_work && __intel_pageflip_stall_check(dev, crtc)) {
                WARN_ONCE(1, "Kicking stuck page flip: queued at %d, now %d\n",
-                        intel_crtc->unpin_work->flip_queued_vblank, drm_vblank_count(dev, pipe));
+                        intel_crtc->unpin_work->flip_queued_vblank,
+                        drm_vblank_count(dev, pipe));
                page_flip_completed(intel_crtc);
        }
        spin_unlock(&dev->event_lock);
@@ -9760,7 +10119,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
        work->event = event;
        work->crtc = crtc;
-       work->old_fb_obj = intel_fb_obj(old_fb);
+       work->old_fb = old_fb;
        INIT_WORK(&work->work, intel_unpin_work_fn);
 
        ret = drm_crtc_vblank_get(crtc);
@@ -9791,18 +10150,19 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
                flush_workqueue(dev_priv->wq);
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               goto cleanup;
-
        /* Reference the objects for the scheduled work. */
-       drm_gem_object_reference(&work->old_fb_obj->base);
+       drm_framebuffer_reference(work->old_fb);
        drm_gem_object_reference(&obj->base);
 
        crtc->primary->fb = fb;
+       update_state_fb(crtc->primary);
 
        work->pending_flip_obj = obj;
 
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               goto cleanup;
+
        atomic_inc(&intel_crtc->unpin_work_count);
        intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
 
@@ -9811,7 +10171,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
        if (IS_VALLEYVIEW(dev)) {
                ring = &dev_priv->ring[BCS];
-               if (obj->tiling_mode != work->old_fb_obj->tiling_mode)
+               if (obj->tiling_mode != intel_fb_obj(work->old_fb)->tiling_mode)
                        /* vlv: DISPLAY_FLIP fails to change tiling */
                        ring = NULL;
        } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
@@ -9824,12 +10184,13 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                ring = &dev_priv->ring[RCS];
        }
 
-       ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, ring);
+       ret = intel_pin_and_fence_fb_obj(crtc->primary, fb,
+                                        crtc->primary->state, ring);
        if (ret)
                goto cleanup_pending;
 
-       work->gtt_offset =
-               i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
+       work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary), obj)
+                                                 + intel_crtc->dspaddr_offset;
 
        if (use_mmio_flip(ring, obj)) {
                ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring,
@@ -9849,10 +10210,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                                        intel_ring_get_request(ring));
        }
 
-       work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe);
+       work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
        work->enable_stall_check = true;
 
-       i915_gem_track_fb(work->old_fb_obj, obj,
+       i915_gem_track_fb(intel_fb_obj(work->old_fb), obj,
                          INTEL_FRONTBUFFER_PRIMARY(pipe));
 
        intel_fbc_disable(dev);
@@ -9864,15 +10225,17 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        return 0;
 
 cleanup_unpin:
-       intel_unpin_fb_obj(obj);
+       intel_unpin_fb_obj(fb, crtc->primary->state);
 cleanup_pending:
        atomic_dec(&intel_crtc->unpin_work_count);
-       crtc->primary->fb = old_fb;
-       drm_gem_object_unreference(&work->old_fb_obj->base);
-       drm_gem_object_unreference(&obj->base);
        mutex_unlock(&dev->struct_mutex);
-
 cleanup:
+       crtc->primary->fb = old_fb;
+       update_state_fb(crtc->primary);
+
+       drm_gem_object_unreference_unlocked(&obj->base);
+       drm_framebuffer_unreference(work->old_fb);
+
        spin_lock_irq(&dev->event_lock);
        intel_crtc->unpin_work = NULL;
        spin_unlock_irq(&dev->event_lock);
@@ -9912,8 +10275,7 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
        struct intel_encoder *encoder;
        struct intel_connector *connector;
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list,
-                           base.head) {
+       for_each_intel_connector(dev, connector) {
                connector->new_encoder =
                        to_intel_encoder(connector->base.encoder);
        }
@@ -9924,7 +10286,7 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
        }
 
        for_each_intel_crtc(dev, crtc) {
-               crtc->new_enabled = crtc->base.enabled;
+               crtc->new_enabled = crtc->base.state->enable;
 
                if (crtc->new_enabled)
                        crtc->new_config = crtc->config;
@@ -9933,6 +10295,27 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
        }
 }
 
+/* Transitional helper to copy current connector/encoder state to
+ * connector->state. This is needed so that code that is partially
+ * converted to atomic does the right thing.
+ */
+static void intel_modeset_update_connector_atomic_state(struct drm_device *dev)
+{
+       struct intel_connector *connector;
+
+       for_each_intel_connector(dev, connector) {
+               if (connector->base.encoder) {
+                       connector->base.state->best_encoder =
+                               connector->base.encoder;
+                       connector->base.state->crtc =
+                               connector->base.encoder->crtc;
+               } else {
+                       connector->base.state->best_encoder = NULL;
+                       connector->base.state->crtc = NULL;
+               }
+       }
+}
+
 /**
  * intel_modeset_commit_output_state
  *
@@ -9944,8 +10327,7 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
        struct intel_encoder *encoder;
        struct intel_connector *connector;
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list,
-                           base.head) {
+       for_each_intel_connector(dev, connector) {
                connector->base.encoder = &connector->new_encoder->base;
        }
 
@@ -9954,8 +10336,11 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
        }
 
        for_each_intel_crtc(dev, crtc) {
+               crtc->base.state->enable = crtc->new_enabled;
                crtc->base.enabled = crtc->new_enabled;
        }
+
+       intel_modeset_update_connector_atomic_state(dev);
 }
 
 static void
@@ -9990,8 +10375,9 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc,
                          struct intel_crtc_state *pipe_config)
 {
        struct drm_device *dev = crtc->base.dev;
+       struct drm_atomic_state *state;
        struct intel_connector *connector;
-       int bpp;
+       int bpp, i;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_C8:
@@ -10031,11 +10417,15 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc,
 
        pipe_config->pipe_bpp = bpp;
 
+       state = pipe_config->base.state;
+
        /* Clamp display bpp to EDID value */
-       list_for_each_entry(connector, &dev->mode_config.connector_list,
-                           base.head) {
-               if (!connector->new_encoder ||
-                   connector->new_encoder->new_crtc != crtc)
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
+                       continue;
+
+               connector = to_intel_connector(state->connectors[i]);
+               if (state->connector_states[i]->crtc != &crtc->base)
                        continue;
 
                connected_sink_compute_bpp(connector, pipe_config);
@@ -10160,8 +10550,7 @@ static bool check_digital_port_conflicts(struct drm_device *dev)
         * list to detect the problem on ddi platforms
         * where there's just one encoder per digital port.
         */
-       list_for_each_entry(connector,
-                           &dev->mode_config.connector_list, base.head) {
+       for_each_intel_connector(dev, connector) {
                struct intel_encoder *encoder = connector->new_encoder;
 
                if (!encoder)
@@ -10192,15 +10581,30 @@ static bool check_digital_port_conflicts(struct drm_device *dev)
        return true;
 }
 
+static void
+clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
+{
+       struct drm_crtc_state tmp_state;
+
+       /* Clear only the intel specific part of the crtc state */
+       tmp_state = crtc_state->base;
+       memset(crtc_state, 0, sizeof *crtc_state);
+       crtc_state->base = tmp_state;
+}
+
 static struct intel_crtc_state *
 intel_modeset_pipe_config(struct drm_crtc *crtc,
                          struct drm_framebuffer *fb,
-                         struct drm_display_mode *mode)
+                         struct drm_display_mode *mode,
+                         struct drm_atomic_state *state)
 {
        struct drm_device *dev = crtc->dev;
        struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       struct drm_connector_state *connector_state;
        struct intel_crtc_state *pipe_config;
        int plane_bpp, ret = -EINVAL;
+       int i;
        bool retry = true;
 
        if (!check_encoder_cloning(to_intel_crtc(crtc))) {
@@ -10213,10 +10617,13 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
                return ERR_PTR(-EINVAL);
        }
 
-       pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
-       if (!pipe_config)
-               return ERR_PTR(-ENOMEM);
+       pipe_config = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));
+       if (IS_ERR(pipe_config))
+               return pipe_config;
 
+       clear_intel_crtc_state(pipe_config);
+
+       pipe_config->base.crtc = crtc;
        drm_mode_copy(&pipe_config->base.adjusted_mode, mode);
        drm_mode_copy(&pipe_config->base.mode, mode);
 
@@ -10271,11 +10678,17 @@ encoder_retry:
         * adjust it according to limitations or connector properties, and also
         * a chance to reject the mode entirely.
         */
-       for_each_intel_encoder(dev, encoder) {
+       for (i = 0; i < state->num_connector; i++) {
+               connector = to_intel_connector(state->connectors[i]);
+               if (!connector)
+                       continue;
 
-               if (&encoder->new_crtc->base != crtc)
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != crtc)
                        continue;
 
+               encoder = to_intel_encoder(connector_state->best_encoder);
+
                if (!(encoder->compute_config(encoder, pipe_config))) {
                        DRM_DEBUG_KMS("Encoder config failure\n");
                        goto fail;
@@ -10311,7 +10724,6 @@ encoder_retry:
 
        return pipe_config;
 fail:
-       kfree(pipe_config);
        return ERR_PTR(ret);
 }
 
@@ -10333,8 +10745,7 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes,
         * to be part of the prepare_pipes mask. We don't (yet) support global
         * modeset across multiple crtcs, so modeset_pipes will only have one
         * bit set at most. */
-       list_for_each_entry(connector, &dev->mode_config.connector_list,
-                           base.head) {
+       for_each_intel_connector(dev, connector) {
                if (connector->base.encoder == &connector->new_encoder->base)
                        continue;
 
@@ -10365,7 +10776,7 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes,
 
        /* Check for pipes that will be enabled/disabled ... */
        for_each_intel_crtc(dev, intel_crtc) {
-               if (intel_crtc->base.enabled == intel_crtc->new_enabled)
+               if (intel_crtc->base.state->enable == intel_crtc->new_enabled)
                        continue;
 
                if (!intel_crtc->new_enabled)
@@ -10440,10 +10851,10 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
 
        /* Double check state. */
        for_each_intel_crtc(dev, intel_crtc) {
-               WARN_ON(intel_crtc->base.enabled != intel_crtc_in_use(&intel_crtc->base));
+               WARN_ON(intel_crtc->base.state->enable != intel_crtc_in_use(&intel_crtc->base));
                WARN_ON(intel_crtc->new_config &&
                        intel_crtc->new_config != intel_crtc->config);
-               WARN_ON(intel_crtc->base.enabled != !!intel_crtc->new_config);
+               WARN_ON(intel_crtc->base.state->enable != !!intel_crtc->new_config);
        }
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -10703,7 +11114,7 @@ static void check_wm_state(struct drm_device *dev)
                        continue;
 
                /* planes */
-               for_each_plane(pipe, plane) {
+               for_each_plane(dev_priv, pipe, plane) {
                        hw_entry = &hw_ddb.plane[pipe][plane];
                        sw_entry = &sw_ddb->plane[pipe][plane];
 
@@ -10737,8 +11148,7 @@ check_connector_state(struct drm_device *dev)
 {
        struct intel_connector *connector;
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list,
-                           base.head) {
+       for_each_intel_connector(dev, connector) {
                /* This also checks the encoder/connector hw state with the
                 * ->get_hw_state callbacks. */
                intel_connector_check_state(connector);
@@ -10768,8 +11178,7 @@ check_encoder_state(struct drm_device *dev)
                I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc,
                     "encoder's active_connectors set, but no crtc\n");
 
-               list_for_each_entry(connector, &dev->mode_config.connector_list,
-                                   base.head) {
+               for_each_intel_connector(dev, connector) {
                        if (connector->base.encoder != &encoder->base)
                                continue;
                        enabled = true;
@@ -10830,7 +11239,7 @@ check_crtc_state(struct drm_device *dev)
                DRM_DEBUG_KMS("[CRTC:%d]\n",
                              crtc->base.base.id);
 
-               I915_STATE_WARN(crtc->active && !crtc->base.enabled,
+               I915_STATE_WARN(crtc->active && !crtc->base.state->enable,
                     "active crtc, but not enabled in sw tracking\n");
 
                for_each_intel_encoder(dev, encoder) {
@@ -10844,9 +11253,10 @@ check_crtc_state(struct drm_device *dev)
                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.enabled,
+               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.enabled);
+                    "(expected %i, found %i)\n", enabled,
+                               crtc->base.state->enable);
 
                active = dev_priv->display.get_pipe_config(crtc,
                                                           &pipe_config);
@@ -10910,7 +11320,7 @@ check_shared_dpll_state(struct drm_device *dev)
                     pll->on, active);
 
                for_each_intel_crtc(dev, crtc) {
-                       if (crtc->base.enabled && intel_crtc_to_shared_dpll(crtc) == pll)
+                       if (crtc->base.state->enable && intel_crtc_to_shared_dpll(crtc) == pll)
                                enabled_crtcs++;
                        if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll)
                                active_crtcs++;
@@ -10992,17 +11402,30 @@ static struct intel_crtc_state *
 intel_modeset_compute_config(struct drm_crtc *crtc,
                             struct drm_display_mode *mode,
                             struct drm_framebuffer *fb,
+                            struct drm_atomic_state *state,
                             unsigned *modeset_pipes,
                             unsigned *prepare_pipes,
                             unsigned *disable_pipes)
 {
+       struct drm_device *dev = crtc->dev;
        struct intel_crtc_state *pipe_config = NULL;
+       struct intel_crtc *intel_crtc;
+       int ret = 0;
+
+       ret = drm_atomic_add_affected_connectors(state, crtc);
+       if (ret)
+               return ERR_PTR(ret);
 
        intel_modeset_affected_pipes(crtc, modeset_pipes,
                                     prepare_pipes, disable_pipes);
 
-       if ((*modeset_pipes) == 0)
-               goto out;
+       for_each_intel_crtc_masked(dev, *disable_pipes, intel_crtc) {
+               pipe_config = intel_atomic_get_crtc_state(state, intel_crtc);
+               if (IS_ERR(pipe_config))
+                       return pipe_config;
+
+               pipe_config->base.enable = false;
+       }
 
        /*
         * Note this needs changes when we start tracking multiple modes
@@ -11010,15 +11433,21 @@ intel_modeset_compute_config(struct drm_crtc *crtc,
         * (i.e. one pipe_config for each crtc) rather than just the one
         * for this crtc.
         */
-       pipe_config = intel_modeset_pipe_config(crtc, fb, mode);
-       if (IS_ERR(pipe_config)) {
-               goto out;
+       for_each_intel_crtc_masked(dev, *modeset_pipes, intel_crtc) {
+               /* FIXME: For now we still expect modeset_pipes has at most
+                * one bit set. */
+               if (WARN_ON(&intel_crtc->base != crtc))
+                       continue;
+
+               pipe_config = intel_modeset_pipe_config(crtc, fb, mode, state);
+               if (IS_ERR(pipe_config))
+                       return pipe_config;
+
+               intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
+                                      "[modeset]");
        }
-       intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
-                              "[modeset]");
 
-out:
-       return pipe_config;
+       return intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));;
 }
 
 static int __intel_set_mode_setup_plls(struct drm_device *dev,
@@ -11062,6 +11491,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_display_mode *saved_mode;
+       struct intel_crtc_state *crtc_state_copy = NULL;
        struct intel_crtc *intel_crtc;
        int ret = 0;
 
@@ -11069,6 +11499,12 @@ static int __intel_set_mode(struct drm_crtc *crtc,
        if (!saved_mode)
                return -ENOMEM;
 
+       crtc_state_copy = kmalloc(sizeof(*crtc_state_copy), GFP_KERNEL);
+       if (!crtc_state_copy) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
        *saved_mode = crtc->mode;
 
        if (modeset_pipes)
@@ -11096,7 +11532,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
                intel_crtc_disable(&intel_crtc->base);
 
        for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) {
-               if (intel_crtc->base.enabled)
+               if (intel_crtc->base.state->enable)
                        dev_priv->display.crtc_disable(&intel_crtc->base);
        }
 
@@ -11126,7 +11562,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
         * update the the output configuration. */
        intel_modeset_update_state(dev, prepare_pipes);
 
-       modeset_update_crtc_power_domains(dev);
+       modeset_update_crtc_power_domains(pipe_config->base.state);
 
        /* Set up the DPLL and any encoders state that needs to adjust or depend
         * on the DPLL.
@@ -11152,9 +11588,25 @@ static int __intel_set_mode(struct drm_crtc *crtc,
 
        /* FIXME: add subpixel order */
 done:
-       if (ret && crtc->enabled)
+       if (ret && crtc->state->enable)
                crtc->mode = *saved_mode;
 
+       if (ret == 0 && pipe_config) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+               /* The pipe_config will be freed with the atomic state, so
+                * make a copy. */
+               memcpy(crtc_state_copy, intel_crtc->config,
+                      sizeof *crtc_state_copy);
+               intel_crtc->config = crtc_state_copy;
+               intel_crtc->base.state = &crtc_state_copy->base;
+
+               if (modeset_pipes)
+                       intel_crtc->new_config = intel_crtc->config;
+       } else {
+               kfree(crtc_state_copy);
+       }
+
        kfree(saved_mode);
        return ret;
 }
@@ -11180,27 +11632,81 @@ static int intel_set_mode_pipes(struct drm_crtc *crtc,
 
 static int intel_set_mode(struct drm_crtc *crtc,
                          struct drm_display_mode *mode,
-                         int x, int y, struct drm_framebuffer *fb)
+                         int x, int y, struct drm_framebuffer *fb,
+                         struct drm_atomic_state *state)
 {
        struct intel_crtc_state *pipe_config;
        unsigned modeset_pipes, prepare_pipes, disable_pipes;
+       int ret = 0;
 
-       pipe_config = intel_modeset_compute_config(crtc, mode, fb,
+       pipe_config = intel_modeset_compute_config(crtc, mode, fb, state,
                                                   &modeset_pipes,
                                                   &prepare_pipes,
                                                   &disable_pipes);
 
-       if (IS_ERR(pipe_config))
-               return PTR_ERR(pipe_config);
+       if (IS_ERR(pipe_config)) {
+               ret = PTR_ERR(pipe_config);
+               goto out;
+       }
 
-       return intel_set_mode_pipes(crtc, mode, x, y, fb, pipe_config,
-                                   modeset_pipes, prepare_pipes,
-                                   disable_pipes);
+       ret = intel_set_mode_pipes(crtc, mode, x, y, fb, pipe_config,
+                                  modeset_pipes, prepare_pipes,
+                                  disable_pipes);
+       if (ret)
+               goto out;
+
+out:
+       return ret;
 }
 
 void intel_crtc_restore_mode(struct drm_crtc *crtc)
 {
-       intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb);
+       struct drm_device *dev = crtc->dev;
+       struct drm_atomic_state *state;
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       struct drm_connector_state *connector_state;
+
+       state = drm_atomic_state_alloc(dev);
+       if (!state) {
+               DRM_DEBUG_KMS("[CRTC:%d] mode restore failed, out of memory",
+                             crtc->base.id);
+               return;
+       }
+
+       state->acquire_ctx = dev->mode_config.acquire_ctx;
+
+       /* The force restore path in the HW readout code relies on the staged
+        * config still keeping the user requested config while the actual
+        * state has been overwritten by the configuration read from HW. We
+        * need to copy the staged config to the atomic state, otherwise the
+        * mode set will just reapply the state the HW is already in. */
+       for_each_intel_encoder(dev, encoder) {
+               if (&encoder->new_crtc->base != crtc)
+                       continue;
+
+               for_each_intel_connector(dev, connector) {
+                       if (connector->new_encoder != encoder)
+                               continue;
+
+                       connector_state = drm_atomic_get_connector_state(state, &connector->base);
+                       if (IS_ERR(connector_state)) {
+                               DRM_DEBUG_KMS("Failed to add [CONNECTOR:%d:%s] to state: %ld\n",
+                                             connector->base.base.id,
+                                             connector->base.name,
+                                             PTR_ERR(connector_state));
+                               continue;
+                       }
+
+                       connector_state->crtc = crtc;
+                       connector_state->best_encoder = &encoder->base;
+               }
+       }
+
+       intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb,
+                      state);
+
+       drm_atomic_state_free(state);
 }
 
 #undef for_each_intel_crtc_masked
@@ -11248,7 +11754,7 @@ static int intel_set_config_save_state(struct drm_device *dev,
         */
        count = 0;
        for_each_crtc(dev, crtc) {
-               config->save_crtc_enabled[count++] = crtc->enabled;
+               config->save_crtc_enabled[count++] = crtc->state->enable;
        }
 
        count = 0;
@@ -11289,7 +11795,7 @@ static void intel_set_config_restore_state(struct drm_device *dev,
        }
 
        count = 0;
-       list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) {
+       for_each_intel_connector(dev, connector) {
                connector->new_encoder =
                        to_intel_encoder(config->save_connector_encoders[count++]);
        }
@@ -11369,9 +11875,11 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
 static int
 intel_modeset_stage_output_state(struct drm_device *dev,
                                 struct drm_mode_set *set,
-                                struct intel_set_config *config)
+                                struct intel_set_config *config,
+                                struct drm_atomic_state *state)
 {
        struct intel_connector *connector;
+       struct drm_connector_state *connector_state;
        struct intel_encoder *encoder;
        struct intel_crtc *crtc;
        int ro;
@@ -11381,8 +11889,7 @@ intel_modeset_stage_output_state(struct drm_device *dev,
        WARN_ON(!set->fb && (set->num_connectors != 0));
        WARN_ON(set->fb && (set->num_connectors == 0));
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list,
-                           base.head) {
+       for_each_intel_connector(dev, connector) {
                /* Otherwise traverse passed in connector list and get encoders
                 * for them. */
                for (ro = 0; ro < set->num_connectors; ro++) {
@@ -11407,15 +11914,16 @@ intel_modeset_stage_output_state(struct drm_device *dev,
 
 
                if (&connector->new_encoder->base != connector->base.encoder) {
-                       DRM_DEBUG_KMS("encoder changed, full mode switch\n");
+                       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] encoder changed, full mode switch\n",
+                                     connector->base.base.id,
+                                     connector->base.name);
                        config->mode_changed = true;
                }
        }
        /* connector->new_encoder is now updated for all connectors. */
 
        /* Update crtc of enabled connectors. */
-       list_for_each_entry(connector, &dev->mode_config.connector_list,
-                           base.head) {
+       for_each_intel_connector(dev, connector) {
                struct drm_crtc *new_crtc;
 
                if (!connector->new_encoder)
@@ -11435,6 +11943,14 @@ intel_modeset_stage_output_state(struct drm_device *dev,
                }
                connector->new_encoder->new_crtc = to_intel_crtc(new_crtc);
 
+               connector_state =
+                       drm_atomic_get_connector_state(state, &connector->base);
+               if (IS_ERR(connector_state))
+                       return PTR_ERR(connector_state);
+
+               connector_state->crtc = new_crtc;
+               connector_state->best_encoder = &connector->new_encoder->base;
+
                DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
                        connector->base.base.id,
                        connector->base.name,
@@ -11444,9 +11960,7 @@ intel_modeset_stage_output_state(struct drm_device *dev,
        /* Check for any encoders that needs to be disabled. */
        for_each_intel_encoder(dev, encoder) {
                int num_connectors = 0;
-               list_for_each_entry(connector,
-                                   &dev->mode_config.connector_list,
-                                   base.head) {
+               for_each_intel_connector(dev, connector) {
                        if (connector->new_encoder == encoder) {
                                WARN_ON(!connector->new_encoder->new_crtc);
                                num_connectors++;
@@ -11461,16 +11975,25 @@ intel_modeset_stage_output_state(struct drm_device *dev,
                /* Only now check for crtc changes so we don't miss encoders
                 * that will be disabled. */
                if (&encoder->new_crtc->base != encoder->base.crtc) {
-                       DRM_DEBUG_KMS("crtc changed, full mode switch\n");
+                       DRM_DEBUG_KMS("[ENCODER:%d:%s] crtc changed, full mode switch\n",
+                                     encoder->base.base.id,
+                                     encoder->base.name);
                        config->mode_changed = true;
                }
        }
        /* Now we've also updated encoder->new_crtc for all encoders. */
-       list_for_each_entry(connector, &dev->mode_config.connector_list,
-                           base.head) {
-               if (connector->new_encoder)
+       for_each_intel_connector(dev, connector) {
+               connector_state =
+                       drm_atomic_get_connector_state(state, &connector->base);
+               if (IS_ERR(connector_state))
+                       return PTR_ERR(connector_state);
+
+               if (connector->new_encoder) {
                        if (connector->new_encoder != connector->encoder)
                                connector->encoder = connector->new_encoder;
+               } else {
+                       connector_state->crtc = NULL;
+               }
        }
        for_each_intel_crtc(dev, crtc) {
                crtc->new_enabled = false;
@@ -11482,8 +12005,9 @@ intel_modeset_stage_output_state(struct drm_device *dev,
                        }
                }
 
-               if (crtc->new_enabled != crtc->base.enabled) {
-                       DRM_DEBUG_KMS("crtc %sabled, full mode switch\n",
+               if (crtc->new_enabled != crtc->base.state->enable) {
+                       DRM_DEBUG_KMS("[CRTC:%d] %sabled, full mode switch\n",
+                                     crtc->base.base.id,
                                      crtc->new_enabled ? "en" : "dis");
                        config->mode_changed = true;
                }
@@ -11506,7 +12030,7 @@ static void disable_crtc_nofb(struct intel_crtc *crtc)
        DRM_DEBUG_KMS("Trying to restore without FB -> disabling pipe %c\n",
                      pipe_name(crtc->pipe));
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) {
+       for_each_intel_connector(dev, connector) {
                if (connector->new_encoder &&
                    connector->new_encoder->new_crtc == crtc)
                        connector->new_encoder = NULL;
@@ -11525,6 +12049,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 {
        struct drm_device *dev;
        struct drm_mode_set save_set;
+       struct drm_atomic_state *state = NULL;
        struct intel_set_config *config;
        struct intel_crtc_state *pipe_config;
        unsigned modeset_pipes, prepare_pipes, disable_pipes;
@@ -11569,12 +12094,20 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
         * such cases. */
        intel_set_config_compute_mode_changes(set, config);
 
-       ret = intel_modeset_stage_output_state(dev, set, config);
+       state = drm_atomic_state_alloc(dev);
+       if (!state) {
+               ret = -ENOMEM;
+               goto out_config;
+       }
+
+       state->acquire_ctx = dev->mode_config.acquire_ctx;
+
+       ret = intel_modeset_stage_output_state(dev, set, config, state);
        if (ret)
                goto fail;
 
        pipe_config = intel_modeset_compute_config(set->crtc, set->mode,
-                                                  set->fb,
+                                                  set->fb, state,
                                                   &modeset_pipes,
                                                   &prepare_pipes,
                                                   &disable_pipes);
@@ -11594,10 +12127,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
                 */
        }
 
-       /* set_mode will free it in the mode_changed case */
-       if (!config->mode_changed)
-               kfree(pipe_config);
-
        intel_update_pipe_size(to_intel_crtc(set->crtc));
 
        if (config->mode_changed) {
@@ -11643,6 +12172,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 fail:
                intel_set_config_restore_state(dev, config);
 
+               drm_atomic_state_clear(state);
+
                /*
                 * HACK: if the pipe was on, but we didn't have a framebuffer,
                 * force the pipe off to avoid oopsing in the modeset code
@@ -11655,11 +12186,15 @@ fail:
                /* Try to restore the config */
                if (config->mode_changed &&
                    intel_set_mode(save_set.crtc, save_set.mode,
-                                  save_set.x, save_set.y, save_set.fb))
+                                  save_set.x, save_set.y, save_set.fb,
+                                  state))
                        DRM_ERROR("failed to restore config after modeset failure\n");
        }
 
 out_config:
+       if (state)
+               drm_atomic_state_free(state);
+
        intel_set_config_free(config);
        return ret;
 }
@@ -11773,6 +12308,28 @@ static void intel_shared_dpll_init(struct drm_device *dev)
        BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
 }
 
+/**
+ * intel_wm_need_update - Check whether watermarks need updating
+ * @plane: drm plane
+ * @state: new plane state
+ *
+ * Check current plane state versus the new one to determine whether
+ * watermarks need to be recalculated.
+ *
+ * Returns true or false.
+ */
+bool intel_wm_need_update(struct drm_plane *plane,
+                         struct drm_plane_state *state)
+{
+       /* Update watermarks on tiling changes. */
+       if (!plane->state->fb || !state->fb ||
+           plane->state->fb->modifier[0] != state->fb->modifier[0] ||
+           plane->state->rotation != state->rotation)
+               return true;
+
+       return false;
+}
+
 /**
  * intel_prepare_plane_fb - Prepare fb for usage on plane
  * @plane: drm plane to prepare for
@@ -11787,7 +12344,8 @@ static void intel_shared_dpll_init(struct drm_device *dev)
  */
 int
 intel_prepare_plane_fb(struct drm_plane *plane,
-                      struct drm_framebuffer *fb)
+                      struct drm_framebuffer *fb,
+                      const struct drm_plane_state *new_state)
 {
        struct drm_device *dev = plane->dev;
        struct intel_plane *intel_plane = to_intel_plane(plane);
@@ -11821,7 +12379,7 @@ intel_prepare_plane_fb(struct drm_plane *plane,
                if (ret)
                        DRM_DEBUG_KMS("failed to attach phys object\n");
        } else {
-               ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
+               ret = intel_pin_and_fence_fb_obj(plane, fb, new_state, NULL);
        }
 
        if (ret == 0)
@@ -11841,7 +12399,8 @@ intel_prepare_plane_fb(struct drm_plane *plane,
  */
 void
 intel_cleanup_plane_fb(struct drm_plane *plane,
-                      struct drm_framebuffer *fb)
+                      struct drm_framebuffer *fb,
+                      const struct drm_plane_state *old_state)
 {
        struct drm_device *dev = plane->dev;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
@@ -11852,7 +12411,7 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
        if (plane->type != DRM_PLANE_TYPE_CURSOR ||
            !INTEL_INFO(dev)->cursor_needs_physical) {
                mutex_lock(&dev->struct_mutex);
-               intel_unpin_fb_obj(obj);
+               intel_unpin_fb_obj(fb, old_state);
                mutex_unlock(&dev->struct_mutex);
        }
 }
@@ -11897,7 +12456,7 @@ intel_check_primary_plane(struct drm_plane *plane,
                 */
                if (intel_crtc->primary_enabled &&
                    INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
-                   dev_priv->fbc.plane == intel_crtc->plane &&
+                   dev_priv->fbc.crtc == intel_crtc &&
                    state->base.rotation != BIT(DRM_ROTATE_0)) {
                        intel_crtc->atomic.disable_fbc = true;
                }
@@ -11916,6 +12475,9 @@ intel_check_primary_plane(struct drm_plane *plane,
                        INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
 
                intel_crtc->atomic.update_fbc = true;
+
+               if (intel_wm_need_update(plane, &state->base))
+                       intel_crtc->atomic.update_wm = true;
        }
 
        return 0;
@@ -11930,8 +12492,6 @@ intel_commit_primary_plane(struct drm_plane *plane,
        struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-       struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_rect *src = &state->src;
 
        crtc = crtc ? crtc : plane->crtc;
@@ -11941,8 +12501,6 @@ intel_commit_primary_plane(struct drm_plane *plane,
        crtc->x = src->x1 >> 16;
        crtc->y = src->y1 >> 16;
 
-       intel_plane->obj = obj;
-
        if (intel_crtc->active) {
                if (state->visible) {
                        /* FIXME: kill this fastboot hack */
@@ -12182,20 +12740,14 @@ intel_check_cursor_plane(struct drm_plane *plane,
                return -ENOMEM;
        }
 
-       if (fb == crtc->cursor->fb)
-               return 0;
-
-       /* we only need to pin inside GTT if cursor is non-phy */
-       mutex_lock(&dev->struct_mutex);
-       if (!INTEL_INFO(dev)->cursor_needs_physical && obj->tiling_mode) {
+       if (fb->modifier[0] != DRM_FORMAT_MOD_NONE) {
                DRM_DEBUG_KMS("cursor cannot be tiled\n");
                ret = -EINVAL;
        }
-       mutex_unlock(&dev->struct_mutex);
 
 finish:
        if (intel_crtc->active) {
-               if (intel_crtc->cursor_width != state->base.crtc_w)
+               if (plane->state->crtc_w != state->base.crtc_w)
                        intel_crtc->atomic.update_wm = true;
 
                intel_crtc->atomic.fb_bits |=
@@ -12212,7 +12764,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
        struct drm_crtc *crtc = state->base.crtc;
        struct drm_device *dev = plane->dev;
        struct intel_crtc *intel_crtc;
-       struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
        uint32_t addr;
 
@@ -12223,8 +12774,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
        crtc->cursor_x = state->base.crtc_x;
        crtc->cursor_y = state->base.crtc_y;
 
-       intel_plane->obj = obj;
-
        if (intel_crtc->cursor_bo == obj)
                goto update;
 
@@ -12238,8 +12787,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
        intel_crtc->cursor_addr = addr;
        intel_crtc->cursor_bo = obj;
 update:
-       intel_crtc->cursor_width = state->base.crtc_w;
-       intel_crtc->cursor_height = state->base.crtc_h;
 
        if (intel_crtc->active)
                intel_crtc_update_cursor(crtc, state->visible);
@@ -12309,6 +12856,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        if (!crtc_state)
                goto fail;
        intel_crtc_set_state(intel_crtc, crtc_state);
+       crtc_state->base.crtc = &intel_crtc->base;
 
        primary = intel_primary_plane_create(dev, pipe);
        if (!primary)
@@ -12386,9 +12934,6 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
        struct drm_crtc *drmmode_crtc;
        struct intel_crtc *crtc;
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -ENODEV;
-
        drmmode_crtc = drm_crtc_find(dev, pipe_from_crtc_id->crtc_id);
 
        if (!drmmode_crtc) {
@@ -12469,10 +13014,15 @@ static void intel_setup_outputs(struct drm_device *dev)
        if (HAS_DDI(dev)) {
                int found;
 
-               /* Haswell uses DDI functions to detect digital outputs */
+               /*
+                * Haswell uses DDI functions to detect digital outputs.
+                * On SKL pre-D0 the strap isn't connected, so we assume
+                * it's there.
+                */
                found = I915_READ(DDI_BUF_CTL_A) & DDI_INIT_DISPLAY_DETECTED;
-               /* DDI A only supports eDP */
-               if (found)
+               /* WaIgnoreDDIAStrap: skl */
+               if (found ||
+                   (IS_SKYLAKE(dev) && INTEL_REVID(dev) < SKL_REVID_D0))
                        intel_ddi_init(dev, PORT_A);
 
                /* DDI B, C and D detection is indicated by the SFUSE_STRAP
@@ -12604,19 +13154,21 @@ static void intel_setup_outputs(struct drm_device *dev)
         * testing/debug of the plane operations (and only when a specific
         * kernel module option is given), that shouldn't really matter.
         *
+        * We are also relying on these states to convert the legacy mode set
+        * to use a drm_atomic_state struct. The states are kept consistent
+        * with actual state, so that it is safe to rely on that instead of
+        * the staged config.
+        *
         * Once atomic support for crtc's + connectors lands, this loop should
         * be removed since we'll be setting up real connector state, which
         * will contain Intel-specific properties.
         */
-       if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
-               list_for_each_entry(connector,
-                                   &dev->mode_config.connector_list,
-                                   head) {
-                       if (!WARN_ON(connector->state)) {
-                               connector->state =
-                                       kzalloc(sizeof(*connector->state),
-                                               GFP_KERNEL);
-                       }
+       list_for_each_entry(connector,
+                           &dev->mode_config.connector_list,
+                           head) {
+               if (!WARN_ON(connector->state)) {
+                       connector->state = kzalloc(sizeof(*connector->state),
+                                                  GFP_KERNEL);
                }
        }
 
@@ -12661,52 +13213,100 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
        .create_handle = intel_user_framebuffer_create_handle,
 };
 
+static
+u32 intel_fb_pitch_limit(struct drm_device *dev, uint64_t fb_modifier,
+                        uint32_t pixel_format)
+{
+       u32 gen = INTEL_INFO(dev)->gen;
+
+       if (gen >= 9) {
+               /* "The stride in bytes must not exceed the of the size of 8K
+                *  pixels and 32K bytes."
+                */
+                return min(8192*drm_format_plane_cpp(pixel_format, 0), 32768);
+       } else if (gen >= 5 && !IS_VALLEYVIEW(dev)) {
+               return 32*1024;
+       } else if (gen >= 4) {
+               if (fb_modifier == I915_FORMAT_MOD_X_TILED)
+                       return 16*1024;
+               else
+                       return 32*1024;
+       } else if (gen >= 3) {
+               if (fb_modifier == I915_FORMAT_MOD_X_TILED)
+                       return 8*1024;
+               else
+                       return 16*1024;
+       } else {
+               /* XXX DSPC is limited to 4k tiled */
+               return 8*1024;
+       }
+}
+
 static int intel_framebuffer_init(struct drm_device *dev,
                                  struct intel_framebuffer *intel_fb,
                                  struct drm_mode_fb_cmd2 *mode_cmd,
                                  struct drm_i915_gem_object *obj)
 {
-       int aligned_height;
-       int pitch_limit;
+       unsigned int aligned_height;
        int ret;
+       u32 pitch_limit, stride_alignment;
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
-       if (obj->tiling_mode == I915_TILING_Y) {
-               DRM_DEBUG("hardware does not support tiling Y\n");
-               return -EINVAL;
+       if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
+               /* Enforce that fb modifier and tiling mode match, but only for
+                * X-tiled. This is needed for FBC. */
+               if (!!(obj->tiling_mode == I915_TILING_X) !=
+                   !!(mode_cmd->modifier[0] == I915_FORMAT_MOD_X_TILED)) {
+                       DRM_DEBUG("tiling_mode doesn't match fb modifier\n");
+                       return -EINVAL;
+               }
+       } else {
+               if (obj->tiling_mode == I915_TILING_X)
+                       mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED;
+               else if (obj->tiling_mode == I915_TILING_Y) {
+                       DRM_DEBUG("No Y tiling for legacy addfb\n");
+                       return -EINVAL;
+               }
        }
 
-       if (mode_cmd->pitches[0] & 63) {
-               DRM_DEBUG("pitch (%d) must be at least 64 byte aligned\n",
-                         mode_cmd->pitches[0]);
+       /* Passed in modifier sanity checking. */
+       switch (mode_cmd->modifier[0]) {
+       case I915_FORMAT_MOD_Y_TILED:
+       case I915_FORMAT_MOD_Yf_TILED:
+               if (INTEL_INFO(dev)->gen < 9) {
+                       DRM_DEBUG("Unsupported tiling 0x%llx!\n",
+                                 mode_cmd->modifier[0]);
+                       return -EINVAL;
+               }
+       case DRM_FORMAT_MOD_NONE:
+       case I915_FORMAT_MOD_X_TILED:
+               break;
+       default:
+               DRM_DEBUG("Unsupported fb modifier 0x%llx!\n",
+                         mode_cmd->modifier[0]);
                return -EINVAL;
        }
 
-       if (INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev)) {
-               pitch_limit = 32*1024;
-       } else if (INTEL_INFO(dev)->gen >= 4) {
-               if (obj->tiling_mode)
-                       pitch_limit = 16*1024;
-               else
-                       pitch_limit = 32*1024;
-       } else if (INTEL_INFO(dev)->gen >= 3) {
-               if (obj->tiling_mode)
-                       pitch_limit = 8*1024;
-               else
-                       pitch_limit = 16*1024;
-       } else
-               /* XXX DSPC is limited to 4k tiled */
-               pitch_limit = 8*1024;
+       stride_alignment = intel_fb_stride_alignment(dev, mode_cmd->modifier[0],
+                                                    mode_cmd->pixel_format);
+       if (mode_cmd->pitches[0] & (stride_alignment - 1)) {
+               DRM_DEBUG("pitch (%d) must be at least %u byte aligned\n",
+                         mode_cmd->pitches[0], stride_alignment);
+               return -EINVAL;
+       }
 
+       pitch_limit = intel_fb_pitch_limit(dev, mode_cmd->modifier[0],
+                                          mode_cmd->pixel_format);
        if (mode_cmd->pitches[0] > pitch_limit) {
-               DRM_DEBUG("%s pitch (%d) must be at less than %d\n",
-                         obj->tiling_mode ? "tiled" : "linear",
+               DRM_DEBUG("%s pitch (%u) must be at less than %d\n",
+                         mode_cmd->modifier[0] != DRM_FORMAT_MOD_NONE ?
+                         "tiled" : "linear",
                          mode_cmd->pitches[0], pitch_limit);
                return -EINVAL;
        }
 
-       if (obj->tiling_mode != I915_TILING_NONE &&
+       if (mode_cmd->modifier[0] == I915_FORMAT_MOD_X_TILED &&
            mode_cmd->pitches[0] != obj->stride) {
                DRM_DEBUG("pitch (%d) must match tiling stride (%d)\n",
                          mode_cmd->pitches[0], obj->stride);
@@ -12761,7 +13361,8 @@ static int intel_framebuffer_init(struct drm_device *dev,
                return -EINVAL;
 
        aligned_height = intel_fb_align_height(dev, mode_cmd->height,
-                                              obj->tiling_mode);
+                                              mode_cmd->pixel_format,
+                                              mode_cmd->modifier[0]);
        /* FIXME drm helper for size checks (especially planar formats)? */
        if (obj->base.size < aligned_height * mode_cmd->pitches[0])
                return -EINVAL;
@@ -12914,8 +13515,6 @@ static void intel_init_display(struct drm_device *dev)
        } else if (IS_IVYBRIDGE(dev)) {
                /* FIXME: detect B0+ stepping and use auto training */
                dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
-               dev_priv->display.modeset_global_resources =
-                       ivb_modeset_global_resources;
        } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                dev_priv->display.fdi_link_train = hsw_fdi_link_train;
        } else if (IS_VALLEYVIEW(dev)) {
@@ -12923,9 +13522,6 @@ static void intel_init_display(struct drm_device *dev)
                        valleyview_modeset_global_resources;
        }
 
-       /* Default just returns -ENODEV to indicate unsupported */
-       dev_priv->display.queue_flip = intel_default_queue_flip;
-
        switch (INTEL_INFO(dev)->gen) {
        case 2:
                dev_priv->display.queue_flip = intel_gen2_queue_flip;
@@ -12948,8 +13544,10 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.queue_flip = intel_gen7_queue_flip;
                break;
        case 9:
-               dev_priv->display.queue_flip = intel_gen9_queue_flip;
-               break;
+               /* Drop through - unsupported since execlist only. */
+       default:
+               /* Default just returns -ENODEV to indicate unsupported */
+               dev_priv->display.queue_flip = intel_default_queue_flip;
        }
 
        intel_panel_init_backlight_funcs(dev);
@@ -13096,6 +13694,9 @@ static struct intel_quirk intel_quirks[] = {
 
        /* HP Chromebook 14 (Celeron 2955U) */
        { 0x0a06, 0x103c, 0x21ed, quirk_backlight_present },
+
+       /* Dell Chromebook 11 */
+       { 0x0a06, 0x1028, 0x0a35, quirk_backlight_present },
 };
 
 static void intel_init_quirks(struct drm_device *dev)
@@ -13165,6 +13766,8 @@ void intel_modeset_init(struct drm_device *dev)
        dev->mode_config.preferred_depth = 24;
        dev->mode_config.prefer_shadow = 1;
 
+       dev->mode_config.allow_fb_modifiers = true;
+
        dev->mode_config.funcs = &intel_mode_funcs;
 
        intel_init_quirks(dev);
@@ -13207,7 +13810,7 @@ void intel_modeset_init(struct drm_device *dev)
 
        for_each_pipe(dev_priv, pipe) {
                intel_crtc_init(dev, pipe);
-               for_each_sprite(pipe, sprite) {
+               for_each_sprite(dev_priv, pipe, sprite) {
                        ret = intel_plane_init(dev, pipe, sprite);
                        if (ret)
                                DRM_DEBUG_KMS("pipe %c sprite %c init failed: %d\n",
@@ -13248,7 +13851,7 @@ void intel_modeset_init(struct drm_device *dev)
                         * If the fb is shared between multiple heads, we'll
                         * just get the first one.
                         */
-                       intel_find_plane_obj(crtc, &crtc->plane_config);
+                       intel_find_initial_plane_obj(crtc, &crtc->plane_config);
                }
        }
 }
@@ -13263,9 +13866,7 @@ static void intel_enable_pipe_a(struct drm_device *dev)
        /* We can't just switch on the pipe A, we need to set things up with a
         * proper mode and output configuration. As a gross hack, enable pipe A
         * by enabling the load detect pipe once. */
-       list_for_each_entry(connector,
-                           &dev->mode_config.connector_list,
-                           base.head) {
+       for_each_intel_connector(dev, connector) {
                if (connector->encoder->type == INTEL_OUTPUT_ANALOG) {
                        crt = &connector->base;
                        break;
@@ -13276,7 +13877,7 @@ static void intel_enable_pipe_a(struct drm_device *dev)
                return;
 
        if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx))
-               intel_release_load_detect_pipe(crt, &load_detect_temp);
+               intel_release_load_detect_pipe(crt, &load_detect_temp, ctx);
 }
 
 static bool
@@ -13310,11 +13911,11 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
        I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
 
        /* restore vblank interrupts to correct state */
+       drm_crtc_vblank_reset(&crtc->base);
        if (crtc->active) {
                update_scanline_offset(crtc);
-               drm_vblank_on(dev, crtc->pipe);
-       } else
-               drm_vblank_off(dev, crtc->pipe);
+               drm_crtc_vblank_on(&crtc->base);
+       }
 
        /* We need to sanitize the plane -> pipe mapping first because this will
         * disable the crtc (and hence change the state) if it is wrong. Note
@@ -13336,8 +13937,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                crtc->plane = plane;
 
                /* ... and break all links. */
-               list_for_each_entry(connector, &dev->mode_config.connector_list,
-                                   base.head) {
+               for_each_intel_connector(dev, connector) {
                        if (connector->encoder->base.crtc != &crtc->base)
                                continue;
 
@@ -13346,14 +13946,14 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                }
                /* multiple connectors may have the same encoder:
                 *  handle them and break crtc link separately */
-               list_for_each_entry(connector, &dev->mode_config.connector_list,
-                                   base.head)
+               for_each_intel_connector(dev, connector)
                        if (connector->encoder->base.crtc == &crtc->base) {
                                connector->encoder->base.crtc = NULL;
                                connector->encoder->connectors_active = false;
                        }
 
                WARN_ON(crtc->active);
+               crtc->base.state->enable = false;
                crtc->base.enabled = false;
        }
 
@@ -13370,7 +13970,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
         * have active connectors/encoders. */
        intel_crtc_update_dpms(&crtc->base);
 
-       if (crtc->active != crtc->base.enabled) {
+       if (crtc->active != crtc->base.state->enable) {
                struct intel_encoder *encoder;
 
                /* This can happen either due to bugs in the get_hw_state
@@ -13378,9 +13978,10 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                 * pipe A quirk. */
                DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n",
                              crtc->base.base.id,
-                             crtc->base.enabled ? "enabled" : "disabled",
+                             crtc->base.state->enable ? "enabled" : "disabled",
                              crtc->active ? "enabled" : "disabled");
 
+               crtc->base.state->enable = crtc->active;
                crtc->base.enabled = crtc->active;
 
                /* Because we only establish the connector -> encoder ->
@@ -13449,9 +14050,7 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
                 * a bug in one of the get_hw_state functions. Or someplace else
                 * in our code, like the register restore mess on resume. Clamp
                 * things to off as a safer default. */
-               list_for_each_entry(connector,
-                                   &dev->mode_config.connector_list,
-                                   base.head) {
+               for_each_intel_connector(dev, connector) {
                        if (connector->encoder != encoder)
                                continue;
                        connector->base.dpms = DRM_MODE_DPMS_OFF;
@@ -13517,6 +14116,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                crtc->active = dev_priv->display.get_pipe_config(crtc,
                                                                 crtc->config);
 
+               crtc->base.state->enable = crtc->active;
                crtc->base.enabled = crtc->active;
                crtc->primary_enabled = primary_get_hw_state(crtc);
 
@@ -13565,8 +14165,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                              pipe_name(pipe));
        }
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list,
-                           base.head) {
+       for_each_intel_connector(dev, connector) {
                if (connector->get_hw_state(connector)) {
                        connector->base.dpms = DRM_MODE_DPMS_ON;
                        connector->encoder->connectors_active = true;
@@ -13622,6 +14221,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                                       "[setup_hw_state]");
        }
 
+       intel_modeset_update_connector_atomic_state(dev);
+
        for (i = 0; i < dev_priv->num_shared_dpll; i++) {
                struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
 
@@ -13650,8 +14251,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                        struct drm_crtc *crtc =
                                dev_priv->pipe_to_crtc_mapping[pipe];
 
-                       intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
-                                      crtc->primary->fb);
+                       intel_crtc_restore_mode(crtc);
                }
        } else {
                intel_modeset_update_staged_output_state(dev);
@@ -13697,11 +14297,13 @@ void intel_modeset_gem_init(struct drm_device *dev)
 
                if (intel_pin_and_fence_fb_obj(c->primary,
                                               c->primary->fb,
+                                              c->primary->state,
                                               NULL)) {
                        DRM_ERROR("failed to pin boot fb on pipe %d\n",
                                  to_intel_crtc(c)->pipe);
                        drm_framebuffer_unreference(c->primary->fb);
                        c->primary->fb = NULL;
+                       update_state_fb(c->primary);
                }
        }
        mutex_unlock(&dev->struct_mutex);
@@ -13745,8 +14347,6 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        intel_fbc_disable(dev);
 
-       ironlake_teardown_rc6(dev);
-
        mutex_unlock(&dev->struct_mutex);
 
        /* flush any delayed tasks or pending work */
index a74aaf9242b965797114c0d775171b181ffdd423..b70e635ccaf4f249c7527dbc9c2c2a39d3530143 100644 (file)
@@ -84,6 +84,13 @@ static const struct dp_link_dpll chv_dpll[] = {
        { DP_LINK_BW_5_4,       /* m2_int = 27, m2_fraction = 0 */
                { .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } }
 };
+/* Skylake supports following rates */
+static const int gen9_rates[] = { 162000, 216000, 270000,
+                                 324000, 432000, 540000 };
+static const int chv_rates[] = { 162000, 202500, 210000, 216000,
+                                243000, 270000, 324000, 405000,
+                                420000, 432000, 540000 };
+static const int default_rates[] = { 162000, 270000, 540000 };
 
 /**
  * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
@@ -118,23 +125,15 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp);
 static void vlv_steal_power_sequencer(struct drm_device *dev,
                                      enum pipe pipe);
 
-int
-intel_dp_max_link_bw(struct intel_dp *intel_dp)
+static int
+intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 {
        int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
-       struct drm_device *dev = intel_dp->attached_connector->base.dev;
 
        switch (max_link_bw) {
        case DP_LINK_BW_1_62:
        case DP_LINK_BW_2_7:
-               break;
-       case DP_LINK_BW_5_4: /* 1.2 capable displays may advertise higher bw */
-               if (((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) ||
-                    INTEL_INFO(dev)->gen >= 8) &&
-                   intel_dp->dpcd[DP_DPCD_REV] >= 0x12)
-                       max_link_bw = DP_LINK_BW_5_4;
-               else
-                       max_link_bw = DP_LINK_BW_2_7;
+       case DP_LINK_BW_5_4:
                break;
        default:
                WARN(1, "invalid max DP link bw val %x, using 1.62Gbps\n",
@@ -210,7 +209,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
                target_clock = fixed_mode->clock;
        }
 
-       max_link_clock = drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp));
+       max_link_clock = intel_dp_max_link_rate(intel_dp);
        max_lanes = intel_dp_max_lane_count(intel_dp);
 
        max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
@@ -240,7 +239,7 @@ uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes)
        return v;
 }
 
-void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
+static void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
 {
        int i;
        if (dst_bytes > 4)
@@ -943,8 +942,9 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        size_t txsize, rxsize;
        int ret;
 
-       txbuf[0] = msg->request << 4;
-       txbuf[1] = msg->address >> 8;
+       txbuf[0] = (msg->request << 4) |
+               ((msg->address >> 16) & 0xf);
+       txbuf[1] = (msg->address >> 8) & 0xff;
        txbuf[2] = msg->address & 0xff;
        txbuf[3] = msg->size - 1;
 
@@ -952,7 +952,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        case DP_AUX_NATIVE_WRITE:
        case DP_AUX_I2C_WRITE:
                txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
-               rxsize = 1;
+               rxsize = 2; /* 0 or 1 data bytes */
 
                if (WARN_ON(txsize > 20))
                        return -E2BIG;
@@ -963,8 +963,13 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                if (ret > 0) {
                        msg->reply = rxbuf[0] >> 4;
 
-                       /* Return payload size. */
-                       ret = msg->size;
+                       if (ret > 1) {
+                               /* Number of bytes written in a short write. */
+                               ret = clamp_t(int, rxbuf[1], 0, msg->size);
+                       } else {
+                               /* Return payload size. */
+                               ret = msg->size;
+                       }
                }
                break;
 
@@ -1075,7 +1080,7 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector)
 }
 
 static void
-skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_bw)
+skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock)
 {
        u32 ctrl1;
 
@@ -1084,19 +1089,35 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_bw)
        pipe_config->dpll_hw_state.cfgcr2 = 0;
 
        ctrl1 = DPLL_CTRL1_OVERRIDE(SKL_DPLL0);
-       switch (link_bw) {
-       case DP_LINK_BW_1_62:
+       switch (link_clock / 2) {
+       case 81000:
                ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_810,
                                              SKL_DPLL0);
                break;
-       case DP_LINK_BW_2_7:
+       case 135000:
                ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1350,
                                              SKL_DPLL0);
                break;
-       case DP_LINK_BW_5_4:
+       case 270000:
                ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2700,
                                              SKL_DPLL0);
                break;
+       case 162000:
+               ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1620,
+                                             SKL_DPLL0);
+               break;
+       /* TBD: For DP link rates 2.16 GHz and 4.32 GHz, VCO is 8640 which
+       results in CDCLK change. Need to handle the change of CDCLK by
+       disabling pipes and re-enabling them */
+       case 108000:
+               ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1080,
+                                             SKL_DPLL0);
+               break;
+       case 216000:
+               ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2160,
+                                             SKL_DPLL0);
+               break;
+
        }
        pipe_config->dpll_hw_state.ctrl1 = ctrl1;
 }
@@ -1117,6 +1138,42 @@ hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw)
        }
 }
 
+static int
+intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
+{
+       if (intel_dp->num_sink_rates) {
+               *sink_rates = intel_dp->sink_rates;
+               return intel_dp->num_sink_rates;
+       }
+
+       *sink_rates = default_rates;
+
+       return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
+}
+
+static int
+intel_dp_source_rates(struct drm_device *dev, const int **source_rates)
+{
+       if (INTEL_INFO(dev)->gen >= 9) {
+               *source_rates = gen9_rates;
+               return ARRAY_SIZE(gen9_rates);
+       } else if (IS_CHERRYVIEW(dev)) {
+               *source_rates = chv_rates;
+               return ARRAY_SIZE(chv_rates);
+       }
+
+       *source_rates = default_rates;
+
+       if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0)
+               /* WaDisableHBR2:skl */
+               return (DP_LINK_BW_2_7 >> 3) + 1;
+       else if (INTEL_INFO(dev)->gen >= 8 ||
+           (IS_HASWELL(dev) && !IS_HSW_ULX(dev)))
+               return (DP_LINK_BW_5_4 >> 3) + 1;
+       else
+               return (DP_LINK_BW_2_7 >> 3) + 1;
+}
+
 static void
 intel_dp_set_clock(struct intel_encoder *encoder,
                   struct intel_crtc_state *pipe_config, int link_bw)
@@ -1150,6 +1207,113 @@ intel_dp_set_clock(struct intel_encoder *encoder,
        }
 }
 
+static int intersect_rates(const int *source_rates, int source_len,
+                          const int *sink_rates, int sink_len,
+                          int *common_rates)
+{
+       int i = 0, j = 0, k = 0;
+
+       while (i < source_len && j < sink_len) {
+               if (source_rates[i] == sink_rates[j]) {
+                       if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
+                               return k;
+                       common_rates[k] = source_rates[i];
+                       ++k;
+                       ++i;
+                       ++j;
+               } else if (source_rates[i] < sink_rates[j]) {
+                       ++i;
+               } else {
+                       ++j;
+               }
+       }
+       return k;
+}
+
+static int intel_dp_common_rates(struct intel_dp *intel_dp,
+                                int *common_rates)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       const int *source_rates, *sink_rates;
+       int source_len, sink_len;
+
+       sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+       source_len = intel_dp_source_rates(dev, &source_rates);
+
+       return intersect_rates(source_rates, source_len,
+                              sink_rates, sink_len,
+                              common_rates);
+}
+
+static void snprintf_int_array(char *str, size_t len,
+                              const int *array, int nelem)
+{
+       int i;
+
+       str[0] = '\0';
+
+       for (i = 0; i < nelem; i++) {
+               int r = snprintf(str, len, "%d,", array[i]);
+               if (r >= len)
+                       return;
+               str += r;
+               len -= r;
+       }
+}
+
+static void intel_dp_print_rates(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       const int *source_rates, *sink_rates;
+       int source_len, sink_len, common_len;
+       int common_rates[DP_MAX_SUPPORTED_RATES];
+       char str[128]; /* FIXME: too big for stack? */
+
+       if ((drm_debug & DRM_UT_KMS) == 0)
+               return;
+
+       source_len = intel_dp_source_rates(dev, &source_rates);
+       snprintf_int_array(str, sizeof(str), source_rates, source_len);
+       DRM_DEBUG_KMS("source rates: %s\n", str);
+
+       sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+       snprintf_int_array(str, sizeof(str), sink_rates, sink_len);
+       DRM_DEBUG_KMS("sink rates: %s\n", str);
+
+       common_len = intel_dp_common_rates(intel_dp, common_rates);
+       snprintf_int_array(str, sizeof(str), common_rates, common_len);
+       DRM_DEBUG_KMS("common rates: %s\n", str);
+}
+
+static int rate_to_index(int find, const int *rates)
+{
+       int i = 0;
+
+       for (i = 0; i < DP_MAX_SUPPORTED_RATES; ++i)
+               if (find == rates[i])
+                       break;
+
+       return i;
+}
+
+int
+intel_dp_max_link_rate(struct intel_dp *intel_dp)
+{
+       int rates[DP_MAX_SUPPORTED_RATES] = {};
+       int len;
+
+       len = intel_dp_common_rates(intel_dp, rates);
+       if (WARN_ON(len <= 0))
+               return 162000;
+
+       return rates[rate_to_index(0, rates) - 1];
+}
+
+int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
+{
+       return rate_to_index(rate, intel_dp->sink_rates);
+}
+
 bool
 intel_dp_compute_config(struct intel_encoder *encoder,
                        struct intel_crtc_state *pipe_config)
@@ -1159,17 +1323,25 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
-       struct intel_crtc *intel_crtc = encoder->new_crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
        struct intel_connector *intel_connector = intel_dp->attached_connector;
        int lane_count, clock;
        int min_lane_count = 1;
        int max_lane_count = intel_dp_max_lane_count(intel_dp);
        /* Conveniently, the link BW constants become indices with a shift...*/
        int min_clock = 0;
-       int max_clock = intel_dp_max_link_bw(intel_dp) >> 3;
+       int max_clock;
        int bpp, mode_rate;
-       static int bws[] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7, DP_LINK_BW_5_4 };
        int link_avail, link_clock;
+       int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+       int common_len;
+
+       common_len = intel_dp_common_rates(intel_dp, common_rates);
+
+       /* No common link rates between source and sink */
+       WARN_ON(common_len <= 0);
+
+       max_clock = common_len - 1;
 
        if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A)
                pipe_config->has_pch_encoder = true;
@@ -1193,8 +1365,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                return false;
 
        DRM_DEBUG_KMS("DP link computation with max lane count %i "
-                     "max bw %02x pixel clock %iKHz\n",
-                     max_lane_count, bws[max_clock],
+                     "max bw %d pixel clock %iKHz\n",
+                     max_lane_count, common_rates[max_clock],
                      adjusted_mode->crtc_clock);
 
        /* Walk through all bpp values. Luckily they're all nicely spaced with 2
@@ -1223,8 +1395,11 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                                                   bpp);
 
                for (clock = min_clock; clock <= max_clock; clock++) {
-                       for (lane_count = min_lane_count; lane_count <= max_lane_count; lane_count <<= 1) {
-                               link_clock = drm_dp_bw_code_to_link_rate(bws[clock]);
+                       for (lane_count = min_lane_count;
+                               lane_count <= max_lane_count;
+                               lane_count <<= 1) {
+
+                               link_clock = common_rates[clock];
                                link_avail = intel_dp_max_data_rate(link_clock,
                                                                    lane_count);
 
@@ -1253,10 +1428,20 @@ found:
        if (intel_dp->color_range)
                pipe_config->limited_color_range = true;
 
-       intel_dp->link_bw = bws[clock];
        intel_dp->lane_count = lane_count;
+
+       if (intel_dp->num_sink_rates) {
+               intel_dp->link_bw = 0;
+               intel_dp->rate_select =
+                       intel_dp_rate_select(intel_dp, common_rates[clock]);
+       } else {
+               intel_dp->link_bw =
+                       drm_dp_link_rate_to_bw_code(common_rates[clock]);
+               intel_dp->rate_select = 0;
+       }
+
        pipe_config->pipe_bpp = bpp;
-       pipe_config->port_clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
+       pipe_config->port_clock = common_rates[clock];
 
        DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n",
                      intel_dp->link_bw, intel_dp->lane_count,
@@ -1279,7 +1464,7 @@ found:
        }
 
        if (IS_SKYLAKE(dev) && is_edp(intel_dp))
-               skl_edp_set_pll_config(pipe_config, intel_dp->link_bw);
+               skl_edp_set_pll_config(pipe_config, common_rates[clock]);
        else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                hsw_dp_set_ddi_pll_sel(pipe_config, intel_dp->link_bw);
        else
@@ -2691,11 +2876,14 @@ static uint8_t
 intel_dp_voltage_max(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
        enum port port = dp_to_dig_port(intel_dp)->port;
 
-       if (INTEL_INFO(dev)->gen >= 9)
+       if (INTEL_INFO(dev)->gen >= 9) {
+               if (dev_priv->vbt.edp_low_vswing && port == PORT_A)
+                       return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
                return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
-       else if (IS_VALLEYVIEW(dev))
+       else if (IS_VALLEYVIEW(dev))
                return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
        else if (IS_GEN7(dev) && port == PORT_A)
                return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
@@ -2719,6 +2907,8 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
                        return DP_TRAIN_PRE_EMPH_LEVEL_2;
                case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                        return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
                default:
                        return DP_TRAIN_PRE_EMPH_LEVEL_0;
                }
@@ -3201,6 +3391,9 @@ intel_hsw_signal_levels(uint8_t train_set)
                return DDI_BUF_TRANS_SELECT(7);
        case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return DDI_BUF_TRANS_SELECT(8);
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return DDI_BUF_TRANS_SELECT(9);
        default:
                DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
                              "0x%x\n", signal_levels);
@@ -3358,6 +3551,9 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
        if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
                link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
        drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
+       if (intel_dp->num_sink_rates)
+               drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
+                               &intel_dp->rate_select, 1);
 
        link_config[0] = 0;
        link_config[1] = DP_SET_ANSI_8B10B;
@@ -3570,6 +3766,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
        struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       uint8_t rev;
 
        if (intel_dp_dpcd_read_wake(&intel_dp->aux, 0x000, intel_dp->dpcd,
                                    sizeof(intel_dp->dpcd)) < 0)
@@ -3601,6 +3798,32 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
        } else
                intel_dp->use_tps3 = false;
 
+       /* Intermediate frequency support */
+       if (is_edp(intel_dp) &&
+           (intel_dp->dpcd[DP_EDP_CONFIGURATION_CAP] & DP_DPCD_DISPLAY_CONTROL_CAPABLE) &&
+           (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_EDP_DPCD_REV, &rev, 1) == 1) &&
+           (rev >= 0x03)) { /* eDp v1.4 or higher */
+               __le16 sink_rates[DP_MAX_SUPPORTED_RATES];
+               int i;
+
+               intel_dp_dpcd_read_wake(&intel_dp->aux,
+                               DP_SUPPORTED_LINK_RATES,
+                               sink_rates,
+                               sizeof(sink_rates));
+
+               for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
+                       int val = le16_to_cpu(sink_rates[i]);
+
+                       if (val == 0)
+                               break;
+
+                       intel_dp->sink_rates[i] = val * 200;
+               }
+               intel_dp->num_sink_rates = i;
+       }
+
+       intel_dp_print_rates(intel_dp);
+
        if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
              DP_DWN_STRM_PORT_PRESENT))
                return true; /* native DP sink */
@@ -3803,7 +4026,7 @@ go_again:
  *  3. Use Link Training from 2.5.3.3 and 3.5.1.3
  *  4. Check link status on receipt of hot-plug interrupt
  */
-void
+static void
 intel_dp_check_link_status(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -4390,6 +4613,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_dp_connector_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
@@ -4736,6 +4960,18 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
                      I915_READ(pp_div_reg));
 }
 
+/**
+ * intel_dp_set_drrs_state - program registers for RR switch to take effect
+ * @dev: DRM device
+ * @refresh_rate: RR to be programmed
+ *
+ * This function gets called when refresh rate (RR) has to be changed from
+ * one frequency to another. Switches can be between high and low RR
+ * supported by the panel or to any other RR based on media playback (in
+ * this case, RR value needs to be passed from user space).
+ *
+ * The caller of this function needs to take a lock on dev_priv->drrs.
+ */
 static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4764,7 +5000,7 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
 
        dig_port = dp_to_dig_port(intel_dp);
        encoder = &dig_port->base;
-       intel_crtc = encoder->new_crtc;
+       intel_crtc = to_intel_crtc(encoder->base.crtc);
 
        if (!intel_crtc) {
                DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n");
@@ -4793,14 +5029,32 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
                return;
        }
 
-       if (INTEL_INFO(dev)->gen > 6 && INTEL_INFO(dev)->gen < 8) {
+       if (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev)) {
+               switch (index) {
+               case DRRS_HIGH_RR:
+                       intel_dp_set_m_n(intel_crtc, M1_N1);
+                       break;
+               case DRRS_LOW_RR:
+                       intel_dp_set_m_n(intel_crtc, M2_N2);
+                       break;
+               case DRRS_MAX_RR:
+               default:
+                       DRM_ERROR("Unsupported refreshrate type\n");
+               }
+       } else if (INTEL_INFO(dev)->gen > 6) {
                reg = PIPECONF(intel_crtc->config->cpu_transcoder);
                val = I915_READ(reg);
+
                if (index > DRRS_HIGH_RR) {
-                       val |= PIPECONF_EDP_RR_MODE_SWITCH;
-                       intel_dp_set_m_n(intel_crtc);
+                       if (IS_VALLEYVIEW(dev))
+                               val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
+                       else
+                               val |= PIPECONF_EDP_RR_MODE_SWITCH;
                } else {
-                       val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
+                       if (IS_VALLEYVIEW(dev))
+                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
+                       else
+                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
                }
                I915_WRITE(reg, val);
        }
@@ -4810,6 +5064,12 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
        DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
 }
 
+/**
+ * intel_edp_drrs_enable - init drrs struct if supported
+ * @intel_dp: DP struct
+ *
+ * Initializes frontbuffer_bits and drrs.dp
+ */
 void intel_edp_drrs_enable(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -4837,6 +5097,11 @@ unlock:
        mutex_unlock(&dev_priv->drrs.mutex);
 }
 
+/**
+ * intel_edp_drrs_disable - Disable DRRS
+ * @intel_dp: DP struct
+ *
+ */
 void intel_edp_drrs_disable(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -4896,6 +5161,17 @@ unlock:
        mutex_unlock(&dev_priv->drrs.mutex);
 }
 
+/**
+ * intel_edp_drrs_invalidate - Invalidate DRRS
+ * @dev: DRM device
+ * @frontbuffer_bits: frontbuffer plane tracking bits
+ *
+ * When there is a disturbance on screen (due to cursor movement/time
+ * update etc), DRRS needs to be invalidated, i.e. need to switch to
+ * high RR.
+ *
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
+ */
 void intel_edp_drrs_invalidate(struct drm_device *dev,
                unsigned frontbuffer_bits)
 {
@@ -4906,12 +5182,13 @@ void intel_edp_drrs_invalidate(struct drm_device *dev,
        if (!dev_priv->drrs.dp)
                return;
 
+       cancel_delayed_work_sync(&dev_priv->drrs.work);
+
        mutex_lock(&dev_priv->drrs.mutex);
        crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
        pipe = to_intel_crtc(crtc)->pipe;
 
        if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) {
-               cancel_delayed_work_sync(&dev_priv->drrs.work);
                intel_dp_set_drrs_state(dev_priv->dev,
                                dev_priv->drrs.dp->attached_connector->panel.
                                fixed_mode->vrefresh);
@@ -4923,6 +5200,17 @@ void intel_edp_drrs_invalidate(struct drm_device *dev,
        mutex_unlock(&dev_priv->drrs.mutex);
 }
 
+/**
+ * intel_edp_drrs_flush - Flush DRRS
+ * @dev: DRM device
+ * @frontbuffer_bits: frontbuffer plane tracking bits
+ *
+ * When there is no movement on screen, DRRS work can be scheduled.
+ * This DRRS work is responsible for setting relevant registers after a
+ * timeout of 1 second.
+ *
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
+ */
 void intel_edp_drrs_flush(struct drm_device *dev,
                unsigned frontbuffer_bits)
 {
@@ -4933,13 +5221,13 @@ void intel_edp_drrs_flush(struct drm_device *dev,
        if (!dev_priv->drrs.dp)
                return;
 
+       cancel_delayed_work_sync(&dev_priv->drrs.work);
+
        mutex_lock(&dev_priv->drrs.mutex);
        crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
        pipe = to_intel_crtc(crtc)->pipe;
        dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
 
-       cancel_delayed_work_sync(&dev_priv->drrs.work);
-
        if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR &&
                        !dev_priv->drrs.busy_frontbuffer_bits)
                schedule_delayed_work(&dev_priv->drrs.work,
@@ -4947,6 +5235,56 @@ void intel_edp_drrs_flush(struct drm_device *dev,
        mutex_unlock(&dev_priv->drrs.mutex);
 }
 
+/**
+ * DOC: Display Refresh Rate Switching (DRRS)
+ *
+ * Display Refresh Rate Switching (DRRS) is a power conservation feature
+ * which enables swtching between low and high refresh rates,
+ * dynamically, based on the usage scenario. This feature is applicable
+ * for internal panels.
+ *
+ * Indication that the panel supports DRRS is given by the panel EDID, which
+ * would list multiple refresh rates for one resolution.
+ *
+ * DRRS is of 2 types - static and seamless.
+ * Static DRRS involves changing refresh rate (RR) by doing a full modeset
+ * (may appear as a blink on screen) and is used in dock-undock scenario.
+ * Seamless DRRS involves changing RR without any visual effect to the user
+ * and can be used during normal system usage. This is done by programming
+ * certain registers.
+ *
+ * Support for static/seamless DRRS may be indicated in the VBT based on
+ * inputs from the panel spec.
+ *
+ * DRRS saves power by switching to low RR based on usage scenarios.
+ *
+ * eDP DRRS:-
+ *        The implementation is based on frontbuffer tracking implementation.
+ * When there is a disturbance on the screen triggered by user activity or a
+ * periodic system activity, DRRS is disabled (RR is changed to high RR).
+ * When there is no movement on screen, after a timeout of 1 second, a switch
+ * to low RR is made.
+ *        For integration with frontbuffer tracking code,
+ * intel_edp_drrs_invalidate() and intel_edp_drrs_flush() are called.
+ *
+ * DRRS can be further extended to support other internal panels and also
+ * the scenario of video playback wherein RR is set based on the rate
+ * requested by userspace.
+ */
+
+/**
+ * intel_dp_drrs_init - Init basic DRRS work and mutex.
+ * @intel_connector: eDP connector
+ * @fixed_mode: preferred mode of panel
+ *
+ * This function is  called only once at driver load to initialize basic
+ * DRRS stuff.
+ *
+ * Returns:
+ * Downclock mode if panel supports it, else return NULL.
+ * DRRS support is determined by the presence of downclock mode (apart
+ * from VBT setting).
+ */
 static struct drm_display_mode *
 intel_dp_drrs_init(struct intel_connector *intel_connector,
                struct drm_display_mode *fixed_mode)
@@ -4970,7 +5308,7 @@ intel_dp_drrs_init(struct intel_connector *intel_connector,
                                        (dev, fixed_mode, connector);
 
        if (!downclock_mode) {
-               DRM_DEBUG_KMS("DRRS not supported\n");
+               DRM_DEBUG_KMS("Downclock mode is not found. DRRS not supported\n");
                return NULL;
        }
 
@@ -5000,8 +5338,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        struct edid *edid;
        enum pipe pipe = INVALID_PIPE;
 
-       dev_priv->drrs.type = DRRS_NOT_SUPPORTED;
-
        if (!is_edp(intel_dp))
                return true;
 
index 9f67a379a9a5946da1ea4b1601069683638d783b..5329c855acce71f4fab98385900e5c99511be986 100644 (file)
@@ -36,11 +36,11 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
        struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
        struct intel_digital_port *intel_dig_port = intel_mst->primary;
        struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_device *dev = encoder->base.dev;
-       int bpp;
-       int lane_count, slots;
+       struct drm_atomic_state *state;
+       int bpp, i;
+       int lane_count, slots, rate;
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct intel_connector *found = NULL, *intel_connector;
+       struct intel_connector *found = NULL;
        int mst_pbn;
 
        pipe_config->dp_encoder_is_mst = true;
@@ -52,15 +52,30 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
         * seem to suggest we should do otherwise.
         */
        lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
-       intel_dp->link_bw = intel_dp_max_link_bw(intel_dp);
+
+       rate = intel_dp_max_link_rate(intel_dp);
+
+       if (intel_dp->num_sink_rates) {
+               intel_dp->link_bw = 0;
+               intel_dp->rate_select = intel_dp_rate_select(intel_dp, rate);
+       } else {
+               intel_dp->link_bw = drm_dp_link_rate_to_bw_code(rate);
+               intel_dp->rate_select = 0;
+       }
+
        intel_dp->lane_count = lane_count;
 
        pipe_config->pipe_bpp = 24;
-       pipe_config->port_clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
+       pipe_config->port_clock = rate;
 
-       list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head) {
-               if (intel_connector->new_encoder == encoder) {
-                       found = intel_connector;
+       state = pipe_config->base.state;
+
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
+                       continue;
+
+               if (state->connector_states[i]->best_encoder == &encoder->base) {
+                       found = to_intel_connector(state->connectors[i]);
                        break;
                }
        }
@@ -140,7 +155,7 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
        struct drm_crtc *crtc = encoder->base.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head) {
+       for_each_intel_connector(dev, intel_connector) {
                if (intel_connector->new_encoder == encoder) {
                        found = intel_connector;
                        break;
@@ -317,6 +332,7 @@ static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_dp_mst_connector_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static int intel_dp_mst_get_modes(struct drm_connector *connector)
index eef79ccd0b7ca9c20329021175543720e2756a9b..6036e3b73b7b9dd7a20cef915643dcb707e055be 100644 (file)
@@ -35,6 +35,7 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_atomic.h>
 
 #define DIV_ROUND_CLOSEST_ULL(ll, d)   \
 ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
@@ -56,8 +57,8 @@
                                ret__ = -ETIMEDOUT;                     \
                        break;                                          \
                }                                                       \
-               if (W && drm_can_sleep())  {                            \
-                       msleep(W);                                      \
+               if ((W) && drm_can_sleep()) {                           \
+                       usleep_range((W)*1000, (W)*2000);               \
                } else {                                                \
                        cpu_relax();                                    \
                }                                                       \
@@ -258,6 +259,7 @@ struct intel_plane_state {
 };
 
 struct intel_initial_plane_config {
+       struct intel_framebuffer *fb;
        unsigned int tiling;
        int size;
        u32 base;
@@ -463,7 +465,6 @@ struct intel_crtc {
 
        struct drm_i915_gem_object *cursor_bo;
        uint32_t cursor_addr;
-       int16_t cursor_width, cursor_height;
        uint32_t cursor_cntl;
        uint32_t cursor_size;
        uint32_t cursor_base;
@@ -500,16 +501,20 @@ struct intel_plane_wm_parameters {
        uint8_t bytes_per_pixel;
        bool enabled;
        bool scaled;
+       u64 tiling;
+       unsigned int rotation;
 };
 
 struct intel_plane {
        struct drm_plane base;
        int plane;
        enum pipe pipe;
-       struct drm_i915_gem_object *obj;
        bool can_scale;
        int max_downscale;
 
+       /* FIXME convert to properties */
+       struct drm_intel_sprite_colorkey ckey;
+
        /* Since we need to change the watermarks before/after
         * enabling/disabling the planes, we need to store the parameters here
         * as the other pieces of the struct may not reflect the values we want
@@ -526,7 +531,6 @@ struct intel_plane {
        void (*update_plane)(struct drm_plane *plane,
                             struct drm_crtc *crtc,
                             struct drm_framebuffer *fb,
-                            struct drm_i915_gem_object *obj,
                             int crtc_x, int crtc_y,
                             unsigned int crtc_w, unsigned int crtc_h,
                             uint32_t x, uint32_t y,
@@ -537,10 +541,6 @@ struct intel_plane {
                           struct intel_plane_state *state);
        void (*commit_plane)(struct drm_plane *plane,
                             struct intel_plane_state *state);
-       int (*update_colorkey)(struct drm_plane *plane,
-                              struct drm_intel_sprite_colorkey *key);
-       void (*get_colorkey)(struct drm_plane *plane,
-                            struct drm_intel_sprite_colorkey *key);
 };
 
 struct intel_watermark_params {
@@ -563,6 +563,7 @@ struct cxsr_latency {
 };
 
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
+#define to_intel_crtc_state(x) container_of(x, struct intel_crtc_state, base)
 #define to_intel_connector(x) container_of(x, struct intel_connector, base)
 #define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
@@ -592,6 +593,26 @@ struct intel_hdmi {
 struct intel_dp_mst_encoder;
 #define DP_MAX_DOWNSTREAM_PORTS                0x10
 
+/*
+ * enum link_m_n_set:
+ *     When platform provides two set of M_N registers for dp, we can
+ *     program them and switch between them incase of DRRS.
+ *     But When only one such register is provided, we have to program the
+ *     required divider value on that registers itself based on the DRRS state.
+ *
+ * M1_N1       : Program dp_m_n on M1_N1 registers
+ *                       dp_m2_n2 on M2_N2 registers (If supported)
+ *
+ * M2_N2       : Program dp_m2_n2 on M1_N1 registers
+ *                       M2_N2 registers are not supported
+ */
+
+enum link_m_n_set {
+       /* Sets the m1_n1 and m2_n2 */
+       M1_N1 = 0,
+       M2_N2
+};
+
 struct intel_dp {
        uint32_t output_reg;
        uint32_t aux_ch_ctl_reg;
@@ -601,10 +622,14 @@ struct intel_dp {
        uint32_t color_range;
        bool color_range_auto;
        uint8_t link_bw;
+       uint8_t rate_select;
        uint8_t lane_count;
        uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
        uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
        uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
+       /* sink rates as reported by DP_SUPPORTED_LINK_RATES */
+       uint8_t num_sink_rates;
+       int sink_rates[DP_MAX_SUPPORTED_RATES];
        struct drm_dp_aux aux;
        uint8_t train_set[4];
        int panel_power_up_delay;
@@ -710,7 +735,7 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane)
 struct intel_unpin_work {
        struct work_struct work;
        struct drm_crtc *crtc;
-       struct drm_i915_gem_object *old_fb_obj;
+       struct drm_framebuffer *old_fb;
        struct drm_i915_gem_object *pending_flip_obj;
        struct drm_pending_vblank_event *event;
        atomic_t pending;
@@ -817,7 +842,8 @@ static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
 }
 
 int intel_get_crtc_scanline(struct intel_crtc *crtc);
-void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv);
+void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
+                                    unsigned int pipe_mask);
 
 /* intel_crt.c */
 void intel_crt_init(struct drm_device *dev);
@@ -852,7 +878,8 @@ void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 
 /* intel_frontbuffer.c */
 void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
-                            struct intel_engine_cs *ring);
+                            struct intel_engine_cs *ring,
+                            enum fb_op_origin origin);
 void intel_frontbuffer_flip_prepare(struct drm_device *dev,
                                    unsigned frontbuffer_bits);
 void intel_frontbuffer_flip_complete(struct drm_device *dev,
@@ -877,10 +904,14 @@ void intel_frontbuffer_flip(struct drm_device *dev,
        intel_frontbuffer_flush(dev, frontbuffer_bits);
 }
 
-int intel_fb_align_height(struct drm_device *dev, int height,
-                         unsigned int tiling);
+unsigned int intel_fb_align_height(struct drm_device *dev,
+                                  unsigned int height,
+                                  uint32_t pixel_format,
+                                  uint64_t fb_format_modifier);
 void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
 
+u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier,
+                             uint32_t pixel_format);
 
 /* intel_audio.c */
 void intel_init_audio(struct drm_device *dev);
@@ -928,11 +959,12 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
                                struct intel_load_detect_pipe *old,
                                struct drm_modeset_acquire_ctx *ctx);
 void intel_release_load_detect_pipe(struct drm_connector *connector,
-                                   struct intel_load_detect_pipe *old);
+                                   struct intel_load_detect_pipe *old,
+                                   struct drm_modeset_acquire_ctx *ctx);
 int intel_pin_and_fence_fb_obj(struct drm_plane *plane,
                               struct drm_framebuffer *fb,
+                              const struct drm_plane_state *plane_state,
                               struct intel_engine_cs *pipelined);
-void intel_unpin_fb_obj(struct drm_i915_gem_object *obj);
 struct drm_framebuffer *
 __intel_framebuffer_create(struct drm_device *dev,
                           struct drm_mode_fb_cmd2 *mode_cmd,
@@ -942,9 +974,11 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe);
 void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
 void intel_check_page_flip(struct drm_device *dev, int pipe);
 int intel_prepare_plane_fb(struct drm_plane *plane,
-                          struct drm_framebuffer *fb);
+                          struct drm_framebuffer *fb,
+                          const struct drm_plane_state *new_state);
 void intel_cleanup_plane_fb(struct drm_plane *plane,
-                           struct drm_framebuffer *fb);
+                           struct drm_framebuffer *fb,
+                           const struct drm_plane_state *old_state);
 int intel_plane_atomic_get_property(struct drm_plane *plane,
                                    const struct drm_plane_state *state,
                                    struct drm_property *property,
@@ -954,6 +988,19 @@ int intel_plane_atomic_set_property(struct drm_plane *plane,
                                    struct drm_property *property,
                                    uint64_t val);
 
+unsigned int
+intel_tile_height(struct drm_device *dev, uint32_t pixel_format,
+                 uint64_t fb_format_modifier);
+
+static inline bool
+intel_rotation_90_or_270(unsigned int rotation)
+{
+       return rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270));
+}
+
+bool intel_wm_need_update(struct drm_plane *plane,
+                         struct drm_plane_state *state);
+
 /* shared dpll functions */
 struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
 void assert_shared_dpll(struct drm_i915_private *dev_priv,
@@ -993,7 +1040,7 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv);
 void hsw_disable_pc8(struct drm_i915_private *dev_priv);
 void intel_dp_get_m_n(struct intel_crtc *crtc,
                      struct intel_crtc_state *pipe_config);
-void intel_dp_set_m_n(struct intel_crtc *crtc);
+void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n);
 int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n);
 void
 ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config,
@@ -1008,6 +1055,9 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
 void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
 void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
 
+unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
+                                    struct drm_i915_gem_object *obj);
+
 /* intel_dp.c */
 void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
 bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
@@ -1017,7 +1067,6 @@ void intel_dp_complete_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
 void intel_dp_encoder_destroy(struct drm_encoder *encoder);
-void intel_dp_check_link_status(struct intel_dp *intel_dp);
 int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc);
 bool intel_dp_compute_config(struct intel_encoder *encoder,
                             struct intel_crtc_state *pipe_config);
@@ -1032,17 +1081,11 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector);
 void intel_dp_mst_suspend(struct drm_device *dev);
 void intel_dp_mst_resume(struct drm_device *dev);
-int intel_dp_max_link_bw(struct intel_dp *intel_dp);
+int intel_dp_max_link_rate(struct intel_dp *intel_dp);
+int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
 void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
 void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
 uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
-void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes);
-int intel_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);
-int intel_disable_plane(struct drm_plane *plane);
 void intel_plane_destroy(struct drm_plane *plane);
 void intel_edp_drrs_enable(struct intel_dp *intel_dp);
 void intel_edp_drrs_disable(struct intel_dp *intel_dp);
@@ -1097,7 +1140,11 @@ bool intel_fbc_enabled(struct drm_device *dev);
 void intel_fbc_update(struct drm_device *dev);
 void intel_fbc_init(struct drm_i915_private *dev_priv);
 void intel_fbc_disable(struct drm_device *dev);
-void bdw_fbc_sw_flush(struct drm_device *dev, u32 value);
+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);
 
 /* intel_hdmi.c */
 void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port);
@@ -1213,8 +1260,9 @@ void intel_enable_gt_powersave(struct drm_device *dev);
 void intel_disable_gt_powersave(struct drm_device *dev);
 void intel_suspend_gt_powersave(struct drm_device *dev);
 void intel_reset_gt_powersave(struct drm_device *dev);
-void ironlake_teardown_rc6(struct drm_device *dev);
 void gen6_update_ring_freq(struct drm_device *dev);
+void gen6_rps_busy(struct drm_i915_private *dev_priv);
+void gen6_rps_reset_ei(struct drm_i915_private *dev_priv);
 void gen6_rps_idle(struct drm_i915_private *dev_priv);
 void gen6_rps_boost(struct drm_i915_private *dev_priv);
 void ilk_wm_get_hw_state(struct drm_device *dev);
@@ -1231,14 +1279,9 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob);
 int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
 void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
                               enum plane plane);
-int intel_plane_set_property(struct drm_plane *plane,
-                            struct drm_property *prop,
-                            uint64_t val);
 int intel_plane_restore(struct drm_plane *plane);
 int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
-int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
-                             struct drm_file *file_priv);
 bool intel_pipe_update_start(struct intel_crtc *crtc,
                             uint32_t *start_vbl_count);
 void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count);
@@ -1261,6 +1304,17 @@ int intel_connector_atomic_get_property(struct drm_connector *connector,
 struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc);
 void intel_crtc_destroy_state(struct drm_crtc *crtc,
                               struct drm_crtc_state *state);
+static inline struct intel_crtc_state *
+intel_atomic_get_crtc_state(struct drm_atomic_state *state,
+                           struct intel_crtc *crtc)
+{
+       struct drm_crtc_state *crtc_state;
+       crtc_state = drm_atomic_get_crtc_state(state, &crtc->base);
+       if (IS_ERR(crtc_state))
+               return ERR_PTR(PTR_ERR(crtc_state));
+
+       return to_intel_crtc_state(crtc_state);
+}
 
 /* intel_atomic_plane.c */
 struct intel_plane_state *intel_create_plane_state(struct drm_plane *plane);
index 10ab68457ca885adb3d4125478731fd0816f6553..572251e9810bc40bacc3862ed23387d281fced4d 100644 (file)
@@ -854,7 +854,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
 
 
                /* recovery disables */
-               I915_WRITE(MIPI_EOT_DISABLE(port), val);
+               I915_WRITE(MIPI_EOT_DISABLE(port), tmp);
 
                /* in terms of low power clock */
                I915_WRITE(MIPI_INIT_COUNT(port), intel_dsi->init_count);
@@ -975,6 +975,7 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = {
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_get_property = intel_connector_atomic_get_property,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 void intel_dsi_init(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.h b/drivers/gpu/drm/i915/intel_dsi_cmd.h
deleted file mode 100644 (file)
index 8867790..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright Â© 2013 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.
- *
- * Author: Jani Nikula <jani.nikula@intel.com>
- */
-
-#ifndef _INTEL_DSI_DSI_H
-#define _INTEL_DSI_DSI_H
-
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <video/mipi_display.h>
-#include "i915_drv.h"
-#include "intel_drv.h"
-#include "intel_dsi.h"
-
-void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable,
-                                               enum port port);
-
-#endif /* _INTEL_DSI_DSI_H */
index d8579510beb018fc92ce0fb2a739b5b4a4d95b9b..4ccd6c3f133d3d3812bd2edc969760ff4a041ff9 100644 (file)
@@ -393,6 +393,7 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = {
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_get_property = intel_connector_atomic_get_property,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
index 624d1d92d2845a5f8d76640b21b4209bd5445c38..4165ce0644f7a959e6b53a4c34ac0178fd5bd7f6 100644 (file)
@@ -78,7 +78,8 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc)
 
        dev_priv->fbc.enabled = true;
 
-       cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
+       /* Note: fbc.threshold == 1 for i8xx */
+       cfb_pitch = dev_priv->fbc.uncompressed_size / FBC_LL_SIZE;
        if (fb->pitches[0] < cfb_pitch)
                cfb_pitch = fb->pitches[0];
 
@@ -173,29 +174,10 @@ static bool g4x_fbc_enabled(struct drm_device *dev)
        return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
 }
 
-static void snb_fbc_blit_update(struct drm_device *dev)
+static void intel_fbc_nuke(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 blt_ecoskpd;
-
-       /* Make sure blitter notifies FBC of writes */
-
-       /* Blitter is part of Media powerwell on VLV. No impact of
-        * his param in other platforms for now */
-       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_MEDIA);
-
-       blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
-       blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
-               GEN6_BLITTER_LOCK_SHIFT;
-       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-       blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
-       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-       blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
-                        GEN6_BLITTER_LOCK_SHIFT);
-       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-       POSTING_READ(GEN6_BLITTER_ECOSKPD);
-
-       intel_uncore_forcewake_put(dev_priv, FORCEWAKE_MEDIA);
+       I915_WRITE(MSG_FBC_REND_STATE, FBC_REND_NUKE);
+       POSTING_READ(MSG_FBC_REND_STATE);
 }
 
 static void ilk_fbc_enable(struct drm_crtc *crtc)
@@ -238,9 +220,10 @@ static void ilk_fbc_enable(struct drm_crtc *crtc)
                I915_WRITE(SNB_DPFC_CTL_SA,
                           SNB_CPU_FENCE_ENABLE | obj->fence_reg);
                I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
-               snb_fbc_blit_update(dev);
        }
 
+       intel_fbc_nuke(dev_priv);
+
        DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
 }
 
@@ -319,7 +302,7 @@ static void gen7_fbc_enable(struct drm_crtc *crtc)
                   SNB_CPU_FENCE_ENABLE | obj->fence_reg);
        I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
 
-       snb_fbc_blit_update(dev);
+       intel_fbc_nuke(dev_priv);
 
        DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
 }
@@ -339,19 +322,6 @@ bool intel_fbc_enabled(struct drm_device *dev)
        return dev_priv->fbc.enabled;
 }
 
-void bdw_fbc_sw_flush(struct drm_device *dev, u32 value)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (!IS_GEN8(dev))
-               return;
-
-       if (!intel_fbc_enabled(dev))
-               return;
-
-       I915_WRITE(MSG_FBC_REND_STATE, value);
-}
-
 static void intel_fbc_work_fn(struct work_struct *__work)
 {
        struct intel_fbc_work *work =
@@ -368,7 +338,7 @@ static void intel_fbc_work_fn(struct work_struct *__work)
                if (work->crtc->primary->fb == work->fb) {
                        dev_priv->display.enable_fbc(work->crtc);
 
-                       dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
+                       dev_priv->fbc.crtc = to_intel_crtc(work->crtc);
                        dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
                        dev_priv->fbc.y = work->crtc->y;
                }
@@ -459,7 +429,7 @@ void intel_fbc_disable(struct drm_device *dev)
                return;
 
        dev_priv->display.disable_fbc(dev);
-       dev_priv->fbc.plane = -1;
+       dev_priv->fbc.crtc = NULL;
 }
 
 static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
@@ -472,6 +442,43 @@ static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
        return true;
 }
 
+static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv)
+{
+       struct drm_crtc *crtc = NULL, *tmp_crtc;
+       enum pipe pipe;
+       bool pipe_a_only = false, one_pipe_only = false;
+
+       if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
+               pipe_a_only = true;
+       else if (INTEL_INFO(dev_priv)->gen <= 4)
+               one_pipe_only = true;
+
+       for_each_pipe(dev_priv, pipe) {
+               tmp_crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+
+               if (intel_crtc_active(tmp_crtc) &&
+                   to_intel_crtc(tmp_crtc)->primary_enabled) {
+                       if (one_pipe_only && crtc) {
+                               if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
+                                       DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+                               return NULL;
+                       }
+                       crtc = tmp_crtc;
+               }
+
+               if (pipe_a_only)
+                       break;
+       }
+
+       if (!crtc || crtc->primary->fb == NULL) {
+               if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
+                       DRM_DEBUG_KMS("no output, disabling\n");
+               return NULL;
+       }
+
+       return crtc;
+}
+
 /**
  * intel_fbc_update - enable/disable FBC as needed
  * @dev: the drm_device
@@ -494,22 +501,30 @@ static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
 void intel_fbc_update(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = NULL, *tmp_crtc;
+       struct drm_crtc *crtc = NULL;
        struct intel_crtc *intel_crtc;
        struct drm_framebuffer *fb;
        struct drm_i915_gem_object *obj;
        const struct drm_display_mode *adjusted_mode;
        unsigned int max_width, max_height;
 
-       if (!HAS_FBC(dev)) {
-               set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
+       if (!HAS_FBC(dev))
                return;
+
+       /* disable framebuffer compression in vGPU */
+       if (intel_vgpu_active(dev))
+               i915.enable_fbc = 0;
+
+       if (i915.enable_fbc < 0) {
+               if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
+                       DRM_DEBUG_KMS("disabled per chip default\n");
+               goto out_disable;
        }
 
-       if (!i915.powersave) {
+       if (!i915.enable_fbc) {
                if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
                        DRM_DEBUG_KMS("fbc disabled per module param\n");
-               return;
+               goto out_disable;
        }
 
        /*
@@ -521,39 +536,15 @@ void intel_fbc_update(struct drm_device *dev)
         *   - new fb is too large to fit in compressed buffer
         *   - going to an unsupported config (interlace, pixel multiply, etc.)
         */
-       for_each_crtc(dev, tmp_crtc) {
-               if (intel_crtc_active(tmp_crtc) &&
-                   to_intel_crtc(tmp_crtc)->primary_enabled) {
-                       if (crtc) {
-                               if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
-                                       DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
-                               goto out_disable;
-                       }
-                       crtc = tmp_crtc;
-               }
-       }
-
-       if (!crtc || crtc->primary->fb == NULL) {
-               if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
-                       DRM_DEBUG_KMS("no output, disabling\n");
+       crtc = intel_fbc_find_crtc(dev_priv);
+       if (!crtc)
                goto out_disable;
-       }
 
        intel_crtc = to_intel_crtc(crtc);
        fb = crtc->primary->fb;
        obj = intel_fb_obj(fb);
        adjusted_mode = &intel_crtc->config->base.adjusted_mode;
 
-       if (i915.enable_fbc < 0) {
-               if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
-                       DRM_DEBUG_KMS("disabled per chip default\n");
-               goto out_disable;
-       }
-       if (!i915.enable_fbc) {
-               if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
-                       DRM_DEBUG_KMS("fbc disabled per module param\n");
-               goto out_disable;
-       }
        if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
            (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
                if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
@@ -617,7 +608,7 @@ void intel_fbc_update(struct drm_device *dev)
         * cannot be unpinned (and have its GTT offset and fence revoked)
         * without first being decoupled from the scanout and FBC disabled.
         */
-       if (dev_priv->fbc.plane == intel_crtc->plane &&
+       if (dev_priv->fbc.crtc == intel_crtc &&
            dev_priv->fbc.fb_id == fb->base.id &&
            dev_priv->fbc.y == crtc->y)
                return;
@@ -663,6 +654,44 @@ out_disable:
        i915_gem_stolen_cleanup_compression(dev);
 }
 
+void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
+                         unsigned int frontbuffer_bits,
+                         enum fb_op_origin origin)
+{
+       struct drm_device *dev = dev_priv->dev;
+       unsigned int fbc_bits;
+
+       if (origin == ORIGIN_GTT)
+               return;
+
+       if (dev_priv->fbc.enabled)
+               fbc_bits = INTEL_FRONTBUFFER_PRIMARY(dev_priv->fbc.crtc->pipe);
+       else if (dev_priv->fbc.fbc_work)
+               fbc_bits = INTEL_FRONTBUFFER_PRIMARY(
+                       to_intel_crtc(dev_priv->fbc.fbc_work->crtc)->pipe);
+       else
+               fbc_bits = dev_priv->fbc.possible_framebuffer_bits;
+
+       dev_priv->fbc.busy_bits |= (fbc_bits & frontbuffer_bits);
+
+       if (dev_priv->fbc.busy_bits)
+               intel_fbc_disable(dev);
+}
+
+void intel_fbc_flush(struct drm_i915_private *dev_priv,
+                    unsigned int frontbuffer_bits)
+{
+       struct drm_device *dev = dev_priv->dev;
+
+       if (!dev_priv->fbc.busy_bits)
+               return;
+
+       dev_priv->fbc.busy_bits &= ~frontbuffer_bits;
+
+       if (!dev_priv->fbc.busy_bits)
+               intel_fbc_update(dev);
+}
+
 /**
  * intel_fbc_init - Initialize FBC
  * @dev_priv: the i915 device
@@ -671,11 +700,22 @@ out_disable:
  */
 void intel_fbc_init(struct drm_i915_private *dev_priv)
 {
+       enum pipe pipe;
+
        if (!HAS_FBC(dev_priv)) {
                dev_priv->fbc.enabled = false;
+               dev_priv->fbc.no_fbc_reason = FBC_UNSUPPORTED;
                return;
        }
 
+       for_each_pipe(dev_priv, pipe) {
+               dev_priv->fbc.possible_framebuffer_bits |=
+                               INTEL_FRONTBUFFER_PRIMARY(pipe);
+
+               if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
+                       break;
+       }
+
        if (INTEL_INFO(dev_priv)->gen >= 7) {
                dev_priv->display.fbc_enabled = ilk_fbc_enabled;
                dev_priv->display.enable_fbc = gen7_fbc_enable;
index 3001a86746111f0045362161c8e5acdb6d78480a..4e7e7da2e03bed4f835ca6d9a0666cd131410502 100644 (file)
@@ -71,6 +71,31 @@ static int intel_fbdev_set_par(struct fb_info *info)
        return ret;
 }
 
+static int intel_fbdev_blank(int blank, struct fb_info *info)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+       struct intel_fbdev *ifbdev =
+               container_of(fb_helper, struct intel_fbdev, helper);
+       int ret;
+
+       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, NULL, ORIGIN_GTT);
+               mutex_unlock(&fb_helper->dev->struct_mutex);
+       }
+
+       return ret;
+}
+
 static struct fb_ops intelfb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
@@ -79,7 +104,7 @@ static struct fb_ops intelfb_ops = {
        .fb_copyarea = cfb_copyarea,
        .fb_imageblit = cfb_imageblit,
        .fb_pan_display = drm_fb_helper_pan_display,
-       .fb_blank = drm_fb_helper_blank,
+       .fb_blank = intel_fbdev_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
        .fb_debug_enter = drm_fb_helper_debug_enter,
        .fb_debug_leave = drm_fb_helper_debug_leave,
@@ -126,7 +151,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
        }
 
        /* Flush everything out, we'll be doing GTT only from now on */
-       ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL);
+       ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL);
        if (ret) {
                DRM_ERROR("failed to pin obj: %d\n", ret);
                goto out_fb;
@@ -594,7 +619,8 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
 
                cur_size = intel_crtc->config->base.adjusted_mode.crtc_vdisplay;
                cur_size = intel_fb_align_height(dev, cur_size,
-                                                plane_config->tiling);
+                                                fb->base.pixel_format,
+                                                fb->base.modifier[0]);
                cur_size *= fb->base.pitches[0];
                DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n",
                              pipe_name(intel_crtc->pipe),
index 04e248dd2259715426e8ad82b817b59d3634b24a..54daa66c697077f5b0609ddb5eec0d7989db780a 100644 (file)
@@ -282,16 +282,6 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
        return ret;
 }
 
-static bool
-__cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_priv,
-                                     enum pipe pipe)
-{
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-       return !intel_crtc->cpu_fifo_underrun_disabled;
-}
-
 /**
  * intel_set_pch_fifo_underrun_reporting - set PCH fifo underrun reporting state
  * @dev_priv: i915 device instance
@@ -352,9 +342,15 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
 void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
                                         enum pipe pipe)
 {
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+
+       /* We may be called too early in init, thanks BIOS! */
+       if (crtc == NULL)
+               return;
+
        /* GMCH can't disable fifo underruns, filter them. */
        if (HAS_GMCH_DISPLAY(dev_priv->dev) &&
-           !__cpu_fifo_underrun_reporting_enabled(dev_priv, pipe))
+           to_intel_crtc(crtc)->cpu_fifo_underrun_disabled)
                return;
 
        if (intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false))
index 73cb6e036445dd38f50503191db16d9fbf7a11b6..a20cffb78c0f495055df8de87a0755e3a06cdb16 100644 (file)
@@ -110,16 +110,11 @@ static void intel_mark_fb_busy(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe;
 
-       if (!i915.powersave)
-               return;
-
        for_each_pipe(dev_priv, pipe) {
                if (!(frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe)))
                        continue;
 
                intel_increase_pllclock(dev, pipe);
-               if (ring && intel_fbc_enabled(dev))
-                       ring->fbc_dirty = true;
        }
 }
 
@@ -127,6 +122,7 @@ static void intel_mark_fb_busy(struct drm_device *dev,
  * intel_fb_obj_invalidate - invalidate frontbuffer object
  * @obj: GEM object to invalidate
  * @ring: set for asynchronous rendering
+ * @origin: which operation caused the invalidation
  *
  * This function gets called every time rendering on the given object starts and
  * frontbuffer caching (fbc, low refresh rate for DRRS, panel self refresh) must
@@ -135,7 +131,8 @@ static void intel_mark_fb_busy(struct drm_device *dev,
  * scheduled.
  */
 void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
-                            struct intel_engine_cs *ring)
+                            struct intel_engine_cs *ring,
+                            enum fb_op_origin origin)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -158,6 +155,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
 
        intel_psr_invalidate(dev, obj->frontbuffer_bits);
        intel_edp_drrs_invalidate(dev, obj->frontbuffer_bits);
+       intel_fbc_invalidate(dev_priv, obj->frontbuffer_bits, origin);
 }
 
 /**
@@ -185,16 +183,7 @@ void intel_frontbuffer_flush(struct drm_device *dev,
 
        intel_edp_drrs_flush(dev, frontbuffer_bits);
        intel_psr_flush(dev, frontbuffer_bits);
-
-       /*
-        * FIXME: Unconditional fbc flushing here is a rather gross hack and
-        * needs to be reworked into a proper frontbuffer tracking scheme like
-        * psr employs.
-        */
-       if (dev_priv->fbc.need_sw_cache_clean) {
-               dev_priv->fbc.need_sw_cache_clean = false;
-               bdw_fbc_sw_flush(dev, FBC_REND_CACHE_CLEAN);
-       }
+       intel_fbc_flush(dev_priv, frontbuffer_bits);
 }
 
 /**
index 995c5b261f4f0f5cf295de8b08c95840a36ca0fe..cacbafdad3abd300a02d2d35e22dcc9fd2de037f 100644 (file)
@@ -951,19 +951,30 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
-static bool hdmi_12bpc_possible(struct intel_crtc *crtc)
+static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_device *dev = crtc_state->base.crtc->dev;
+       struct drm_atomic_state *state;
        struct intel_encoder *encoder;
+       struct drm_connector_state *connector_state;
        int count = 0, count_hdmi = 0;
+       int i;
 
        if (HAS_GMCH_DISPLAY(dev))
                return false;
 
-       for_each_intel_encoder(dev, encoder) {
-               if (encoder->new_crtc != crtc)
+       state = crtc_state->base.state;
+
+       for (i = 0; i < state->num_connector; i++) {
+               if (!state->connectors[i])
                        continue;
 
+               connector_state = state->connector_states[i];
+               if (connector_state->crtc != crtc_state->base.crtc)
+                       continue;
+
+               encoder = to_intel_encoder(connector_state->best_encoder);
+
                count_hdmi += encoder->type == INTEL_OUTPUT_HDMI;
                count++;
        }
@@ -1020,7 +1031,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
         */
        if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink &&
            clock_12bpc <= portclock_limit &&
-           hdmi_12bpc_possible(encoder->new_crtc)) {
+           hdmi_12bpc_possible(pipe_config)) {
                DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
                desired_bpp = 12*3;
 
@@ -1618,6 +1629,7 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_hdmi_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
index 0f358c5999ec8e0c8771a3d932447d281748a8b1..fcb074bd55dcb088308c49b862fd087698c27420 100644 (file)
@@ -254,8 +254,10 @@ u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj)
        return lrca >> 12;
 }
 
-static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_object *ctx_obj)
+static uint64_t execlists_ctx_descriptor(struct intel_engine_cs *ring,
+                                        struct drm_i915_gem_object *ctx_obj)
 {
+       struct drm_device *dev = ring->dev;
        uint64_t desc;
        uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj);
 
@@ -272,6 +274,13 @@ static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_object *ctx_obj)
         * signalling between Command Streamers */
        /* desc |= GEN8_CTX_FORCE_RESTORE; */
 
+       /* WaEnableForceRestoreInCtxtDescForVCS:skl */
+       if (IS_GEN9(dev) &&
+           INTEL_REVID(dev) <= SKL_REVID_B0 &&
+           (ring->id == BCS || ring->id == VCS ||
+           ring->id == VECS || ring->id == VCS2))
+               desc |= GEN8_CTX_FORCE_RESTORE;
+
        return desc;
 }
 
@@ -286,13 +295,13 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
 
        /* XXX: You must always write both descriptors in the order below. */
        if (ctx_obj1)
-               temp = execlists_ctx_descriptor(ctx_obj1);
+               temp = execlists_ctx_descriptor(ring, ctx_obj1);
        else
                temp = 0;
        desc[1] = (u32)(temp >> 32);
        desc[0] = (u32)temp;
 
-       temp = execlists_ctx_descriptor(ctx_obj0);
+       temp = execlists_ctx_descriptor(ring, ctx_obj0);
        desc[3] = (u32)(temp >> 32);
        desc[2] = (u32)temp;
 
@@ -503,18 +512,19 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
                 * If there isn't a request associated with this submission,
                 * create one as a temporary holder.
                 */
-               WARN(1, "execlist context submission without request");
                request = kzalloc(sizeof(*request), GFP_KERNEL);
                if (request == NULL)
                        return -ENOMEM;
                request->ring = ring;
                request->ctx = to;
+               kref_init(&request->ref);
+               request->uniq = dev_priv->request_uniq++;
+               i915_gem_context_reference(request->ctx);
        } else {
+               i915_gem_request_reference(request);
                WARN_ON(to != request->ctx);
        }
        request->tail = tail;
-       i915_gem_request_reference(request);
-       i915_gem_context_reference(request->ctx);
 
        intel_runtime_pm_get(dev_priv);
 
@@ -611,7 +621,7 @@ static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf,
  * @vmas: list of vmas.
  * @batch_obj: the batchbuffer to submit.
  * @exec_start: batchbuffer start virtual address pointer.
- * @flags: translated execbuffer call flags.
+ * @dispatch_flags: translated execbuffer call flags.
  *
  * This is the evil twin version of i915_gem_ringbuffer_submission. It abstracts
  * away the submission details of the execbuffer ioctl call.
@@ -624,7 +634,7 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
                               struct drm_i915_gem_execbuffer2 *args,
                               struct list_head *vmas,
                               struct drm_i915_gem_object *batch_obj,
-                              u64 exec_start, u32 flags)
+                              u64 exec_start, u32 dispatch_flags)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
@@ -697,10 +707,12 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
                dev_priv->relative_constants_mode = instp_mode;
        }
 
-       ret = ring->emit_bb_start(ringbuf, ctx, exec_start, flags);
+       ret = ring->emit_bb_start(ringbuf, ctx, exec_start, dispatch_flags);
        if (ret)
                return ret;
 
+       trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), dispatch_flags);
+
        i915_gem_execbuffer_move_to_active(vmas, ring);
        i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
 
@@ -731,7 +743,6 @@ void intel_execlists_retire_requests(struct intel_engine_cs *ring)
                if (ctx_obj && (ctx != ring->default_context))
                        intel_lr_context_unpin(ring, ctx);
                intel_runtime_pm_put(dev_priv);
-               i915_gem_context_unreference(ctx);
                list_del(&req->execlist_link);
                i915_gem_request_unreference(req);
        }
@@ -776,7 +787,7 @@ int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
        return 0;
 }
 
-/**
+/*
  * intel_logical_ring_advance_and_submit() - advance the tail and submit the workload
  * @ringbuf: Logical Ringbuffer to advance.
  *
@@ -785,9 +796,10 @@ int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
  * on a queue waiting for the ELSP to be ready to accept a new context submission. At that
  * point, the tail *inside* the context is updated and the ELSP written to.
  */
-void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf,
-                                          struct intel_context *ctx,
-                                          struct drm_i915_gem_request *request)
+static void
+intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf,
+                                     struct intel_context *ctx,
+                                     struct drm_i915_gem_request *request)
 {
        struct intel_engine_cs *ring = ringbuf->ring;
 
@@ -876,12 +888,9 @@ static int logical_ring_alloc_request(struct intel_engine_cs *ring,
                return ret;
        }
 
-       /* Hold a reference to the context this request belongs to
-        * (we will need it when the time comes to emit/retire the
-        * request).
-        */
        request->ctx = ctx;
        i915_gem_context_reference(request->ctx);
+       request->ringbuf = ctx->engine[ring->id].ringbuf;
 
        ring->outstanding_lazy_request = request;
        return 0;
@@ -1140,11 +1149,22 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
        return init_workarounds_ring(ring);
 }
 
+static int gen9_init_render_ring(struct intel_engine_cs *ring)
+{
+       int ret;
+
+       ret = gen8_init_common_ring(ring);
+       if (ret)
+               return ret;
+
+       return init_workarounds_ring(ring);
+}
+
 static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf,
                              struct intel_context *ctx,
-                             u64 offset, unsigned flags)
+                             u64 offset, unsigned dispatch_flags)
 {
-       bool ppgtt = !(flags & I915_DISPATCH_SECURE);
+       bool ppgtt = !(dispatch_flags & I915_DISPATCH_SECURE);
        int ret;
 
        ret = intel_logical_ring_begin(ringbuf, ctx, 4);
@@ -1316,6 +1336,39 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf,
        return 0;
 }
 
+static int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+                                             struct intel_context *ctx)
+{
+       struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+       struct render_state so;
+       struct drm_i915_file_private *file_priv = ctx->file_priv;
+       struct drm_file *file = file_priv ? file_priv->file : NULL;
+       int ret;
+
+       ret = i915_gem_render_state_prepare(ring, &so);
+       if (ret)
+               return ret;
+
+       if (so.rodata == NULL)
+               return 0;
+
+       ret = ring->emit_bb_start(ringbuf,
+                       ctx,
+                       so.ggtt_offset,
+                       I915_DISPATCH_SECURE);
+       if (ret)
+               goto out;
+
+       i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
+
+       ret = __i915_add_request(ring, file, so.obj);
+       /* intel_logical_ring_add_request moves object to inactive if it
+        * fails */
+out:
+       i915_gem_render_state_fini(&so);
+       return ret;
+}
+
 static int gen8_init_rcs_context(struct intel_engine_cs *ring,
                       struct intel_context *ctx)
 {
@@ -1399,7 +1452,10 @@ static int logical_render_ring_init(struct drm_device *dev)
        if (HAS_L3_DPF(dev))
                ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 
-       ring->init_hw = gen8_init_render_ring;
+       if (INTEL_INFO(dev)->gen >= 9)
+               ring->init_hw = gen9_init_render_ring;
+       else
+               ring->init_hw = gen8_init_render_ring;
        ring->init_context = gen8_init_rcs_context;
        ring->cleanup = intel_fini_pipe_control;
        ring->get_seqno = gen8_get_seqno;
@@ -1581,37 +1637,47 @@ cleanup_render_ring:
        return ret;
 }
 
-int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
-                                      struct intel_context *ctx)
+static u32
+make_rpcs(struct drm_device *dev)
 {
-       struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
-       struct render_state so;
-       struct drm_i915_file_private *file_priv = ctx->file_priv;
-       struct drm_file *file = file_priv ? file_priv->file : NULL;
-       int ret;
-
-       ret = i915_gem_render_state_prepare(ring, &so);
-       if (ret)
-               return ret;
+       u32 rpcs = 0;
 
-       if (so.rodata == NULL)
+       /*
+        * No explicit RPCS request is needed to ensure full
+        * slice/subslice/EU enablement prior to Gen9.
+       */
+       if (INTEL_INFO(dev)->gen < 9)
                return 0;
 
-       ret = ring->emit_bb_start(ringbuf,
-                       ctx,
-                       so.ggtt_offset,
-                       I915_DISPATCH_SECURE);
-       if (ret)
-               goto out;
+       /*
+        * Starting in Gen9, render power gating can leave
+        * slice/subslice/EU in a partially enabled state. We
+        * must make an explicit request through RPCS for full
+        * enablement.
+       */
+       if (INTEL_INFO(dev)->has_slice_pg) {
+               rpcs |= GEN8_RPCS_S_CNT_ENABLE;
+               rpcs |= INTEL_INFO(dev)->slice_total <<
+                       GEN8_RPCS_S_CNT_SHIFT;
+               rpcs |= GEN8_RPCS_ENABLE;
+       }
 
-       i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
+       if (INTEL_INFO(dev)->has_subslice_pg) {
+               rpcs |= GEN8_RPCS_SS_CNT_ENABLE;
+               rpcs |= INTEL_INFO(dev)->subslice_per_slice <<
+                       GEN8_RPCS_SS_CNT_SHIFT;
+               rpcs |= GEN8_RPCS_ENABLE;
+       }
 
-       ret = __i915_add_request(ring, file, so.obj);
-       /* intel_logical_ring_add_request moves object to inactive if it
-        * fails */
-out:
-       i915_gem_render_state_fini(&so);
-       return ret;
+       if (INTEL_INFO(dev)->has_eu_pg) {
+               rpcs |= INTEL_INFO(dev)->eu_per_subslice <<
+                       GEN8_RPCS_EU_MIN_SHIFT;
+               rpcs |= INTEL_INFO(dev)->eu_per_subslice <<
+                       GEN8_RPCS_EU_MAX_SHIFT;
+               rpcs |= GEN8_RPCS_ENABLE;
+       }
+
+       return rpcs;
 }
 
 static int
@@ -1659,7 +1725,8 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
        reg_state[CTX_LRI_HEADER_0] |= MI_LRI_FORCE_POSTED;
        reg_state[CTX_CONTEXT_CONTROL] = RING_CONTEXT_CONTROL(ring);
        reg_state[CTX_CONTEXT_CONTROL+1] =
-                       _MASKED_BIT_ENABLE((1<<3) | MI_RESTORE_INHIBIT);
+               _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH |
+                               CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT);
        reg_state[CTX_RING_HEAD] = RING_HEAD(ring->mmio_base);
        reg_state[CTX_RING_HEAD+1] = 0;
        reg_state[CTX_RING_TAIL] = RING_TAIL(ring->mmio_base);
@@ -1706,18 +1773,18 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
        reg_state[CTX_PDP1_LDW] = GEN8_RING_PDP_LDW(ring, 1);
        reg_state[CTX_PDP0_UDW] = GEN8_RING_PDP_UDW(ring, 0);
        reg_state[CTX_PDP0_LDW] = GEN8_RING_PDP_LDW(ring, 0);
-       reg_state[CTX_PDP3_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[3]);
-       reg_state[CTX_PDP3_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[3]);
-       reg_state[CTX_PDP2_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[2]);
-       reg_state[CTX_PDP2_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[2]);
-       reg_state[CTX_PDP1_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[1]);
-       reg_state[CTX_PDP1_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[1]);
-       reg_state[CTX_PDP0_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[0]);
-       reg_state[CTX_PDP0_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[0]);
+       reg_state[CTX_PDP3_UDW+1] = upper_32_bits(ppgtt->pdp.page_directory[3]->daddr);
+       reg_state[CTX_PDP3_LDW+1] = lower_32_bits(ppgtt->pdp.page_directory[3]->daddr);
+       reg_state[CTX_PDP2_UDW+1] = upper_32_bits(ppgtt->pdp.page_directory[2]->daddr);
+       reg_state[CTX_PDP2_LDW+1] = lower_32_bits(ppgtt->pdp.page_directory[2]->daddr);
+       reg_state[CTX_PDP1_UDW+1] = upper_32_bits(ppgtt->pdp.page_directory[1]->daddr);
+       reg_state[CTX_PDP1_LDW+1] = lower_32_bits(ppgtt->pdp.page_directory[1]->daddr);
+       reg_state[CTX_PDP0_UDW+1] = upper_32_bits(ppgtt->pdp.page_directory[0]->daddr);
+       reg_state[CTX_PDP0_LDW+1] = lower_32_bits(ppgtt->pdp.page_directory[0]->daddr);
        if (ring->id == RCS) {
                reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1);
-               reg_state[CTX_R_PWR_CLK_STATE] = 0x20c8;
-               reg_state[CTX_R_PWR_CLK_STATE+1] = 0;
+               reg_state[CTX_R_PWR_CLK_STATE] = GEN8_R_PWR_CLK_STATE;
+               reg_state[CTX_R_PWR_CLK_STATE+1] = make_rpcs(dev);
        }
 
        kunmap_atomic(reg_state);
@@ -1925,3 +1992,38 @@ error_unpin_ctx:
        drm_gem_object_unreference(&ctx_obj->base);
        return ret;
 }
+
+void intel_lr_context_reset(struct drm_device *dev,
+                       struct intel_context *ctx)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring;
+       int i;
+
+       for_each_ring(ring, dev_priv, i) {
+               struct drm_i915_gem_object *ctx_obj =
+                               ctx->engine[ring->id].state;
+               struct intel_ringbuffer *ringbuf =
+                               ctx->engine[ring->id].ringbuf;
+               uint32_t *reg_state;
+               struct page *page;
+
+               if (!ctx_obj)
+                       continue;
+
+               if (i915_gem_object_get_pages(ctx_obj)) {
+                       WARN(1, "Failed get_pages for context obj\n");
+                       continue;
+               }
+               page = i915_gem_object_get_page(ctx_obj, 1);
+               reg_state = kmap_atomic(page);
+
+               reg_state[CTX_RING_HEAD+1] = 0;
+               reg_state[CTX_RING_TAIL+1] = 0;
+
+               kunmap_atomic(reg_state);
+
+               ringbuf->head = 0;
+               ringbuf->tail = 0;
+       }
+}
index 6f2d7da594f63ab93936550445100727ffd093a8..adb731e49c577370ba0545593c765b66c8524e3c 100644 (file)
@@ -30,6 +30,8 @@
 #define RING_ELSP(ring)                        ((ring)->mmio_base+0x230)
 #define RING_EXECLIST_STATUS(ring)     ((ring)->mmio_base+0x234)
 #define RING_CONTEXT_CONTROL(ring)     ((ring)->mmio_base+0x244)
+#define          CTX_CTRL_INHIBIT_SYN_CTX_SWITCH       (1 << 3)
+#define          CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT   (1 << 0)
 #define RING_CONTEXT_STATUS_BUF(ring)  ((ring)->mmio_base+0x370)
 #define RING_CONTEXT_STATUS_PTR(ring)  ((ring)->mmio_base+0x3a0)
 
@@ -40,10 +42,6 @@ int intel_logical_rings_init(struct drm_device *dev);
 
 int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
                                  struct intel_context *ctx);
-void intel_logical_ring_advance_and_submit(
-                               struct intel_ringbuffer *ringbuf,
-                               struct intel_context *ctx,
-                               struct drm_i915_gem_request *request);
 /**
  * intel_logical_ring_advance() - advance the ringbuffer tail
  * @ringbuf: Ringbuffer to advance.
@@ -70,13 +68,13 @@ int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
                             int num_dwords);
 
 /* Logical Ring Contexts */
-int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
-                                      struct intel_context *ctx);
 void intel_lr_context_free(struct intel_context *ctx);
 int intel_lr_context_deferred_create(struct intel_context *ctx,
                                     struct intel_engine_cs *ring);
 void intel_lr_context_unpin(struct intel_engine_cs *ring,
                struct intel_context *ctx);
+void intel_lr_context_reset(struct drm_device *dev,
+                       struct intel_context *ctx);
 
 /* Execlists */
 int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);
@@ -86,7 +84,7 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
                               struct drm_i915_gem_execbuffer2 *args,
                               struct list_head *vmas,
                               struct drm_i915_gem_object *batch_obj,
-                              u64 exec_start, u32 flags);
+                              u64 exec_start, u32 dispatch_flags);
 u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
 
 void intel_lrc_irq_handler(struct intel_engine_cs *ring);
index 071b96d6e14642778f25a89e81b4ca908c0b64ea..06d2da336f7c863d7ccff9438f2cc54487b4caa8 100644 (file)
@@ -286,7 +286,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
        struct intel_connector *intel_connector =
                &lvds_encoder->attached_connector->base;
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
        unsigned int lvds_bpp;
 
        /* Should never happen!! */
@@ -509,7 +509,7 @@ static int intel_lvds_set_property(struct drm_connector *connector,
                intel_connector->panel.fitting_mode = value;
 
                crtc = intel_attached_encoder(connector)->base.crtc;
-               if (crtc && crtc->enabled) {
+               if (crtc && crtc->state->enable) {
                        /*
                         * If the CRTC is enabled, the display will be changed
                         * according to the new panel fitting mode.
@@ -535,6 +535,7 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_lvds_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
index d8de1d5140a7ed32a06746fe7394ab359ca05f28..71e87abdcae7c1aea0077949f7f7a91cf309732b 100644 (file)
@@ -744,10 +744,8 @@ void intel_opregion_init(struct drm_device *dev)
                return;
 
        if (opregion->acpi) {
-               if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-                       intel_didl_outputs(dev);
-                       intel_setup_cadls(dev);
-               }
+               intel_didl_outputs(dev);
+               intel_setup_cadls(dev);
 
                /* Notify BIOS we are ready to handle ACPI video ext notifs.
                 * Right now, all the events are handled by the ACPI video module.
index f93dfc174495b748ebe4673688ad77eeed98f780..dd92122ed95c87778319d6bef78930c4e381a62b 100644 (file)
@@ -720,7 +720,8 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
        if (ret != 0)
                return ret;
 
-       ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL);
+       ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL,
+                                                  &i915_ggtt_view_normal);
        if (ret != 0)
                return ret;
 
@@ -1065,7 +1066,6 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
        struct put_image_params *params;
        int ret;
 
-       /* No need to check for DRIVER_MODESET - we don't set it up then. */
        overlay = dev_priv->overlay;
        if (!overlay) {
                DRM_DEBUG("userspace bug: no overlay\n");
@@ -1261,7 +1261,6 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
        struct overlay_registers __iomem *regs;
        int ret;
 
-       /* No need to check for DRIVER_MODESET - we don't set it up then. */
        overlay = dev_priv->overlay;
        if (!overlay) {
                DRM_DEBUG("userspace bug: no overlay\n");
index 24d77ddcc5f47bc648309068cb81f69464aeb305..fa4ccb346389e2369effb3b3c48f6f211afa4832 100644 (file)
@@ -56,24 +56,42 @@ static void gen9_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       /*
-        * WaDisableSDEUnitClockGating:skl
-        * This seems to be a pre-production w/a.
-        */
-       I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
-                  GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
+       /* WaEnableLbsSlaRetryTimerDecrement:skl */
+       I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) |
+                  GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE);
+}
 
-       /*
-        * WaDisableDgMirrorFixInHalfSliceChicken5:skl
-        * This is a pre-production w/a.
-        */
-       I915_WRITE(GEN9_HALF_SLICE_CHICKEN5,
-                  I915_READ(GEN9_HALF_SLICE_CHICKEN5) &
-                  ~GEN9_DG_MIRROR_FIX_ENABLE);
+static void skl_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
-       /* Wa4x4STCOptimizationDisable:skl */
-       I915_WRITE(CACHE_MODE_1,
-                  _MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE));
+       gen9_init_clock_gating(dev);
+
+       if (INTEL_REVID(dev) == SKL_REVID_A0) {
+               /*
+                * WaDisableSDEUnitClockGating:skl
+                * WaSetGAPSunitClckGateDisable:skl
+                */
+               I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
+                          GEN8_GAPSUNIT_CLOCK_GATE_DISABLE |
+                          GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
+       }
+
+       if (INTEL_REVID(dev) <= SKL_REVID_D0) {
+               /* WaDisableHDCInvalidation:skl */
+               I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
+                          BDW_DISABLE_HDC_INVALIDATION);
+
+               /* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */
+               I915_WRITE(FF_SLICE_CS_CHICKEN2,
+                          I915_READ(FF_SLICE_CS_CHICKEN2) |
+                          GEN9_TSG_BARRIER_ACK_DISABLE);
+       }
+
+       if (INTEL_REVID(dev) <= SKL_REVID_E0)
+               /* WaDisableLSQCROPERFforOCL:skl */
+               I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
+                          GEN8_LQSC_RO_PERF_DIS);
 }
 
 static void i915_pineview_get_mem_freq(struct drm_device *dev)
@@ -245,6 +263,47 @@ static const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop,
        return NULL;
 }
 
+static void chv_set_memory_dvfs(struct drm_i915_private *dev_priv, bool enable)
+{
+       u32 val;
+
+       mutex_lock(&dev_priv->rps.hw_lock);
+
+       val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2);
+       if (enable)
+               val &= ~FORCE_DDR_HIGH_FREQ;
+       else
+               val |= FORCE_DDR_HIGH_FREQ;
+       val &= ~FORCE_DDR_LOW_FREQ;
+       val |= FORCE_DDR_FREQ_REQ_ACK;
+       vlv_punit_write(dev_priv, PUNIT_REG_DDR_SETUP2, val);
+
+       if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2) &
+                     FORCE_DDR_FREQ_REQ_ACK) == 0, 3))
+               DRM_ERROR("timed out waiting for Punit DDR DVFS request\n");
+
+       mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+static void chv_set_memory_pm5(struct drm_i915_private *dev_priv, bool enable)
+{
+       u32 val;
+
+       mutex_lock(&dev_priv->rps.hw_lock);
+
+       val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
+       if (enable)
+               val |= DSP_MAXFIFO_PM5_ENABLE;
+       else
+               val &= ~DSP_MAXFIFO_PM5_ENABLE;
+       vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val);
+
+       mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+#define FW_WM(value, plane) \
+       (((value) << DSPFW_ ## plane ## _SHIFT) & DSPFW_ ## plane ## _MASK)
+
 void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
 {
        struct drm_device *dev = dev_priv->dev;
@@ -252,6 +311,8 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
 
        if (IS_VALLEYVIEW(dev)) {
                I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0);
+               if (IS_CHERRYVIEW(dev))
+                       chv_set_memory_pm5(dev_priv, enable);
        } else if (IS_G4X(dev) || IS_CRESTLINE(dev)) {
                I915_WRITE(FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0);
        } else if (IS_PINEVIEW(dev)) {
@@ -274,6 +335,7 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
                      enable ? "enabled" : "disabled");
 }
 
+
 /*
  * Latency for FIFO fetches is dependent on several factors:
  *   - memory configuration (speed, channels)
@@ -290,6 +352,61 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
  */
 static const int pessimal_latency_ns = 5000;
 
+#define VLV_FIFO_START(dsparb, dsparb2, lo_shift, hi_shift) \
+       ((((dsparb) >> (lo_shift)) & 0xff) | ((((dsparb2) >> (hi_shift)) & 0x1) << 8))
+
+static int vlv_get_fifo_size(struct drm_device *dev,
+                             enum pipe pipe, int plane)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int sprite0_start, sprite1_start, size;
+
+       switch (pipe) {
+               uint32_t dsparb, dsparb2, dsparb3;
+       case PIPE_A:
+               dsparb = I915_READ(DSPARB);
+               dsparb2 = I915_READ(DSPARB2);
+               sprite0_start = VLV_FIFO_START(dsparb, dsparb2, 0, 0);
+               sprite1_start = VLV_FIFO_START(dsparb, dsparb2, 8, 4);
+               break;
+       case PIPE_B:
+               dsparb = I915_READ(DSPARB);
+               dsparb2 = I915_READ(DSPARB2);
+               sprite0_start = VLV_FIFO_START(dsparb, dsparb2, 16, 8);
+               sprite1_start = VLV_FIFO_START(dsparb, dsparb2, 24, 12);
+               break;
+       case PIPE_C:
+               dsparb2 = I915_READ(DSPARB2);
+               dsparb3 = I915_READ(DSPARB3);
+               sprite0_start = VLV_FIFO_START(dsparb3, dsparb2, 0, 16);
+               sprite1_start = VLV_FIFO_START(dsparb3, dsparb2, 8, 20);
+               break;
+       default:
+               return 0;
+       }
+
+       switch (plane) {
+       case 0:
+               size = sprite0_start;
+               break;
+       case 1:
+               size = sprite1_start - sprite0_start;
+               break;
+       case 2:
+               size = 512 - 1 - sprite1_start;
+               break;
+       default:
+               return 0;
+       }
+
+       DRM_DEBUG_KMS("Pipe %c %s %c FIFO size: %d\n",
+                     pipe_name(pipe), plane == 0 ? "primary" : "sprite",
+                     plane == 0 ? plane_name(pipe) : sprite_name(pipe, plane - 1),
+                     size);
+
+       return size;
+}
+
 static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -535,7 +652,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
        crtc = single_enabled_crtc(dev);
        if (crtc) {
                const struct drm_display_mode *adjusted_mode;
-               int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
+               int pixel_size = crtc->primary->state->fb->bits_per_pixel / 8;
                int clock;
 
                adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
@@ -547,7 +664,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
                                        pixel_size, latency->display_sr);
                reg = I915_READ(DSPFW1);
                reg &= ~DSPFW_SR_MASK;
-               reg |= wm << DSPFW_SR_SHIFT;
+               reg |= FW_WM(wm, SR);
                I915_WRITE(DSPFW1, reg);
                DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg);
 
@@ -557,7 +674,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
                                        pixel_size, latency->cursor_sr);
                reg = I915_READ(DSPFW3);
                reg &= ~DSPFW_CURSOR_SR_MASK;
-               reg |= (wm & 0x3f) << DSPFW_CURSOR_SR_SHIFT;
+               reg |= FW_WM(wm, CURSOR_SR);
                I915_WRITE(DSPFW3, reg);
 
                /* Display HPLL off SR */
@@ -566,7 +683,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
                                        pixel_size, latency->display_hpll_disable);
                reg = I915_READ(DSPFW3);
                reg &= ~DSPFW_HPLL_SR_MASK;
-               reg |= wm & DSPFW_HPLL_SR_MASK;
+               reg |= FW_WM(wm, HPLL_SR);
                I915_WRITE(DSPFW3, reg);
 
                /* cursor HPLL off SR */
@@ -575,7 +692,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
                                        pixel_size, latency->cursor_hpll_disable);
                reg = I915_READ(DSPFW3);
                reg &= ~DSPFW_HPLL_CURSOR_MASK;
-               reg |= (wm & 0x3f) << DSPFW_HPLL_CURSOR_SHIFT;
+               reg |= FW_WM(wm, HPLL_CURSOR);
                I915_WRITE(DSPFW3, reg);
                DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg);
 
@@ -611,7 +728,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,
        clock = adjusted_mode->crtc_clock;
        htotal = adjusted_mode->crtc_htotal;
        hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
-       pixel_size = crtc->primary->fb->bits_per_pixel / 8;
+       pixel_size = crtc->primary->state->fb->bits_per_pixel / 8;
 
        /* Use the small buffer method to calculate plane watermark */
        entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
@@ -626,7 +743,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,
        /* Use the large buffer method to calculate cursor watermark */
        line_time_us = max(htotal * 1000 / clock, 1);
        line_count = (cursor_latency_ns / line_time_us + 1000) / 1000;
-       entries = line_count * to_intel_crtc(crtc)->cursor_width * pixel_size;
+       entries = line_count * crtc->cursor->state->crtc_w * pixel_size;
        tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8;
        if (tlb_miss > 0)
                entries += tlb_miss;
@@ -698,7 +815,7 @@ static bool g4x_compute_srwm(struct drm_device *dev,
        clock = adjusted_mode->crtc_clock;
        htotal = adjusted_mode->crtc_htotal;
        hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
-       pixel_size = crtc->primary->fb->bits_per_pixel / 8;
+       pixel_size = crtc->primary->state->fb->bits_per_pixel / 8;
 
        line_time_us = max(htotal * 1000 / clock, 1);
        line_count = (latency_ns / line_time_us + 1000) / 1000;
@@ -712,7 +829,7 @@ static bool g4x_compute_srwm(struct drm_device *dev,
        *display_wm = entries + display->guard_size;
 
        /* calculate the self-refresh watermark for display cursor */
-       entries = line_count * pixel_size * to_intel_crtc(crtc)->cursor_width;
+       entries = line_count * pixel_size * crtc->cursor->state->crtc_w;
        entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
        *cursor_wm = entries + cursor->guard_size;
 
@@ -721,232 +838,234 @@ static bool g4x_compute_srwm(struct drm_device *dev,
                              display, cursor);
 }
 
-static bool vlv_compute_drain_latency(struct drm_crtc *crtc,
-                                     int pixel_size,
-                                     int *prec_mult,
-                                     int *drain_latency)
-{
-       struct drm_device *dev = crtc->dev;
-       int entries;
-       int clock = to_intel_crtc(crtc)->config->base.adjusted_mode.crtc_clock;
+#define FW_WM_VLV(value, plane) \
+       (((value) << DSPFW_ ## plane ## _SHIFT) & DSPFW_ ## plane ## _MASK_VLV)
 
-       if (WARN(clock == 0, "Pixel clock is zero!\n"))
-               return false;
+static void vlv_write_wm_values(struct intel_crtc *crtc,
+                               const struct vlv_wm_values *wm)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
 
-       if (WARN(pixel_size == 0, "Pixel size is zero!\n"))
-               return false;
+       I915_WRITE(VLV_DDL(pipe),
+                  (wm->ddl[pipe].cursor << DDL_CURSOR_SHIFT) |
+                  (wm->ddl[pipe].sprite[1] << DDL_SPRITE_SHIFT(1)) |
+                  (wm->ddl[pipe].sprite[0] << DDL_SPRITE_SHIFT(0)) |
+                  (wm->ddl[pipe].primary << DDL_PLANE_SHIFT));
 
-       entries = DIV_ROUND_UP(clock, 1000) * pixel_size;
-       if (IS_CHERRYVIEW(dev))
-               *prec_mult = (entries > 128) ? DRAIN_LATENCY_PRECISION_32 :
-                                              DRAIN_LATENCY_PRECISION_16;
-       else
-               *prec_mult = (entries > 128) ? DRAIN_LATENCY_PRECISION_64 :
-                                              DRAIN_LATENCY_PRECISION_32;
-       *drain_latency = (64 * (*prec_mult) * 4) / entries;
+       I915_WRITE(DSPFW1,
+                  FW_WM(wm->sr.plane, SR) |
+                  FW_WM(wm->pipe[PIPE_B].cursor, CURSORB) |
+                  FW_WM_VLV(wm->pipe[PIPE_B].primary, PLANEB) |
+                  FW_WM_VLV(wm->pipe[PIPE_A].primary, PLANEA));
+       I915_WRITE(DSPFW2,
+                  FW_WM_VLV(wm->pipe[PIPE_A].sprite[1], SPRITEB) |
+                  FW_WM(wm->pipe[PIPE_A].cursor, CURSORA) |
+                  FW_WM_VLV(wm->pipe[PIPE_A].sprite[0], SPRITEA));
+       I915_WRITE(DSPFW3,
+                  FW_WM(wm->sr.cursor, CURSOR_SR));
+
+       if (IS_CHERRYVIEW(dev_priv)) {
+               I915_WRITE(DSPFW7_CHV,
+                          FW_WM_VLV(wm->pipe[PIPE_B].sprite[1], SPRITED) |
+                          FW_WM_VLV(wm->pipe[PIPE_B].sprite[0], SPRITEC));
+               I915_WRITE(DSPFW8_CHV,
+                          FW_WM_VLV(wm->pipe[PIPE_C].sprite[1], SPRITEF) |
+                          FW_WM_VLV(wm->pipe[PIPE_C].sprite[0], SPRITEE));
+               I915_WRITE(DSPFW9_CHV,
+                          FW_WM_VLV(wm->pipe[PIPE_C].primary, PLANEC) |
+                          FW_WM(wm->pipe[PIPE_C].cursor, CURSORC));
+               I915_WRITE(DSPHOWM,
+                          FW_WM(wm->sr.plane >> 9, SR_HI) |
+                          FW_WM(wm->pipe[PIPE_C].sprite[1] >> 8, SPRITEF_HI) |
+                          FW_WM(wm->pipe[PIPE_C].sprite[0] >> 8, SPRITEE_HI) |
+                          FW_WM(wm->pipe[PIPE_C].primary >> 8, PLANEC_HI) |
+                          FW_WM(wm->pipe[PIPE_B].sprite[1] >> 8, SPRITED_HI) |
+                          FW_WM(wm->pipe[PIPE_B].sprite[0] >> 8, SPRITEC_HI) |
+                          FW_WM(wm->pipe[PIPE_B].primary >> 8, PLANEB_HI) |
+                          FW_WM(wm->pipe[PIPE_A].sprite[1] >> 8, SPRITEB_HI) |
+                          FW_WM(wm->pipe[PIPE_A].sprite[0] >> 8, SPRITEA_HI) |
+                          FW_WM(wm->pipe[PIPE_A].primary >> 8, PLANEA_HI));
+       } else {
+               I915_WRITE(DSPFW7,
+                          FW_WM_VLV(wm->pipe[PIPE_B].sprite[1], SPRITED) |
+                          FW_WM_VLV(wm->pipe[PIPE_B].sprite[0], SPRITEC));
+               I915_WRITE(DSPHOWM,
+                          FW_WM(wm->sr.plane >> 9, SR_HI) |
+                          FW_WM(wm->pipe[PIPE_B].sprite[1] >> 8, SPRITED_HI) |
+                          FW_WM(wm->pipe[PIPE_B].sprite[0] >> 8, SPRITEC_HI) |
+                          FW_WM(wm->pipe[PIPE_B].primary >> 8, PLANEB_HI) |
+                          FW_WM(wm->pipe[PIPE_A].sprite[1] >> 8, SPRITEB_HI) |
+                          FW_WM(wm->pipe[PIPE_A].sprite[0] >> 8, SPRITEA_HI) |
+                          FW_WM(wm->pipe[PIPE_A].primary >> 8, PLANEA_HI));
+       }
 
-       if (*drain_latency > DRAIN_LATENCY_MASK)
-               *drain_latency = DRAIN_LATENCY_MASK;
+       POSTING_READ(DSPFW1);
 
-       return true;
+       dev_priv->wm.vlv = *wm;
 }
 
-/*
- * Update drain latency registers of memory arbiter
- *
- * Valleyview SoC has a new memory arbiter and needs drain latency registers
- * to be programmed. Each plane has a drain latency multiplier and a drain
- * latency value.
- */
+#undef FW_WM_VLV
 
-static void vlv_update_drain_latency(struct drm_crtc *crtc)
+static uint8_t vlv_compute_drain_latency(struct drm_crtc *crtc,
+                                        struct drm_plane *plane)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pixel_size;
-       int drain_latency;
-       enum pipe pipe = intel_crtc->pipe;
-       int plane_prec, prec_mult, plane_dl;
-       const int high_precision = IS_CHERRYVIEW(dev) ?
-               DRAIN_LATENCY_PRECISION_32 : DRAIN_LATENCY_PRECISION_64;
+       int entries, prec_mult, drain_latency, pixel_size;
+       int clock = intel_crtc->config->base.adjusted_mode.crtc_clock;
+       const int high_precision = IS_CHERRYVIEW(dev) ? 16 : 64;
 
-       plane_dl = I915_READ(VLV_DDL(pipe)) & ~(DDL_PLANE_PRECISION_HIGH |
-                  DRAIN_LATENCY_MASK | DDL_CURSOR_PRECISION_HIGH |
-                  (DRAIN_LATENCY_MASK << DDL_CURSOR_SHIFT));
+       /*
+        * FIXME the plane might have an fb
+        * but be invisible (eg. due to clipping)
+        */
+       if (!intel_crtc->active || !plane->state->fb)
+               return 0;
 
-       if (!intel_crtc_active(crtc)) {
-               I915_WRITE(VLV_DDL(pipe), plane_dl);
-               return;
-       }
+       if (WARN(clock == 0, "Pixel clock is zero!\n"))
+               return 0;
 
-       /* Primary plane Drain Latency */
-       pixel_size = crtc->primary->fb->bits_per_pixel / 8;     /* BPP */
-       if (vlv_compute_drain_latency(crtc, pixel_size, &prec_mult, &drain_latency)) {
-               plane_prec = (prec_mult == high_precision) ?
-                                          DDL_PLANE_PRECISION_HIGH :
-                                          DDL_PLANE_PRECISION_LOW;
-               plane_dl |= plane_prec | drain_latency;
-       }
+       pixel_size = drm_format_plane_cpp(plane->state->fb->pixel_format, 0);
 
-       /* Cursor Drain Latency
-        * BPP is always 4 for cursor
-        */
-       pixel_size = 4;
+       if (WARN(pixel_size == 0, "Pixel size is zero!\n"))
+               return 0;
 
-       /* Program cursor DL only if it is enabled */
-       if (intel_crtc->cursor_base &&
-           vlv_compute_drain_latency(crtc, pixel_size, &prec_mult, &drain_latency)) {
-               plane_prec = (prec_mult == high_precision) ?
-                                          DDL_CURSOR_PRECISION_HIGH :
-                                          DDL_CURSOR_PRECISION_LOW;
-               plane_dl |= plane_prec | (drain_latency << DDL_CURSOR_SHIFT);
+       entries = DIV_ROUND_UP(clock, 1000) * pixel_size;
+
+       prec_mult = high_precision;
+       drain_latency = 64 * prec_mult * 4 / entries;
+
+       if (drain_latency > DRAIN_LATENCY_MASK) {
+               prec_mult /= 2;
+               drain_latency = 64 * prec_mult * 4 / entries;
        }
 
-       I915_WRITE(VLV_DDL(pipe), plane_dl);
-}
+       if (drain_latency > DRAIN_LATENCY_MASK)
+               drain_latency = DRAIN_LATENCY_MASK;
 
-#define single_plane_enabled(mask) is_power_of_2(mask)
+       return drain_latency | (prec_mult == high_precision ?
+                               DDL_PRECISION_HIGH : DDL_PRECISION_LOW);
+}
 
-static void valleyview_update_wm(struct drm_crtc *crtc)
+static int vlv_compute_wm(struct intel_crtc *crtc,
+                         struct intel_plane *plane,
+                         int fifo_size)
 {
-       struct drm_device *dev = crtc->dev;
-       static const int sr_latency_ns = 12000;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
-       int plane_sr, cursor_sr;
-       int ignore_plane_sr, ignore_cursor_sr;
-       unsigned int enabled = 0;
-       bool cxsr_enabled;
+       int clock, entries, pixel_size;
 
-       vlv_update_drain_latency(crtc);
+       /*
+        * FIXME the plane might have an fb
+        * but be invisible (eg. due to clipping)
+        */
+       if (!crtc->active || !plane->base.state->fb)
+               return 0;
 
-       if (g4x_compute_wm0(dev, PIPE_A,
-                           &valleyview_wm_info, pessimal_latency_ns,
-                           &valleyview_cursor_wm_info, pessimal_latency_ns,
-                           &planea_wm, &cursora_wm))
-               enabled |= 1 << PIPE_A;
+       pixel_size = drm_format_plane_cpp(plane->base.state->fb->pixel_format, 0);
+       clock = crtc->config->base.adjusted_mode.crtc_clock;
 
-       if (g4x_compute_wm0(dev, PIPE_B,
-                           &valleyview_wm_info, pessimal_latency_ns,
-                           &valleyview_cursor_wm_info, pessimal_latency_ns,
-                           &planeb_wm, &cursorb_wm))
-               enabled |= 1 << PIPE_B;
+       entries = DIV_ROUND_UP(clock, 1000) * pixel_size;
 
-       if (single_plane_enabled(enabled) &&
-           g4x_compute_srwm(dev, ffs(enabled) - 1,
-                            sr_latency_ns,
-                            &valleyview_wm_info,
-                            &valleyview_cursor_wm_info,
-                            &plane_sr, &ignore_cursor_sr) &&
-           g4x_compute_srwm(dev, ffs(enabled) - 1,
-                            2*sr_latency_ns,
-                            &valleyview_wm_info,
-                            &valleyview_cursor_wm_info,
-                            &ignore_plane_sr, &cursor_sr)) {
-               cxsr_enabled = true;
-       } else {
-               cxsr_enabled = false;
-               intel_set_memory_cxsr(dev_priv, false);
-               plane_sr = cursor_sr = 0;
+       /*
+        * Set up the watermark such that we don't start issuing memory
+        * requests until we are within PND's max deadline value (256us).
+        * Idea being to be idle as long as possible while still taking
+        * advatange of PND's deadline scheduling. The limit of 8
+        * cachelines (used when the FIFO will anyway drain in less time
+        * than 256us) should match what we would be done if trickle
+        * feed were enabled.
+        */
+       return fifo_size - clamp(DIV_ROUND_UP(256 * entries, 64), 0, fifo_size - 8);
+}
+
+static bool vlv_compute_sr_wm(struct drm_device *dev,
+                             struct vlv_wm_values *wm)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_crtc *crtc;
+       enum pipe pipe = INVALID_PIPE;
+       int num_planes = 0;
+       int fifo_size = 0;
+       struct intel_plane *plane;
+
+       wm->sr.cursor = wm->sr.plane = 0;
+
+       crtc = single_enabled_crtc(dev);
+       /* maxfifo not supported on pipe C */
+       if (crtc && to_intel_crtc(crtc)->pipe != PIPE_C) {
+               pipe = to_intel_crtc(crtc)->pipe;
+               num_planes = !!wm->pipe[pipe].primary +
+                       !!wm->pipe[pipe].sprite[0] +
+                       !!wm->pipe[pipe].sprite[1];
+               fifo_size = INTEL_INFO(dev_priv)->num_pipes * 512 - 1;
        }
 
-       DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, "
-                     "B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
-                     planea_wm, cursora_wm,
-                     planeb_wm, cursorb_wm,
-                     plane_sr, cursor_sr);
+       if (fifo_size == 0 || num_planes > 1)
+               return false;
 
-       I915_WRITE(DSPFW1,
-                  (plane_sr << DSPFW_SR_SHIFT) |
-                  (cursorb_wm << DSPFW_CURSORB_SHIFT) |
-                  (planeb_wm << DSPFW_PLANEB_SHIFT) |
-                  (planea_wm << DSPFW_PLANEA_SHIFT));
-       I915_WRITE(DSPFW2,
-                  (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) |
-                  (cursora_wm << DSPFW_CURSORA_SHIFT));
-       I915_WRITE(DSPFW3,
-                  (I915_READ(DSPFW3) & ~DSPFW_CURSOR_SR_MASK) |
-                  (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
+       wm->sr.cursor = vlv_compute_wm(to_intel_crtc(crtc),
+                                      to_intel_plane(crtc->cursor), 0x3f);
 
-       if (cxsr_enabled)
-               intel_set_memory_cxsr(dev_priv, true);
+       list_for_each_entry(plane, &dev->mode_config.plane_list, base.head) {
+               if (plane->base.type == DRM_PLANE_TYPE_CURSOR)
+                       continue;
+
+               if (plane->pipe != pipe)
+                       continue;
+
+               wm->sr.plane = vlv_compute_wm(to_intel_crtc(crtc),
+                                             plane, fifo_size);
+               if (wm->sr.plane != 0)
+                       break;
+       }
+
+       return true;
 }
 
-static void cherryview_update_wm(struct drm_crtc *crtc)
+static void valleyview_update_wm(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       static const int sr_latency_ns = 12000;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int planea_wm, planeb_wm, planec_wm;
-       int cursora_wm, cursorb_wm, cursorc_wm;
-       int plane_sr, cursor_sr;
-       int ignore_plane_sr, ignore_cursor_sr;
-       unsigned int enabled = 0;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum pipe pipe = intel_crtc->pipe;
        bool cxsr_enabled;
+       struct vlv_wm_values wm = dev_priv->wm.vlv;
 
-       vlv_update_drain_latency(crtc);
+       wm.ddl[pipe].primary = vlv_compute_drain_latency(crtc, crtc->primary);
+       wm.pipe[pipe].primary = vlv_compute_wm(intel_crtc,
+                                              to_intel_plane(crtc->primary),
+                                              vlv_get_fifo_size(dev, pipe, 0));
 
-       if (g4x_compute_wm0(dev, PIPE_A,
-                           &valleyview_wm_info, pessimal_latency_ns,
-                           &valleyview_cursor_wm_info, pessimal_latency_ns,
-                           &planea_wm, &cursora_wm))
-               enabled |= 1 << PIPE_A;
+       wm.ddl[pipe].cursor = vlv_compute_drain_latency(crtc, crtc->cursor);
+       wm.pipe[pipe].cursor = vlv_compute_wm(intel_crtc,
+                                             to_intel_plane(crtc->cursor),
+                                             0x3f);
 
-       if (g4x_compute_wm0(dev, PIPE_B,
-                           &valleyview_wm_info, pessimal_latency_ns,
-                           &valleyview_cursor_wm_info, pessimal_latency_ns,
-                           &planeb_wm, &cursorb_wm))
-               enabled |= 1 << PIPE_B;
+       cxsr_enabled = vlv_compute_sr_wm(dev, &wm);
 
-       if (g4x_compute_wm0(dev, PIPE_C,
-                           &valleyview_wm_info, pessimal_latency_ns,
-                           &valleyview_cursor_wm_info, pessimal_latency_ns,
-                           &planec_wm, &cursorc_wm))
-               enabled |= 1 << PIPE_C;
+       if (memcmp(&wm, &dev_priv->wm.vlv, sizeof(wm)) == 0)
+               return;
 
-       if (single_plane_enabled(enabled) &&
-           g4x_compute_srwm(dev, ffs(enabled) - 1,
-                            sr_latency_ns,
-                            &valleyview_wm_info,
-                            &valleyview_cursor_wm_info,
-                            &plane_sr, &ignore_cursor_sr) &&
-           g4x_compute_srwm(dev, ffs(enabled) - 1,
-                            2*sr_latency_ns,
-                            &valleyview_wm_info,
-                            &valleyview_cursor_wm_info,
-                            &ignore_plane_sr, &cursor_sr)) {
-               cxsr_enabled = true;
-       } else {
-               cxsr_enabled = false;
-               intel_set_memory_cxsr(dev_priv, false);
-               plane_sr = cursor_sr = 0;
-       }
+       DRM_DEBUG_KMS("Setting FIFO watermarks - %c: plane=%d, cursor=%d, "
+                     "SR: plane=%d, cursor=%d\n", pipe_name(pipe),
+                     wm.pipe[pipe].primary, wm.pipe[pipe].cursor,
+                     wm.sr.plane, wm.sr.cursor);
 
-       DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, "
-                     "B: plane=%d, cursor=%d, C: plane=%d, cursor=%d, "
-                     "SR: plane=%d, cursor=%d\n",
-                     planea_wm, cursora_wm,
-                     planeb_wm, cursorb_wm,
-                     planec_wm, cursorc_wm,
-                     plane_sr, cursor_sr);
+       /*
+        * FIXME DDR DVFS introduces massive memory latencies which
+        * are not known to system agent so any deadline specified
+        * by the display may not be respected. To support DDR DVFS
+        * the watermark code needs to be rewritten to essentially
+        * bypass deadline mechanism and rely solely on the
+        * watermarks. For now disable DDR DVFS.
+        */
+       if (IS_CHERRYVIEW(dev_priv))
+               chv_set_memory_dvfs(dev_priv, false);
 
-       I915_WRITE(DSPFW1,
-                  (plane_sr << DSPFW_SR_SHIFT) |
-                  (cursorb_wm << DSPFW_CURSORB_SHIFT) |
-                  (planeb_wm << DSPFW_PLANEB_SHIFT) |
-                  (planea_wm << DSPFW_PLANEA_SHIFT));
-       I915_WRITE(DSPFW2,
-                  (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) |
-                  (cursora_wm << DSPFW_CURSORA_SHIFT));
-       I915_WRITE(DSPFW3,
-                  (I915_READ(DSPFW3) & ~DSPFW_CURSOR_SR_MASK) |
-                  (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
-       I915_WRITE(DSPFW9_CHV,
-                  (I915_READ(DSPFW9_CHV) & ~(DSPFW_PLANEC_MASK |
-                                             DSPFW_CURSORC_MASK)) |
-                  (planec_wm << DSPFW_PLANEC_SHIFT) |
-                  (cursorc_wm << DSPFW_CURSORC_SHIFT));
+       if (!cxsr_enabled)
+               intel_set_memory_cxsr(dev_priv, false);
+
+       vlv_write_wm_values(intel_crtc, &wm);
 
        if (cxsr_enabled)
                intel_set_memory_cxsr(dev_priv, true);
@@ -961,30 +1080,47 @@ static void valleyview_update_sprite_wm(struct drm_plane *plane,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int pipe = to_intel_plane(plane)->pipe;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum pipe pipe = intel_crtc->pipe;
        int sprite = to_intel_plane(plane)->plane;
-       int drain_latency;
-       int plane_prec;
-       int sprite_dl;
-       int prec_mult;
-       const int high_precision = IS_CHERRYVIEW(dev) ?
-               DRAIN_LATENCY_PRECISION_32 : DRAIN_LATENCY_PRECISION_64;
+       bool cxsr_enabled;
+       struct vlv_wm_values wm = dev_priv->wm.vlv;
 
-       sprite_dl = I915_READ(VLV_DDL(pipe)) & ~(DDL_SPRITE_PRECISION_HIGH(sprite) |
-                   (DRAIN_LATENCY_MASK << DDL_SPRITE_SHIFT(sprite)));
+       if (enabled) {
+               wm.ddl[pipe].sprite[sprite] =
+                       vlv_compute_drain_latency(crtc, plane);
 
-       if (enabled && vlv_compute_drain_latency(crtc, pixel_size, &prec_mult,
-                                                &drain_latency)) {
-               plane_prec = (prec_mult == high_precision) ?
-                                          DDL_SPRITE_PRECISION_HIGH(sprite) :
-                                          DDL_SPRITE_PRECISION_LOW(sprite);
-               sprite_dl |= plane_prec |
-                            (drain_latency << DDL_SPRITE_SHIFT(sprite));
+               wm.pipe[pipe].sprite[sprite] =
+                       vlv_compute_wm(intel_crtc,
+                                      to_intel_plane(plane),
+                                      vlv_get_fifo_size(dev, pipe, sprite+1));
+       } else {
+               wm.ddl[pipe].sprite[sprite] = 0;
+               wm.pipe[pipe].sprite[sprite] = 0;
        }
 
-       I915_WRITE(VLV_DDL(pipe), sprite_dl);
+       cxsr_enabled = vlv_compute_sr_wm(dev, &wm);
+
+       if (memcmp(&wm, &dev_priv->wm.vlv, sizeof(wm)) == 0)
+               return;
+
+       DRM_DEBUG_KMS("Setting FIFO watermarks - %c: sprite %c=%d, "
+                     "SR: plane=%d, cursor=%d\n", pipe_name(pipe),
+                     sprite_name(pipe, sprite),
+                     wm.pipe[pipe].sprite[sprite],
+                     wm.sr.plane, wm.sr.cursor);
+
+       if (!cxsr_enabled)
+               intel_set_memory_cxsr(dev_priv, false);
+
+       vlv_write_wm_values(intel_crtc, &wm);
+
+       if (cxsr_enabled)
+               intel_set_memory_cxsr(dev_priv, true);
 }
 
+#define single_plane_enabled(mask) is_power_of_2(mask)
+
 static void g4x_update_wm(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -1027,17 +1163,17 @@ static void g4x_update_wm(struct drm_crtc *crtc)
                      plane_sr, cursor_sr);
 
        I915_WRITE(DSPFW1,
-                  (plane_sr << DSPFW_SR_SHIFT) |
-                  (cursorb_wm << DSPFW_CURSORB_SHIFT) |
-                  (planeb_wm << DSPFW_PLANEB_SHIFT) |
-                  (planea_wm << DSPFW_PLANEA_SHIFT));
+                  FW_WM(plane_sr, SR) |
+                  FW_WM(cursorb_wm, CURSORB) |
+                  FW_WM(planeb_wm, PLANEB) |
+                  FW_WM(planea_wm, PLANEA));
        I915_WRITE(DSPFW2,
                   (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) |
-                  (cursora_wm << DSPFW_CURSORA_SHIFT));
+                  FW_WM(cursora_wm, CURSORA));
        /* HPLL off in SR has some issues on G4x... disable it */
        I915_WRITE(DSPFW3,
                   (I915_READ(DSPFW3) & ~(DSPFW_HPLL_SR_EN | DSPFW_CURSOR_SR_MASK)) |
-                  (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
+                  FW_WM(cursor_sr, CURSOR_SR));
 
        if (cxsr_enabled)
                intel_set_memory_cxsr(dev_priv, true);
@@ -1062,7 +1198,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
                int clock = adjusted_mode->crtc_clock;
                int htotal = adjusted_mode->crtc_htotal;
                int hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
-               int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
+               int pixel_size = crtc->primary->state->fb->bits_per_pixel / 8;
                unsigned long line_time_us;
                int entries;
 
@@ -1080,7 +1216,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
                              entries, srwm);
 
                entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                       pixel_size * to_intel_crtc(crtc)->cursor_width;
+                       pixel_size * crtc->cursor->state->crtc_w;
                entries = DIV_ROUND_UP(entries,
                                          i965_cursor_wm_info.cacheline_size);
                cursor_sr = i965_cursor_wm_info.fifo_size -
@@ -1103,19 +1239,21 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
                      srwm);
 
        /* 965 has limitations... */
-       I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) |
-                  (8 << DSPFW_CURSORB_SHIFT) |
-                  (8 << DSPFW_PLANEB_SHIFT) |
-                  (8 << DSPFW_PLANEA_SHIFT));
-       I915_WRITE(DSPFW2, (8 << DSPFW_CURSORA_SHIFT) |
-                  (8 << DSPFW_PLANEC_SHIFT_OLD));
+       I915_WRITE(DSPFW1, FW_WM(srwm, SR) |
+                  FW_WM(8, CURSORB) |
+                  FW_WM(8, PLANEB) |
+                  FW_WM(8, PLANEA));
+       I915_WRITE(DSPFW2, FW_WM(8, CURSORA) |
+                  FW_WM(8, PLANEC_OLD));
        /* update cursor SR watermark */
-       I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
+       I915_WRITE(DSPFW3, FW_WM(cursor_sr, CURSOR_SR));
 
        if (cxsr_enabled)
                intel_set_memory_cxsr(dev_priv, true);
 }
 
+#undef FW_WM
+
 static void i9xx_update_wm(struct drm_crtc *unused_crtc)
 {
        struct drm_device *dev = unused_crtc->dev;
@@ -1139,7 +1277,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
        crtc = intel_get_crtc_for_plane(dev, 0);
        if (intel_crtc_active(crtc)) {
                const struct drm_display_mode *adjusted_mode;
-               int cpp = crtc->primary->fb->bits_per_pixel / 8;
+               int cpp = crtc->primary->state->fb->bits_per_pixel / 8;
                if (IS_GEN2(dev))
                        cpp = 4;
 
@@ -1161,7 +1299,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
        crtc = intel_get_crtc_for_plane(dev, 1);
        if (intel_crtc_active(crtc)) {
                const struct drm_display_mode *adjusted_mode;
-               int cpp = crtc->primary->fb->bits_per_pixel / 8;
+               int cpp = crtc->primary->state->fb->bits_per_pixel / 8;
                if (IS_GEN2(dev))
                        cpp = 4;
 
@@ -1184,7 +1322,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
        if (IS_I915GM(dev) && enabled) {
                struct drm_i915_gem_object *obj;
 
-               obj = intel_fb_obj(enabled->primary->fb);
+               obj = intel_fb_obj(enabled->primary->state->fb);
 
                /* self-refresh seems busted with untiled */
                if (obj->tiling_mode == I915_TILING_NONE)
@@ -1208,7 +1346,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
                int clock = adjusted_mode->crtc_clock;
                int htotal = adjusted_mode->crtc_htotal;
                int hdisplay = to_intel_crtc(enabled)->config->pipe_src_w;
-               int pixel_size = enabled->primary->fb->bits_per_pixel / 8;
+               int pixel_size = enabled->primary->state->fb->bits_per_pixel / 8;
                unsigned long line_time_us;
                int entries;
 
@@ -1645,7 +1783,7 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc)
        struct drm_display_mode *mode = &intel_crtc->config->base.adjusted_mode;
        u32 linetime, ips_linetime;
 
-       if (!intel_crtc_active(crtc))
+       if (!intel_crtc->active)
                return 0;
 
        /* The WM are computed with base on how long it takes to fill a single
@@ -1711,6 +1849,8 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8])
                                GEN9_MEM_LATENCY_LEVEL_MASK;
 
                /*
+                * WaWmMemoryReadLatency:skl
+                *
                 * punit doesn't take into account the read latency so we need
                 * to add 2us to the various latency levels we retrieve from
                 * the punit.
@@ -1898,19 +2038,31 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
        enum pipe pipe = intel_crtc->pipe;
        struct drm_plane *plane;
 
-       if (!intel_crtc_active(crtc))
+       if (!intel_crtc->active)
                return;
 
        p->active = true;
        p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
        p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
-       p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
-       p->cur.bytes_per_pixel = 4;
+
+       if (crtc->primary->state->fb) {
+               p->pri.enabled = true;
+               p->pri.bytes_per_pixel =
+                       crtc->primary->state->fb->bits_per_pixel / 8;
+       } else {
+               p->pri.enabled = false;
+               p->pri.bytes_per_pixel = 0;
+       }
+
+       if (crtc->cursor->state->fb) {
+               p->cur.enabled = true;
+               p->cur.bytes_per_pixel = 4;
+       } else {
+               p->cur.enabled = false;
+               p->cur.bytes_per_pixel = 0;
+       }
        p->pri.horiz_pixels = intel_crtc->config->pipe_src_w;
-       p->cur.horiz_pixels = intel_crtc->cursor_width;
-       /* TODO: for now, assume primary and cursor planes are always enabled. */
-       p->pri.enabled = true;
-       p->cur.enabled = true;
+       p->cur.horiz_pixels = intel_crtc->base.cursor->state->crtc_w;
 
        drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
                struct intel_plane *intel_plane = to_intel_plane(plane);
@@ -2410,7 +2562,7 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
 
        nth_active_pipe = 0;
        for_each_crtc(dev, crtc) {
-               if (!intel_crtc_active(crtc))
+               if (!to_intel_crtc(crtc)->active)
                        continue;
 
                if (crtc == for_crtc)
@@ -2443,13 +2595,12 @@ static void skl_ddb_entry_init_from_hw(struct skl_ddb_entry *entry, u32 reg)
 void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
                          struct skl_ddb_allocation *ddb /* out */)
 {
-       struct drm_device *dev = dev_priv->dev;
        enum pipe pipe;
        int plane;
        u32 val;
 
        for_each_pipe(dev_priv, pipe) {
-               for_each_plane(pipe, plane) {
+               for_each_plane(dev_priv, pipe, plane) {
                        val = I915_READ(PLANE_BUF_CFG(pipe, plane));
                        skl_ddb_entry_init_from_hw(&ddb->plane[pipe][plane],
                                                   val);
@@ -2498,10 +2649,12 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
                      struct skl_ddb_allocation *ddb /* out */)
 {
        struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum pipe pipe = intel_crtc->pipe;
        struct skl_ddb_entry *alloc = &ddb->pipe[pipe];
        uint16_t alloc_size, start, cursor_blocks;
+       uint16_t minimum[I915_MAX_PLANES];
        unsigned int total_data_rate;
        int plane;
 
@@ -2520,9 +2673,21 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
        alloc_size -= cursor_blocks;
        alloc->end -= cursor_blocks;
 
+       /* 1. Allocate the mininum required blocks for each active plane */
+       for_each_plane(dev_priv, pipe, plane) {
+               const struct intel_plane_wm_parameters *p;
+
+               p = &params->plane[plane];
+               if (!p->enabled)
+                       continue;
+
+               minimum[plane] = 8;
+               alloc_size -= minimum[plane];
+       }
+
        /*
-        * Each active plane get a portion of the remaining space, in
-        * proportion to the amount of data they need to fetch from memory.
+        * 2. Distribute the remaining space in proportion to the amount of
+        * data each plane needs to fetch from memory.
         *
         * FIXME: we may not allocate every single block here.
         */
@@ -2544,8 +2709,9 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
                 * promote the expression to 64 bits to avoid overflowing, the
                 * result is < available as data_rate / total_data_rate < 1
                 */
-               plane_blocks = div_u64((uint64_t)alloc_size * data_rate,
-                                      total_data_rate);
+               plane_blocks = minimum[plane];
+               plane_blocks += div_u64((uint64_t)alloc_size * data_rate,
+                                       total_data_rate);
 
                ddb->plane[pipe][plane].start = start;
                ddb->plane[pipe][plane].end = start + plane_blocks;
@@ -2575,7 +2741,7 @@ static uint32_t skl_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel,
        if (latency == 0)
                return UINT_MAX;
 
-       wm_intermediate_val = latency * pixel_rate * bytes_per_pixel;
+       wm_intermediate_val = latency * pixel_rate * bytes_per_pixel / 512;
        ret = DIV_ROUND_UP(wm_intermediate_val, 1000);
 
        return ret;
@@ -2583,17 +2749,29 @@ static uint32_t skl_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel,
 
 static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
                               uint32_t horiz_pixels, uint8_t bytes_per_pixel,
-                              uint32_t latency)
+                              uint64_t tiling, uint32_t latency)
 {
-       uint32_t ret, plane_bytes_per_line, wm_intermediate_val;
+       uint32_t ret;
+       uint32_t plane_bytes_per_line, plane_blocks_per_line;
+       uint32_t wm_intermediate_val;
 
        if (latency == 0)
                return UINT_MAX;
 
        plane_bytes_per_line = horiz_pixels * bytes_per_pixel;
+
+       if (tiling == I915_FORMAT_MOD_Y_TILED ||
+           tiling == I915_FORMAT_MOD_Yf_TILED) {
+               plane_bytes_per_line *= 4;
+               plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
+               plane_blocks_per_line /= 4;
+       } else {
+               plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
+       }
+
        wm_intermediate_val = latency * pixel_rate;
        ret = DIV_ROUND_UP(wm_intermediate_val, pipe_htotal * 1000) *
-                               plane_bytes_per_line;
+                               plane_blocks_per_line;
 
        return ret;
 }
@@ -2624,7 +2802,7 @@ static void skl_compute_wm_global_parameters(struct drm_device *dev,
        struct drm_plane *plane;
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
-               config->num_pipes_active += intel_crtc_active(crtc);
+               config->num_pipes_active += to_intel_crtc(crtc)->active;
 
        /* FIXME: I don't think we need those two global parameters on SKL */
        list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
@@ -2642,26 +2820,40 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum pipe pipe = intel_crtc->pipe;
        struct drm_plane *plane;
+       struct drm_framebuffer *fb;
        int i = 1; /* Index for sprite planes start */
 
-       p->active = intel_crtc_active(crtc);
+       p->active = intel_crtc->active;
        if (p->active) {
                p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
                p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config);
 
-               /*
-                * For now, assume primary and cursor planes are always enabled.
-                */
-               p->plane[0].enabled = true;
-               p->plane[0].bytes_per_pixel =
-                       crtc->primary->fb->bits_per_pixel / 8;
+               fb = crtc->primary->state->fb;
+               if (fb) {
+                       p->plane[0].enabled = true;
+                       p->plane[0].bytes_per_pixel = fb->bits_per_pixel / 8;
+                       p->plane[0].tiling = fb->modifier[0];
+               } else {
+                       p->plane[0].enabled = false;
+                       p->plane[0].bytes_per_pixel = 0;
+                       p->plane[0].tiling = DRM_FORMAT_MOD_NONE;
+               }
                p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w;
                p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h;
-
-               p->cursor.enabled = true;
-               p->cursor.bytes_per_pixel = 4;
-               p->cursor.horiz_pixels = intel_crtc->cursor_width ?
-                                        intel_crtc->cursor_width : 64;
+               p->plane[0].rotation = crtc->primary->state->rotation;
+
+               fb = crtc->cursor->state->fb;
+               if (fb) {
+                       p->cursor.enabled = true;
+                       p->cursor.bytes_per_pixel = fb->bits_per_pixel / 8;
+                       p->cursor.horiz_pixels = crtc->cursor->state->crtc_w;
+                       p->cursor.vert_pixels = crtc->cursor->state->crtc_h;
+               } else {
+                       p->cursor.enabled = false;
+                       p->cursor.bytes_per_pixel = 0;
+                       p->cursor.horiz_pixels = 64;
+                       p->cursor.vert_pixels = 64;
+               }
        }
 
        list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
@@ -2673,41 +2865,74 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
        }
 }
 
-static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p,
+static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
+                                struct skl_pipe_wm_parameters *p,
                                 struct intel_plane_wm_parameters *p_params,
                                 uint16_t ddb_allocation,
-                                uint32_t mem_value,
+                                int level,
                                 uint16_t *out_blocks, /* out */
                                 uint8_t *out_lines /* out */)
 {
-       uint32_t method1, method2, plane_bytes_per_line, res_blocks, res_lines;
-       uint32_t result_bytes;
+       uint32_t latency = dev_priv->wm.skl_latency[level];
+       uint32_t method1, method2;
+       uint32_t plane_bytes_per_line, plane_blocks_per_line;
+       uint32_t res_blocks, res_lines;
+       uint32_t selected_result;
 
-       if (mem_value == 0 || !p->active || !p_params->enabled)
+       if (latency == 0 || !p->active || !p_params->enabled)
                return false;
 
        method1 = skl_wm_method1(p->pixel_rate,
                                 p_params->bytes_per_pixel,
-                                mem_value);
+                                latency);
        method2 = skl_wm_method2(p->pixel_rate,
                                 p->pipe_htotal,
                                 p_params->horiz_pixels,
                                 p_params->bytes_per_pixel,
-                                mem_value);
+                                p_params->tiling,
+                                latency);
 
        plane_bytes_per_line = p_params->horiz_pixels *
                                        p_params->bytes_per_pixel;
+       plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
+
+       if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
+           p_params->tiling == I915_FORMAT_MOD_Yf_TILED) {
+               uint32_t min_scanlines = 4;
+               uint32_t y_tile_minimum;
+               if (intel_rotation_90_or_270(p_params->rotation)) {
+                       switch (p_params->bytes_per_pixel) {
+                       case 1:
+                               min_scanlines = 16;
+                               break;
+                       case 2:
+                               min_scanlines = 8;
+                               break;
+                       case 8:
+                               WARN(1, "Unsupported pixel depth for rotation");
+                       }
+               }
+               y_tile_minimum = plane_blocks_per_line * min_scanlines;
+               selected_result = max(method2, y_tile_minimum);
+       } else {
+               if ((ddb_allocation / plane_blocks_per_line) >= 1)
+                       selected_result = min(method1, method2);
+               else
+                       selected_result = method1;
+       }
 
-       /* For now xtile and linear */
-       if (((ddb_allocation * 512) / plane_bytes_per_line) >= 1)
-               result_bytes = min(method1, method2);
-       else
-               result_bytes = method1;
+       res_blocks = selected_result + 1;
+       res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line);
 
-       res_blocks = DIV_ROUND_UP(result_bytes, 512) + 1;
-       res_lines = DIV_ROUND_UP(result_bytes, plane_bytes_per_line);
+       if (level >= 1 && level <= 7) {
+               if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
+                   p_params->tiling == I915_FORMAT_MOD_Yf_TILED)
+                       res_lines += 4;
+               else
+                       res_blocks++;
+       }
 
-       if (res_blocks > ddb_allocation || res_lines > 31)
+       if (res_blocks >= ddb_allocation || res_lines > 31)
                return false;
 
        *out_blocks = res_blocks;
@@ -2724,30 +2949,31 @@ static void skl_compute_wm_level(const struct drm_i915_private *dev_priv,
                                 int num_planes,
                                 struct skl_wm_level *result)
 {
-       uint16_t latency = dev_priv->wm.skl_latency[level];
        uint16_t ddb_blocks;
        int i;
 
        for (i = 0; i < num_planes; i++) {
                ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][i]);
 
-               result->plane_en[i] = skl_compute_plane_wm(p, &p->plane[i],
+               result->plane_en[i] = skl_compute_plane_wm(dev_priv,
+                                               p, &p->plane[i],
                                                ddb_blocks,
-                                               latency,
+                                               level,
                                                &result->plane_res_b[i],
                                                &result->plane_res_l[i]);
        }
 
        ddb_blocks = skl_ddb_entry_size(&ddb->cursor[pipe]);
-       result->cursor_en = skl_compute_plane_wm(p, &p->cursor, ddb_blocks,
-                                                latency, &result->cursor_res_b,
+       result->cursor_en = skl_compute_plane_wm(dev_priv, p, &p->cursor,
+                                                ddb_blocks, level,
+                                                &result->cursor_res_b,
                                                 &result->cursor_res_l);
 }
 
 static uint32_t
 skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p)
 {
-       if (!intel_crtc_active(crtc))
+       if (!to_intel_crtc(crtc)->active)
                return 0;
 
        return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate);
@@ -2921,12 +3147,11 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
 static void
 skl_wm_flush_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, int pass)
 {
-       struct drm_device *dev = dev_priv->dev;
        int plane;
 
        DRM_DEBUG_KMS("flush pipe %c (pass %d)\n", pipe_name(pipe), pass);
 
-       for_each_plane(pipe, plane) {
+       for_each_plane(dev_priv, pipe, plane) {
                I915_WRITE(PLANE_SURF(pipe, plane),
                           I915_READ(PLANE_SURF(pipe, plane)));
        }
@@ -3133,12 +3358,21 @@ skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc,
                     int pixel_size, bool enabled, bool scaled)
 {
        struct intel_plane *intel_plane = to_intel_plane(plane);
+       struct drm_framebuffer *fb = plane->state->fb;
 
        intel_plane->wm.enabled = enabled;
        intel_plane->wm.scaled = scaled;
        intel_plane->wm.horiz_pixels = sprite_width;
        intel_plane->wm.vert_pixels = sprite_height;
        intel_plane->wm.bytes_per_pixel = pixel_size;
+       intel_plane->wm.tiling = DRM_FORMAT_MOD_NONE;
+       /*
+        * Framebuffer can be NULL on plane disable, but it does not
+        * matter for watermarks if we assume no tiling in that case.
+        */
+       if (fb)
+               intel_plane->wm.tiling = fb->modifier[0];
+       intel_plane->wm.rotation = plane->state->rotation;
 
        skl_update_wm(crtc);
 }
@@ -3287,7 +3521,7 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc)
                hw->plane_trans[pipe][i] = I915_READ(PLANE_WM_TRANS(pipe, i));
        hw->cursor_trans[pipe] = I915_READ(CUR_WM_TRANS(pipe));
 
-       if (!intel_crtc_active(crtc))
+       if (!intel_crtc->active)
                return;
 
        hw->dirty[pipe] = true;
@@ -3342,7 +3576,7 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe));
 
-       active->pipe_enabled = intel_crtc_active(crtc);
+       active->pipe_enabled = intel_crtc->active;
 
        if (active->pipe_enabled) {
                u32 tmp = hw->wm_pipe[pipe];
@@ -3456,41 +3690,6 @@ void intel_update_sprite_watermarks(struct drm_plane *plane,
                                                   pixel_size, enabled, scaled);
 }
 
-static struct drm_i915_gem_object *
-intel_alloc_context_page(struct drm_device *dev)
-{
-       struct drm_i915_gem_object *ctx;
-       int ret;
-
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
-       ctx = i915_gem_alloc_object(dev, 4096);
-       if (!ctx) {
-               DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
-               return NULL;
-       }
-
-       ret = i915_gem_obj_ggtt_pin(ctx, 4096, 0);
-       if (ret) {
-               DRM_ERROR("failed to pin power context: %d\n", ret);
-               goto err_unref;
-       }
-
-       ret = i915_gem_object_set_to_gtt_domain(ctx, 1);
-       if (ret) {
-               DRM_ERROR("failed to set-domain on power context: %d\n", ret);
-               goto err_unpin;
-       }
-
-       return ctx;
-
-err_unpin:
-       i915_gem_object_ggtt_unpin(ctx);
-err_unref:
-       drm_gem_object_unreference(&ctx->base);
-       return NULL;
-}
-
 /**
  * Lock protecting IPS related data structures
  */
@@ -3623,7 +3822,7 @@ static void ironlake_disable_drps(struct drm_device *dev)
  * ourselves, instead of doing a rmw cycle (which might result in us clearing
  * all limits and the gpu stuck at whatever frequency it is at atm).
  */
-static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val)
+static u32 intel_rps_limits(struct drm_i915_private *dev_priv, u8 val)
 {
        u32 limits;
 
@@ -3633,9 +3832,15 @@ static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val)
         * the hw runs at the minimal clock before selecting the desired
         * frequency, if the down threshold expires in that window we will not
         * receive a down interrupt. */
-       limits = dev_priv->rps.max_freq_softlimit << 24;
-       if (val <= dev_priv->rps.min_freq_softlimit)
-               limits |= dev_priv->rps.min_freq_softlimit << 16;
+       if (IS_GEN9(dev_priv->dev)) {
+               limits = (dev_priv->rps.max_freq_softlimit) << 23;
+               if (val <= dev_priv->rps.min_freq_softlimit)
+                       limits |= (dev_priv->rps.min_freq_softlimit) << 14;
+       } else {
+               limits = dev_priv->rps.max_freq_softlimit << 24;
+               if (val <= dev_priv->rps.min_freq_softlimit)
+                       limits |= dev_priv->rps.min_freq_softlimit << 16;
+       }
 
        return limits;
 }
@@ -3643,6 +3848,8 @@ static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val)
 static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
 {
        int new_power;
+       u32 threshold_up = 0, threshold_down = 0; /* in % */
+       u32 ei_up = 0, ei_down = 0;
 
        new_power = dev_priv->rps.power;
        switch (dev_priv->rps.power) {
@@ -3664,9 +3871,9 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
                break;
        }
        /* Max/min bins are special */
-       if (val == dev_priv->rps.min_freq_softlimit)
+       if (val <= dev_priv->rps.min_freq_softlimit)
                new_power = LOW_POWER;
-       if (val == dev_priv->rps.max_freq_softlimit)
+       if (val >= dev_priv->rps.max_freq_softlimit)
                new_power = HIGH_POWER;
        if (new_power == dev_priv->rps.power)
                return;
@@ -3675,59 +3882,53 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
        switch (new_power) {
        case LOW_POWER:
                /* Upclock if more than 95% busy over 16ms */
-               I915_WRITE(GEN6_RP_UP_EI, 12500);
-               I915_WRITE(GEN6_RP_UP_THRESHOLD, 11800);
+               ei_up = 16000;
+               threshold_up = 95;
 
                /* Downclock if less than 85% busy over 32ms */
-               I915_WRITE(GEN6_RP_DOWN_EI, 25000);
-               I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 21250);
-
-               I915_WRITE(GEN6_RP_CONTROL,
-                          GEN6_RP_MEDIA_TURBO |
-                          GEN6_RP_MEDIA_HW_NORMAL_MODE |
-                          GEN6_RP_MEDIA_IS_GFX |
-                          GEN6_RP_ENABLE |
-                          GEN6_RP_UP_BUSY_AVG |
-                          GEN6_RP_DOWN_IDLE_AVG);
+               ei_down = 32000;
+               threshold_down = 85;
                break;
 
        case BETWEEN:
                /* Upclock if more than 90% busy over 13ms */
-               I915_WRITE(GEN6_RP_UP_EI, 10250);
-               I915_WRITE(GEN6_RP_UP_THRESHOLD, 9225);
+               ei_up = 13000;
+               threshold_up = 90;
 
                /* Downclock if less than 75% busy over 32ms */
-               I915_WRITE(GEN6_RP_DOWN_EI, 25000);
-               I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 18750);
-
-               I915_WRITE(GEN6_RP_CONTROL,
-                          GEN6_RP_MEDIA_TURBO |
-                          GEN6_RP_MEDIA_HW_NORMAL_MODE |
-                          GEN6_RP_MEDIA_IS_GFX |
-                          GEN6_RP_ENABLE |
-                          GEN6_RP_UP_BUSY_AVG |
-                          GEN6_RP_DOWN_IDLE_AVG);
+               ei_down = 32000;
+               threshold_down = 75;
                break;
 
        case HIGH_POWER:
                /* Upclock if more than 85% busy over 10ms */
-               I915_WRITE(GEN6_RP_UP_EI, 8000);
-               I915_WRITE(GEN6_RP_UP_THRESHOLD, 6800);
+               ei_up = 10000;
+               threshold_up = 85;
 
                /* Downclock if less than 60% busy over 32ms */
-               I915_WRITE(GEN6_RP_DOWN_EI, 25000);
-               I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 15000);
-
-               I915_WRITE(GEN6_RP_CONTROL,
-                          GEN6_RP_MEDIA_TURBO |
-                          GEN6_RP_MEDIA_HW_NORMAL_MODE |
-                          GEN6_RP_MEDIA_IS_GFX |
-                          GEN6_RP_ENABLE |
-                          GEN6_RP_UP_BUSY_AVG |
-                          GEN6_RP_DOWN_IDLE_AVG);
+               ei_down = 32000;
+               threshold_down = 60;
                break;
        }
 
+       I915_WRITE(GEN6_RP_UP_EI,
+               GT_INTERVAL_FROM_US(dev_priv, ei_up));
+       I915_WRITE(GEN6_RP_UP_THRESHOLD,
+               GT_INTERVAL_FROM_US(dev_priv, (ei_up * threshold_up / 100)));
+
+       I915_WRITE(GEN6_RP_DOWN_EI,
+               GT_INTERVAL_FROM_US(dev_priv, ei_down));
+       I915_WRITE(GEN6_RP_DOWN_THRESHOLD,
+               GT_INTERVAL_FROM_US(dev_priv, (ei_down * threshold_down / 100)));
+
+        I915_WRITE(GEN6_RP_CONTROL,
+                   GEN6_RP_MEDIA_TURBO |
+                   GEN6_RP_MEDIA_HW_NORMAL_MODE |
+                   GEN6_RP_MEDIA_IS_GFX |
+                   GEN6_RP_ENABLE |
+                   GEN6_RP_UP_BUSY_AVG |
+                   GEN6_RP_DOWN_IDLE_AVG);
+
        dev_priv->rps.power = new_power;
        dev_priv->rps.last_adj = 0;
 }
@@ -3737,11 +3938,10 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
        u32 mask = 0;
 
        if (val > dev_priv->rps.min_freq_softlimit)
-               mask |= GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
+               mask |= GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
        if (val < dev_priv->rps.max_freq_softlimit)
-               mask |= GEN6_PM_RP_UP_THRESHOLD;
+               mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD;
 
-       mask |= dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED);
        mask &= dev_priv->pm_rps_events;
 
        return gen6_sanitize_rps_pm_mask(dev_priv, ~mask);
@@ -3750,13 +3950,13 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
 /* gen6_set_rps is called to update the frequency request, but should also be
  * called when the range (min_delay and max_delay) is modified so that we can
  * update the GEN6_RP_INTERRUPT_LIMITS register accordingly. */
-void gen6_set_rps(struct drm_device *dev, u8 val)
+static void gen6_set_rps(struct drm_device *dev, u8 val)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-       WARN_ON(val > dev_priv->rps.max_freq_softlimit);
-       WARN_ON(val < dev_priv->rps.min_freq_softlimit);
+       WARN_ON(val > dev_priv->rps.max_freq);
+       WARN_ON(val < dev_priv->rps.min_freq);
 
        /* min/max delay may still have been modified so be sure to
         * write the limits value.
@@ -3764,7 +3964,10 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
        if (val != dev_priv->rps.cur_freq) {
                gen6_set_rps_thresholds(dev_priv, val);
 
-               if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               if (IS_GEN9(dev))
+                       I915_WRITE(GEN6_RPNSWREQ,
+                                  GEN9_FREQUENCY(val));
+               else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                        I915_WRITE(GEN6_RPNSWREQ,
                                   HSW_FREQUENCY(val));
                else
@@ -3777,7 +3980,7 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
        /* Make sure we continue to get interrupts
         * until we hit the minimum or maximum frequencies.
         */
-       I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, gen6_rps_limits(dev_priv, val));
+       I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, intel_rps_limits(dev_priv, val));
        I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
 
        POSTING_READ(GEN6_RPNSWREQ);
@@ -3786,6 +3989,27 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
        trace_intel_gpu_freq_change(val * 50);
 }
 
+static void valleyview_set_rps(struct drm_device *dev, u8 val)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+       WARN_ON(val > dev_priv->rps.max_freq);
+       WARN_ON(val < dev_priv->rps.min_freq);
+
+       if (WARN_ONCE(IS_CHERRYVIEW(dev) && (val & 1),
+                     "Odd GPU freq value\n"))
+               val &= ~1;
+
+       if (val != dev_priv->rps.cur_freq)
+               vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
+
+       I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
+
+       dev_priv->rps.cur_freq = val;
+       trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val));
+}
+
 /* vlv_set_rps_idle: Set the frequency to Rpn if Gfx clocks are down
  *
  * * If Gfx is Idle, then
@@ -3798,10 +4022,11 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
 static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
+       u32 val = dev_priv->rps.idle_freq;
 
        /* CHV and latest VLV don't need to force the gfx clock */
        if (IS_CHERRYVIEW(dev) || dev->pdev->revision >= 0xd) {
-               valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+               valleyview_set_rps(dev_priv->dev, val);
                return;
        }
 
@@ -3809,7 +4034,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
         * When we are idle.  Drop to min voltage state.
         */
 
-       if (dev_priv->rps.cur_freq <= dev_priv->rps.min_freq_softlimit)
+       if (dev_priv->rps.cur_freq <= val)
                return;
 
        /* Mask turbo interrupt so that they will not come in between */
@@ -3818,10 +4043,9 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
 
        vlv_force_gfx_clock(dev_priv, true);
 
-       dev_priv->rps.cur_freq = dev_priv->rps.min_freq_softlimit;
+       dev_priv->rps.cur_freq = val;
 
-       vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ,
-                                       dev_priv->rps.min_freq_softlimit);
+       vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
 
        if (wait_for(((vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS))
                                & GENFREQSTATUS) == 0, 100))
@@ -3829,8 +4053,19 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
 
        vlv_force_gfx_clock(dev_priv, false);
 
-       I915_WRITE(GEN6_PMINTRMSK,
-                  gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
+       I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
+}
+
+void gen6_rps_busy(struct drm_i915_private *dev_priv)
+{
+       mutex_lock(&dev_priv->rps.hw_lock);
+       if (dev_priv->rps.enabled) {
+               if (dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED))
+                       gen6_rps_reset_ei(dev_priv);
+               I915_WRITE(GEN6_PMINTRMSK,
+                          gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
+       }
+       mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
 void gen6_rps_idle(struct drm_i915_private *dev_priv)
@@ -3842,46 +4077,34 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
                if (IS_VALLEYVIEW(dev))
                        vlv_set_rps_idle(dev_priv);
                else
-                       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+                       gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
                dev_priv->rps.last_adj = 0;
+               I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
 void gen6_rps_boost(struct drm_i915_private *dev_priv)
 {
-       struct drm_device *dev = dev_priv->dev;
+       u32 val;
 
        mutex_lock(&dev_priv->rps.hw_lock);
-       if (dev_priv->rps.enabled) {
-               if (IS_VALLEYVIEW(dev))
-                       valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
-               else
-                       gen6_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
+       val = dev_priv->rps.max_freq_softlimit;
+       if (dev_priv->rps.enabled &&
+           dev_priv->mm.busy &&
+           dev_priv->rps.cur_freq < val) {
+               intel_set_rps(dev_priv->dev, val);
                dev_priv->rps.last_adj = 0;
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
-void valleyview_set_rps(struct drm_device *dev, u8 val)
+void intel_set_rps(struct drm_device *dev, u8 val)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-       WARN_ON(val > dev_priv->rps.max_freq_softlimit);
-       WARN_ON(val < dev_priv->rps.min_freq_softlimit);
-
-       if (WARN_ONCE(IS_CHERRYVIEW(dev) && (val & 1),
-                     "Odd GPU freq value\n"))
-               val &= ~1;
-
-       if (val != dev_priv->rps.cur_freq)
-               vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
-
-       I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
-
-       dev_priv->rps.cur_freq = val;
-       trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val));
+       if (IS_VALLEYVIEW(dev))
+               valleyview_set_rps(dev, val);
+       else
+               gen6_set_rps(dev, val);
 }
 
 static void gen9_disable_rps(struct drm_device *dev)
@@ -3995,6 +4218,13 @@ static void gen6_init_rps_frequencies(struct drm_device *dev)
        dev_priv->rps.rp0_freq          = (rp_state_cap >>  0) & 0xff;
        dev_priv->rps.rp1_freq          = (rp_state_cap >>  8) & 0xff;
        dev_priv->rps.min_freq          = (rp_state_cap >> 16) & 0xff;
+       if (IS_SKYLAKE(dev)) {
+               /* Store the frequency values in 16.66 MHZ units, which is
+                  the natural hardware unit for SKL */
+               dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER;
+               dev_priv->rps.rp1_freq *= GEN9_FREQ_SCALER;
+               dev_priv->rps.min_freq *= GEN9_FREQ_SCALER;
+       }
        /* hw_max = RP0 until we check for overclocking */
        dev_priv->rps.max_freq          = dev_priv->rps.rp0_freq;
 
@@ -4011,6 +4241,8 @@ static void gen6_init_rps_frequencies(struct drm_device *dev)
                                        dev_priv->rps.max_freq);
        }
 
+       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
        /* Preserve min/max settings in case of re-init */
        if (dev_priv->rps.max_freq_softlimit == 0)
                dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
@@ -4035,23 +4267,21 @@ static void gen9_enable_rps(struct drm_device *dev)
 
        gen6_init_rps_frequencies(dev);
 
-       I915_WRITE(GEN6_RPNSWREQ, 0xc800000);
-       I915_WRITE(GEN6_RC_VIDEO_FREQ, 0xc800000);
+       /* Program defaults and thresholds for RPS*/
+       I915_WRITE(GEN6_RC_VIDEO_FREQ,
+               GEN9_FREQUENCY(dev_priv->rps.rp1_freq));
+
+       /* 1 second timeout*/
+       I915_WRITE(GEN6_RP_DOWN_TIMEOUT,
+               GT_INTERVAL_FROM_US(dev_priv, 1000000));
 
-       I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 0xf4240);
-       I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, 0x12060000);
-       I915_WRITE(GEN6_RP_UP_THRESHOLD, 0xe808);
-       I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 0x3bd08);
-       I915_WRITE(GEN6_RP_UP_EI, 0x101d0);
-       I915_WRITE(GEN6_RP_DOWN_EI, 0x55730);
        I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 0xa);
-       I915_WRITE(GEN6_PMINTRMSK, 0x6);
-       I915_WRITE(GEN6_RP_CONTROL, GEN6_RP_MEDIA_TURBO |
-                  GEN6_RP_MEDIA_HW_MODE | GEN6_RP_MEDIA_IS_GFX |
-                  GEN6_RP_ENABLE | GEN6_RP_UP_BUSY_AVG |
-                  GEN6_RP_DOWN_IDLE_AVG);
 
-       gen6_enable_rps_interrupts(dev);
+       /* Leaning on the below call to gen6_set_rps to program/setup the
+        * Up/Down EI & threshold registers, as well as the RP_CONTROL,
+        * RP_INTERRUPT_LIMITS & RPNSWREQ registers */
+       dev_priv->rps.power = HIGH_POWER; /* force a reset */
+       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
@@ -4179,7 +4409,7 @@ static void gen8_enable_rps(struct drm_device *dev)
        /* 6: Ring frequency + overclocking (our driver does this later */
 
        dev_priv->rps.power = HIGH_POWER; /* force a reset */
-       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+       gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
@@ -4273,7 +4503,7 @@ static void gen6_enable_rps(struct drm_device *dev)
        }
 
        dev_priv->rps.power = HIGH_POWER; /* force a reset */
-       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+       gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
 
        rc6vids = 0;
        ret = sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids);
@@ -4638,6 +4868,8 @@ static void valleyview_init_gt_powersave(struct drm_device *dev)
                         intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
                         dev_priv->rps.min_freq);
 
+       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
        /* Preserve min/max settings in case of re-init */
        if (dev_priv->rps.max_freq_softlimit == 0)
                dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
@@ -4713,6 +4945,8 @@ static void cherryview_init_gt_powersave(struct drm_device *dev)
                   dev_priv->rps.min_freq) & 1,
                  "Odd GPU freq values\n");
 
+       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
        /* Preserve min/max settings in case of re-init */
        if (dev_priv->rps.max_freq_softlimit == 0)
                dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
@@ -4904,124 +5138,6 @@ static void valleyview_enable_rps(struct drm_device *dev)
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
 
-void ironlake_teardown_rc6(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->ips.renderctx) {
-               i915_gem_object_ggtt_unpin(dev_priv->ips.renderctx);
-               drm_gem_object_unreference(&dev_priv->ips.renderctx->base);
-               dev_priv->ips.renderctx = NULL;
-       }
-
-       if (dev_priv->ips.pwrctx) {
-               i915_gem_object_ggtt_unpin(dev_priv->ips.pwrctx);
-               drm_gem_object_unreference(&dev_priv->ips.pwrctx->base);
-               dev_priv->ips.pwrctx = NULL;
-       }
-}
-
-static void ironlake_disable_rc6(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (I915_READ(PWRCTXA)) {
-               /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
-               I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
-               wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
-                        50);
-
-               I915_WRITE(PWRCTXA, 0);
-               POSTING_READ(PWRCTXA);
-
-               I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
-               POSTING_READ(RSTDBYCTL);
-       }
-}
-
-static int ironlake_setup_rc6(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->ips.renderctx == NULL)
-               dev_priv->ips.renderctx = intel_alloc_context_page(dev);
-       if (!dev_priv->ips.renderctx)
-               return -ENOMEM;
-
-       if (dev_priv->ips.pwrctx == NULL)
-               dev_priv->ips.pwrctx = intel_alloc_context_page(dev);
-       if (!dev_priv->ips.pwrctx) {
-               ironlake_teardown_rc6(dev);
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void ironlake_enable_rc6(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_engine_cs *ring = &dev_priv->ring[RCS];
-       bool was_interruptible;
-       int ret;
-
-       /* rc6 disabled by default due to repeated reports of hanging during
-        * boot and resume.
-        */
-       if (!intel_enable_rc6(dev))
-               return;
-
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
-       ret = ironlake_setup_rc6(dev);
-       if (ret)
-               return;
-
-       was_interruptible = dev_priv->mm.interruptible;
-       dev_priv->mm.interruptible = false;
-
-       /*
-        * GPU can automatically power down the render unit if given a page
-        * to save state.
-        */
-       ret = intel_ring_begin(ring, 6);
-       if (ret) {
-               ironlake_teardown_rc6(dev);
-               dev_priv->mm.interruptible = was_interruptible;
-               return;
-       }
-
-       intel_ring_emit(ring, MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
-       intel_ring_emit(ring, MI_SET_CONTEXT);
-       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(dev_priv->ips.renderctx) |
-                       MI_MM_SPACE_GTT |
-                       MI_SAVE_EXT_STATE_EN |
-                       MI_RESTORE_EXT_STATE_EN |
-                       MI_RESTORE_INHIBIT);
-       intel_ring_emit(ring, MI_SUSPEND_FLUSH);
-       intel_ring_emit(ring, MI_NOOP);
-       intel_ring_emit(ring, MI_FLUSH);
-       intel_ring_advance(ring);
-
-       /*
-        * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
-        * does an implicit flush, combined with MI_FLUSH above, it should be
-        * safe to assume that renderctx is valid
-        */
-       ret = intel_ring_idle(ring);
-       dev_priv->mm.interruptible = was_interruptible;
-       if (ret) {
-               DRM_ERROR("failed to enable ironlake power savings\n");
-               ironlake_teardown_rc6(dev);
-               return;
-       }
-
-       I915_WRITE(PWRCTXA, i915_gem_obj_ggtt_offset(dev_priv->ips.pwrctx) | PWRCTX_EN);
-       I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
-
-       intel_print_rc6_info(dev, GEN6_RC_CTL_RC6_ENABLE);
-}
-
 static unsigned long intel_pxfreq(u32 vidfreq)
 {
        unsigned long freq;
@@ -5534,12 +5650,7 @@ static void gen6_suspend_rps(struct drm_device *dev)
 
        flush_delayed_work(&dev_priv->rps.delayed_resume_work);
 
-       /*
-        * TODO: disable RPS interrupts on GEN9+ too once RPS support
-        * is added for it.
-        */
-       if (INTEL_INFO(dev)->gen < 9)
-               gen6_disable_rps_interrupts(dev);
+       gen6_disable_rps_interrupts(dev);
 }
 
 /**
@@ -5569,7 +5680,6 @@ void intel_disable_gt_powersave(struct drm_device *dev)
 
        if (IS_IRONLAKE_M(dev)) {
                ironlake_disable_drps(dev);
-               ironlake_disable_rc6(dev);
        } else if (INTEL_INFO(dev)->gen >= 6) {
                intel_suspend_gt_powersave(dev);
 
@@ -5597,12 +5707,7 @@ static void intel_gen6_powersave_work(struct work_struct *work)
 
        mutex_lock(&dev_priv->rps.hw_lock);
 
-       /*
-        * TODO: reset/enable RPS interrupts on GEN9+ too, once RPS support is
-        * added for it.
-        */
-       if (INTEL_INFO(dev)->gen < 9)
-               gen6_reset_rps_interrupts(dev);
+       gen6_reset_rps_interrupts(dev);
 
        if (IS_CHERRYVIEW(dev)) {
                cherryview_enable_rps(dev);
@@ -5619,10 +5724,16 @@ static void intel_gen6_powersave_work(struct work_struct *work)
                gen6_enable_rps(dev);
                __gen6_update_ring_freq(dev);
        }
+
+       WARN_ON(dev_priv->rps.max_freq < dev_priv->rps.min_freq);
+       WARN_ON(dev_priv->rps.idle_freq > dev_priv->rps.max_freq);
+
+       WARN_ON(dev_priv->rps.efficient_freq < dev_priv->rps.min_freq);
+       WARN_ON(dev_priv->rps.efficient_freq > dev_priv->rps.max_freq);
+
        dev_priv->rps.enabled = true;
 
-       if (INTEL_INFO(dev)->gen < 9)
-               gen6_enable_rps_interrupts(dev);
+       gen6_enable_rps_interrupts(dev);
 
        mutex_unlock(&dev_priv->rps.hw_lock);
 
@@ -5633,10 +5744,13 @@ void intel_enable_gt_powersave(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       /* Powersaving is controlled by the host when inside a VM */
+       if (intel_vgpu_active(dev))
+               return;
+
        if (IS_IRONLAKE_M(dev)) {
                mutex_lock(&dev->struct_mutex);
                ironlake_enable_drps(dev);
-               ironlake_enable_rc6(dev);
                intel_init_emon(dev);
                mutex_unlock(&dev->struct_mutex);
        } else if (INTEL_INFO(dev)->gen >= 6) {
@@ -6169,11 +6283,22 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
        gen6_check_mch_setup(dev);
 }
 
+static void vlv_init_display_clock_gating(struct drm_i915_private *dev_priv)
+{
+       I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
+
+       /*
+        * Disable trickle feed and enable pnd deadline calculation
+        */
+       I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
+       I915_WRITE(CBR1_VLV, 0);
+}
+
 static void valleyview_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
+       vlv_init_display_clock_gating(dev_priv);
 
        /* WaDisableEarlyCull:vlv */
        I915_WRITE(_3D_CHICKEN3,
@@ -6221,8 +6346,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN7_UCGCTL4,
                   I915_READ(GEN7_UCGCTL4) | GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
 
-       I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
-
        /*
         * BSpec says this must be set, even though
         * WaDisable4x2SubspanOptimization isn't listed for VLV.
@@ -6259,9 +6382,7 @@ static void cherryview_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
-
-       I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
+       vlv_init_display_clock_gating(dev_priv);
 
        /* WaVSRefCountFullforceMissDisable:chv */
        /* WaDSRefCountFullforceMissDisable:chv */
@@ -6396,7 +6517,8 @@ void intel_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       dev_priv->display.init_clock_gating(dev);
+       if (dev_priv->display.init_clock_gating)
+               dev_priv->display.init_clock_gating(dev);
 }
 
 void intel_suspend_hw(struct drm_device *dev)
@@ -6422,7 +6544,7 @@ void intel_init_pm(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen >= 9) {
                skl_setup_wm_latency(dev);
 
-               dev_priv->display.init_clock_gating = gen9_init_clock_gating;
+               dev_priv->display.init_clock_gating = skl_init_clock_gating;
                dev_priv->display.update_wm = skl_update_wm;
                dev_priv->display.update_sprite_wm = skl_update_sprite_wm;
        } else if (HAS_PCH_SPLIT(dev)) {
@@ -6450,7 +6572,7 @@ void intel_init_pm(struct drm_device *dev)
                else if (INTEL_INFO(dev)->gen == 8)
                        dev_priv->display.init_clock_gating = broadwell_init_clock_gating;
        } else if (IS_CHERRYVIEW(dev)) {
-               dev_priv->display.update_wm = cherryview_update_wm;
+               dev_priv->display.update_wm = valleyview_update_wm;
                dev_priv->display.update_sprite_wm = valleyview_update_sprite_wm;
                dev_priv->display.init_clock_gating =
                        cherryview_init_clock_gating;
@@ -6618,7 +6740,9 @@ static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val)
 
 int intel_gpu_freq(struct drm_i915_private *dev_priv, int val)
 {
-       if (IS_CHERRYVIEW(dev_priv->dev))
+       if (IS_GEN9(dev_priv->dev))
+               return (val * GT_FREQUENCY_MULTIPLIER) / GEN9_FREQ_SCALER;
+       else if (IS_CHERRYVIEW(dev_priv->dev))
                return chv_gpu_freq(dev_priv, val);
        else if (IS_VALLEYVIEW(dev_priv->dev))
                return byt_gpu_freq(dev_priv, val);
@@ -6628,7 +6752,9 @@ int intel_gpu_freq(struct drm_i915_private *dev_priv, int val)
 
 int intel_freq_opcode(struct drm_i915_private *dev_priv, int val)
 {
-       if (IS_CHERRYVIEW(dev_priv->dev))
+       if (IS_GEN9(dev_priv->dev))
+               return (val * GEN9_FREQ_SCALER) / GT_FREQUENCY_MULTIPLIER;
+       else if (IS_CHERRYVIEW(dev_priv->dev))
                return chv_freq_opcode(dev_priv, val);
        else if (IS_VALLEYVIEW(dev_priv->dev))
                return byt_freq_opcode(dev_priv, val);
index b9f40c2e0af720ff3d8f18c4a53dcd187adb4eee..a8f9348259ae581f977ee1a244f1734947ef0be1 100644 (file)
@@ -532,8 +532,6 @@ static void intel_psr_exit(struct drm_device *dev)
                WARN_ON(!(val & EDP_PSR_ENABLE));
 
                I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE);
-
-               dev_priv->psr.active = false;
        } else {
                val = I915_READ(VLV_PSRCTL(pipe));
 
index e5b3c6dbd46780798e1607b0f3390db5465ecbd5..441e2502b88946ff2d7455a9f26cc32faa87d8fc 100644 (file)
@@ -317,29 +317,6 @@ gen7_render_ring_cs_stall_wa(struct intel_engine_cs *ring)
        return 0;
 }
 
-static int gen7_ring_fbc_flush(struct intel_engine_cs *ring, u32 value)
-{
-       int ret;
-
-       if (!ring->fbc_dirty)
-               return 0;
-
-       ret = intel_ring_begin(ring, 6);
-       if (ret)
-               return ret;
-       /* WaFbcNukeOn3DBlt:ivb/hsw */
-       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
-       intel_ring_emit(ring, MSG_FBC_REND_STATE);
-       intel_ring_emit(ring, value);
-       intel_ring_emit(ring, MI_STORE_REGISTER_MEM(1) | MI_SRM_LRM_GLOBAL_GTT);
-       intel_ring_emit(ring, MSG_FBC_REND_STATE);
-       intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
-       intel_ring_advance(ring);
-
-       ring->fbc_dirty = false;
-       return 0;
-}
-
 static int
 gen7_render_ring_flush(struct intel_engine_cs *ring,
                       u32 invalidate_domains, u32 flush_domains)
@@ -398,9 +375,6 @@ gen7_render_ring_flush(struct intel_engine_cs *ring,
        intel_ring_emit(ring, 0);
        intel_ring_advance(ring);
 
-       if (!invalidate_domains && flush_domains)
-               return gen7_ring_fbc_flush(ring, FBC_REND_NUKE);
-
        return 0;
 }
 
@@ -458,14 +432,7 @@ gen8_render_ring_flush(struct intel_engine_cs *ring,
                        return ret;
        }
 
-       ret = gen8_emit_pipe_control(ring, flags, scratch_addr);
-       if (ret)
-               return ret;
-
-       if (!invalidate_domains && flush_domains)
-               return gen7_ring_fbc_flush(ring, FBC_REND_NUKE);
-
-       return 0;
+       return gen8_emit_pipe_control(ring, flags, scratch_addr);
 }
 
 static void ring_write_tail(struct intel_engine_cs *ring,
@@ -502,6 +469,68 @@ static void ring_setup_phys_status_page(struct intel_engine_cs *ring)
        I915_WRITE(HWS_PGA, addr);
 }
 
+static void intel_ring_setup_status_page(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       u32 mmio = 0;
+
+       /* The ring status page addresses are no longer next to the rest of
+        * the ring registers as of gen7.
+        */
+       if (IS_GEN7(dev)) {
+               switch (ring->id) {
+               case RCS:
+                       mmio = RENDER_HWS_PGA_GEN7;
+                       break;
+               case BCS:
+                       mmio = BLT_HWS_PGA_GEN7;
+                       break;
+               /*
+                * VCS2 actually doesn't exist on Gen7. Only shut up
+                * gcc switch check warning
+                */
+               case VCS2:
+               case VCS:
+                       mmio = BSD_HWS_PGA_GEN7;
+                       break;
+               case VECS:
+                       mmio = VEBOX_HWS_PGA_GEN7;
+                       break;
+               }
+       } else if (IS_GEN6(ring->dev)) {
+               mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
+       } else {
+               /* XXX: gen8 returns to sanity */
+               mmio = RING_HWS_PGA(ring->mmio_base);
+       }
+
+       I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
+       POSTING_READ(mmio);
+
+       /*
+        * Flush the TLB for this page
+        *
+        * FIXME: These two bits have disappeared on gen8, so a question
+        * arises: do we still need this and if so how should we go about
+        * invalidating the TLB?
+        */
+       if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) {
+               u32 reg = RING_INSTPM(ring->mmio_base);
+
+               /* ring should be idle before issuing a sync flush*/
+               WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
+
+               I915_WRITE(reg,
+                          _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE |
+                                             INSTPM_SYNC_FLUSH));
+               if (wait_for((I915_READ(reg) & INSTPM_SYNC_FLUSH) == 0,
+                            1000))
+                       DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n",
+                                 ring->name);
+       }
+}
+
 static bool stop_ring(struct intel_engine_cs *ring)
 {
        struct drm_i915_private *dev_priv = to_i915(ring->dev);
@@ -788,12 +817,14 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring)
         * workaround for for a possible hang in the unlikely event a TLB
         * invalidation occurs during a PSD flush.
         */
-       /* WaForceEnableNonCoherent:bdw */
-       /* WaHdcDisableFetchWhenMasked:bdw */
-       /* WaDisableFenceDestinationToSLM:bdw (GT3 pre-production) */
        WA_SET_BIT_MASKED(HDC_CHICKEN0,
+                         /* WaForceEnableNonCoherent:bdw */
                          HDC_FORCE_NON_COHERENT |
+                         /* WaForceContextSaveRestoreNonCoherent:bdw */
+                         HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
+                         /* WaHdcDisableFetchWhenMasked:bdw */
                          HDC_DONOT_FETCH_MEM_WHEN_MASKED |
+                         /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */
                          (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
 
        /* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0:
@@ -870,9 +901,132 @@ static int chv_init_workarounds(struct intel_engine_cs *ring)
                            GEN6_WIZ_HASHING_MASK,
                            GEN6_WIZ_HASHING_16x4);
 
+       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);
+
        return 0;
 }
 
+static int gen9_init_workarounds(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /* WaDisablePartialInstShootdown:skl */
+       WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
+                         PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
+
+       /* Syncing dependencies between camera and graphics */
+       WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
+                         GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
+
+       if (INTEL_REVID(dev) == SKL_REVID_A0 ||
+           INTEL_REVID(dev) == SKL_REVID_B0) {
+               /* WaDisableDgMirrorFixInHalfSliceChicken5:skl */
+               WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
+                                 GEN9_DG_MIRROR_FIX_ENABLE);
+       }
+
+       if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) {
+               /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl */
+               WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1,
+                                 GEN9_RHWO_OPTIMIZATION_DISABLE);
+               WA_SET_BIT_MASKED(GEN9_SLICE_COMMON_ECO_CHICKEN0,
+                                 DISABLE_PIXEL_MASK_CAMMING);
+       }
+
+       if (INTEL_REVID(dev) >= SKL_REVID_C0) {
+               /* WaEnableYV12BugFixInHalfSliceChicken7:skl */
+               WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
+                                 GEN9_ENABLE_YV12_BUGFIX);
+       }
+
+       if (INTEL_REVID(dev) <= SKL_REVID_D0) {
+               /*
+                *Use Force Non-Coherent whenever executing a 3D context. This
+                * is a workaround for a possible hang in the unlikely event
+                * a TLB invalidation occurs during a PSD flush.
+                */
+               /* WaForceEnableNonCoherent:skl */
+               WA_SET_BIT_MASKED(HDC_CHICKEN0,
+                                 HDC_FORCE_NON_COHERENT);
+       }
+
+       /* Wa4x4STCOptimizationDisable:skl */
+       WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE);
+
+       /* WaDisablePartialResolveInVc:skl */
+       WA_SET_BIT_MASKED(CACHE_MODE_1, GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE);
+
+       /* WaCcsTlbPrefetchDisable:skl */
+       WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
+                         GEN9_CCS_TLB_PREFETCH_ENABLE);
+
+       return 0;
+}
+
+static int skl_tune_iz_hashing(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u8 vals[3] = { 0, 0, 0 };
+       unsigned int i;
+
+       for (i = 0; i < 3; i++) {
+               u8 ss;
+
+               /*
+                * Only consider slices where one, and only one, subslice has 7
+                * EUs
+                */
+               if (hweight8(dev_priv->info.subslice_7eu[i]) != 1)
+                       continue;
+
+               /*
+                * subslice_7eu[i] != 0 (because of the check above) and
+                * ss_max == 4 (maximum number of subslices possible per slice)
+                *
+                * ->    0 <= ss <= 3;
+                */
+               ss = ffs(dev_priv->info.subslice_7eu[i]) - 1;
+               vals[i] = 3 - ss;
+       }
+
+       if (vals[0] == 0 && vals[1] == 0 && vals[2] == 0)
+               return 0;
+
+       /* Tune IZ hashing. See intel_device_info_runtime_init() */
+       WA_SET_FIELD_MASKED(GEN7_GT_MODE,
+                           GEN9_IZ_HASHING_MASK(2) |
+                           GEN9_IZ_HASHING_MASK(1) |
+                           GEN9_IZ_HASHING_MASK(0),
+                           GEN9_IZ_HASHING(2, vals[2]) |
+                           GEN9_IZ_HASHING(1, vals[1]) |
+                           GEN9_IZ_HASHING(0, vals[0]));
+
+       return 0;
+}
+
+
+static int skl_init_workarounds(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       gen9_init_workarounds(ring);
+
+       /* WaDisablePowerCompilerClockGating:skl */
+       if (INTEL_REVID(dev) == SKL_REVID_B0)
+               WA_SET_BIT_MASKED(HIZ_CHICKEN,
+                                 BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE);
+
+       return skl_tune_iz_hashing(ring);
+}
+
 int init_workarounds_ring(struct intel_engine_cs *ring)
 {
        struct drm_device *dev = ring->dev;
@@ -888,6 +1042,11 @@ int init_workarounds_ring(struct intel_engine_cs *ring)
        if (IS_CHERRYVIEW(dev))
                return chv_init_workarounds(ring);
 
+       if (IS_SKYLAKE(dev))
+               return skl_init_workarounds(ring);
+       else if (IS_GEN9(dev))
+               return gen9_init_workarounds(ring);
+
        return 0;
 }
 
@@ -1386,68 +1545,6 @@ i8xx_ring_put_irq(struct intel_engine_cs *ring)
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 }
 
-void intel_ring_setup_status_page(struct intel_engine_cs *ring)
-{
-       struct drm_device *dev = ring->dev;
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
-       u32 mmio = 0;
-
-       /* The ring status page addresses are no longer next to the rest of
-        * the ring registers as of gen7.
-        */
-       if (IS_GEN7(dev)) {
-               switch (ring->id) {
-               case RCS:
-                       mmio = RENDER_HWS_PGA_GEN7;
-                       break;
-               case BCS:
-                       mmio = BLT_HWS_PGA_GEN7;
-                       break;
-               /*
-                * VCS2 actually doesn't exist on Gen7. Only shut up
-                * gcc switch check warning
-                */
-               case VCS2:
-               case VCS:
-                       mmio = BSD_HWS_PGA_GEN7;
-                       break;
-               case VECS:
-                       mmio = VEBOX_HWS_PGA_GEN7;
-                       break;
-               }
-       } else if (IS_GEN6(ring->dev)) {
-               mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
-       } else {
-               /* XXX: gen8 returns to sanity */
-               mmio = RING_HWS_PGA(ring->mmio_base);
-       }
-
-       I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
-       POSTING_READ(mmio);
-
-       /*
-        * Flush the TLB for this page
-        *
-        * FIXME: These two bits have disappeared on gen8, so a question
-        * arises: do we still need this and if so how should we go about
-        * invalidating the TLB?
-        */
-       if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) {
-               u32 reg = RING_INSTPM(ring->mmio_base);
-
-               /* ring should be idle before issuing a sync flush*/
-               WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
-
-               I915_WRITE(reg,
-                          _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE |
-                                             INSTPM_SYNC_FLUSH));
-               if (wait_for((I915_READ(reg) & INSTPM_SYNC_FLUSH) == 0,
-                            1000))
-                       DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n",
-                                 ring->name);
-       }
-}
-
 static int
 bsd_ring_flush(struct intel_engine_cs *ring,
               u32     invalidate_domains,
@@ -1611,7 +1708,7 @@ gen8_ring_put_irq(struct intel_engine_cs *ring)
 static int
 i965_dispatch_execbuffer(struct intel_engine_cs *ring,
                         u64 offset, u32 length,
-                        unsigned flags)
+                        unsigned dispatch_flags)
 {
        int ret;
 
@@ -1622,7 +1719,8 @@ i965_dispatch_execbuffer(struct intel_engine_cs *ring,
        intel_ring_emit(ring,
                        MI_BATCH_BUFFER_START |
                        MI_BATCH_GTT |
-                       (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE_I965));
+                       (dispatch_flags & I915_DISPATCH_SECURE ?
+                        0 : MI_BATCH_NON_SECURE_I965));
        intel_ring_emit(ring, offset);
        intel_ring_advance(ring);
 
@@ -1635,8 +1733,8 @@ i965_dispatch_execbuffer(struct intel_engine_cs *ring,
 #define I830_WA_SIZE max(I830_TLB_ENTRIES*4096, I830_BATCH_LIMIT)
 static int
 i830_dispatch_execbuffer(struct intel_engine_cs *ring,
-                               u64 offset, u32 len,
-                               unsigned flags)
+                        u64 offset, u32 len,
+                        unsigned dispatch_flags)
 {
        u32 cs_offset = ring->scratch.gtt_offset;
        int ret;
@@ -1654,7 +1752,7 @@ i830_dispatch_execbuffer(struct intel_engine_cs *ring,
        intel_ring_emit(ring, MI_NOOP);
        intel_ring_advance(ring);
 
-       if ((flags & I915_DISPATCH_PINNED) == 0) {
+       if ((dispatch_flags & I915_DISPATCH_PINNED) == 0) {
                if (len > I830_BATCH_LIMIT)
                        return -ENOSPC;
 
@@ -1686,7 +1784,8 @@ i830_dispatch_execbuffer(struct intel_engine_cs *ring,
                return ret;
 
        intel_ring_emit(ring, MI_BATCH_BUFFER);
-       intel_ring_emit(ring, offset | (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE));
+       intel_ring_emit(ring, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
+                                       0 : MI_BATCH_NON_SECURE));
        intel_ring_emit(ring, offset + len - 8);
        intel_ring_emit(ring, MI_NOOP);
        intel_ring_advance(ring);
@@ -1697,7 +1796,7 @@ i830_dispatch_execbuffer(struct intel_engine_cs *ring,
 static int
 i915_dispatch_execbuffer(struct intel_engine_cs *ring,
                         u64 offset, u32 len,
-                        unsigned flags)
+                        unsigned dispatch_flags)
 {
        int ret;
 
@@ -1706,7 +1805,8 @@ i915_dispatch_execbuffer(struct intel_engine_cs *ring,
                return ret;
 
        intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
-       intel_ring_emit(ring, offset | (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE));
+       intel_ring_emit(ring, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
+                                       0 : MI_BATCH_NON_SECURE));
        intel_ring_advance(ring);
 
        return 0;
@@ -2097,6 +2197,7 @@ intel_ring_alloc_request(struct intel_engine_cs *ring)
 
        kref_init(&request->ref);
        request->ring = ring;
+       request->ringbuf = ring->buffer;
        request->uniq = dev_private->request_uniq++;
 
        ret = i915_gem_get_seqno(ring->dev, &request->seqno);
@@ -2273,9 +2374,10 @@ static int gen6_bsd_ring_flush(struct intel_engine_cs *ring,
 static int
 gen8_ring_dispatch_execbuffer(struct intel_engine_cs *ring,
                              u64 offset, u32 len,
-                             unsigned flags)
+                             unsigned dispatch_flags)
 {
-       bool ppgtt = USES_PPGTT(ring->dev) && !(flags & I915_DISPATCH_SECURE);
+       bool ppgtt = USES_PPGTT(ring->dev) &&
+                       !(dispatch_flags & I915_DISPATCH_SECURE);
        int ret;
 
        ret = intel_ring_begin(ring, 4);
@@ -2294,8 +2396,8 @@ gen8_ring_dispatch_execbuffer(struct intel_engine_cs *ring,
 
 static int
 hsw_ring_dispatch_execbuffer(struct intel_engine_cs *ring,
-                             u64 offset, u32 len,
-                             unsigned flags)
+                            u64 offset, u32 len,
+                            unsigned dispatch_flags)
 {
        int ret;
 
@@ -2305,7 +2407,7 @@ hsw_ring_dispatch_execbuffer(struct intel_engine_cs *ring,
 
        intel_ring_emit(ring,
                        MI_BATCH_BUFFER_START |
-                       (flags & I915_DISPATCH_SECURE ?
+                       (dispatch_flags & I915_DISPATCH_SECURE ?
                         0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW));
        /* bit0-7 is the length on GEN6+ */
        intel_ring_emit(ring, offset);
@@ -2317,7 +2419,7 @@ hsw_ring_dispatch_execbuffer(struct intel_engine_cs *ring,
 static int
 gen6_ring_dispatch_execbuffer(struct intel_engine_cs *ring,
                              u64 offset, u32 len,
-                             unsigned flags)
+                             unsigned dispatch_flags)
 {
        int ret;
 
@@ -2327,7 +2429,8 @@ gen6_ring_dispatch_execbuffer(struct intel_engine_cs *ring,
 
        intel_ring_emit(ring,
                        MI_BATCH_BUFFER_START |
-                       (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE_I965));
+                       (dispatch_flags & I915_DISPATCH_SECURE ?
+                        0 : MI_BATCH_NON_SECURE_I965));
        /* bit0-7 is the length on GEN6+ */
        intel_ring_emit(ring, offset);
        intel_ring_advance(ring);
@@ -2341,7 +2444,6 @@ static int gen6_ring_flush(struct intel_engine_cs *ring,
                           u32 invalidate, u32 flush)
 {
        struct drm_device *dev = ring->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t cmd;
        int ret;
 
@@ -2350,7 +2452,7 @@ static int gen6_ring_flush(struct intel_engine_cs *ring,
                return ret;
 
        cmd = MI_FLUSH_DW;
-       if (INTEL_INFO(ring->dev)->gen >= 8)
+       if (INTEL_INFO(dev)->gen >= 8)
                cmd += 1;
 
        /* We always require a command barrier so that subsequent
@@ -2370,7 +2472,7 @@ static int gen6_ring_flush(struct intel_engine_cs *ring,
                cmd |= MI_INVALIDATE_TLB;
        intel_ring_emit(ring, cmd);
        intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
-       if (INTEL_INFO(ring->dev)->gen >= 8) {
+       if (INTEL_INFO(dev)->gen >= 8) {
                intel_ring_emit(ring, 0); /* upper addr */
                intel_ring_emit(ring, 0); /* value */
        } else  {
@@ -2379,13 +2481,6 @@ static int gen6_ring_flush(struct intel_engine_cs *ring,
        }
        intel_ring_advance(ring);
 
-       if (!invalidate && flush) {
-               if (IS_GEN7(dev))
-                       return gen7_ring_fbc_flush(ring, FBC_REND_CACHE_CLEAN);
-               else if (IS_BROADWELL(dev))
-                       dev_priv->fbc.need_sw_cache_clean = true;
-       }
-
        return 0;
 }
 
@@ -2612,19 +2707,13 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
 }
 
 /**
- * Initialize the second BSD ring for Broadwell GT3.
- * It is noted that this only exists on Broadwell GT3.
+ * Initialize the second BSD ring (eg. Broadwell GT3, Skylake GT3)
  */
 int intel_init_bsd2_ring_buffer(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_engine_cs *ring = &dev_priv->ring[VCS2];
 
-       if ((INTEL_INFO(dev)->gen != 8)) {
-               DRM_ERROR("No dual-BSD ring on non-BDW machine\n");
-               return -EINVAL;
-       }
-
        ring->name = "bsd2 ring";
        ring->id = VCS2;
 
index 714f3fdd57d2d58503fbb387cea75e253512bc44..c761fe05ad6fd9542d3a5101e8466aa9339ef130 100644 (file)
@@ -164,7 +164,7 @@ struct  intel_engine_cs {
                                     u32 seqno);
        int             (*dispatch_execbuffer)(struct intel_engine_cs *ring,
                                               u64 offset, u32 length,
-                                              unsigned flags);
+                                              unsigned dispatch_flags);
 #define I915_DISPATCH_SECURE 0x1
 #define I915_DISPATCH_PINNED 0x2
        void            (*cleanup)(struct intel_engine_cs *ring);
@@ -242,7 +242,7 @@ struct  intel_engine_cs {
                                      u32 flush_domains);
        int             (*emit_bb_start)(struct intel_ringbuffer *ringbuf,
                                         struct intel_context *ctx,
-                                        u64 offset, unsigned flags);
+                                        u64 offset, unsigned dispatch_flags);
 
        /**
         * List of objects currently involved in rendering from the
@@ -267,7 +267,6 @@ struct  intel_engine_cs {
         */
        struct drm_i915_gem_request *outstanding_lazy_request;
        bool gpu_caches_dirty;
-       bool fbc_dirty;
 
        wait_queue_head_t irq_queue;
 
@@ -373,11 +372,12 @@ intel_write_status_page(struct intel_engine_cs *ring,
  * 0x06: ring 2 head pointer (915-class)
  * 0x10-0x1b: Context status DWords (GM45)
  * 0x1f: Last written status offset. (GM45)
+ * 0x20-0x2f: Reserved (Gen6+)
  *
- * The area from dword 0x20 to 0x3ff is available for driver usage.
+ * The area from dword 0x30 to 0x3ff is available for driver usage.
  */
-#define I915_GEM_HWS_INDEX             0x20
-#define I915_GEM_HWS_SCRATCH_INDEX     0x30
+#define I915_GEM_HWS_INDEX             0x30
+#define I915_GEM_HWS_SCRATCH_INDEX     0x40
 #define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
 
 void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf);
@@ -425,7 +425,6 @@ int intel_init_blt_ring_buffer(struct drm_device *dev);
 int intel_init_vebox_ring_buffer(struct drm_device *dev);
 
 u64 intel_ring_get_active_head(struct intel_engine_cs *ring);
-void intel_ring_setup_status_page(struct intel_engine_cs *ring);
 
 int init_workarounds_ring(struct intel_engine_cs *ring);
 
index 49695d7d51e384bdfd81e361ec28d50612270b02..ce00e6994eeb9585cb0b6e89e08952a0f64ab6ab 100644 (file)
@@ -194,8 +194,39 @@ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
        outb(inb(VGA_MSR_READ), VGA_MSR_WRITE);
        vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
 
-       if (IS_BROADWELL(dev) || (INTEL_INFO(dev)->gen >= 9))
-               gen8_irq_power_well_post_enable(dev_priv);
+       if (IS_BROADWELL(dev))
+               gen8_irq_power_well_post_enable(dev_priv,
+                                               1 << PIPE_C | 1 << PIPE_B);
+}
+
+static void skl_power_well_post_enable(struct drm_i915_private *dev_priv,
+                                      struct i915_power_well *power_well)
+{
+       struct drm_device *dev = dev_priv->dev;
+
+       /*
+        * After we re-enable the power well, if we touch VGA register 0x3d5
+        * we'll get unclaimed register interrupts. This stops after we write
+        * anything to the VGA MSR register. The vgacon module uses this
+        * register all the time, so if we unbind our driver and, as a
+        * consequence, bind vgacon, we'll get stuck in an infinite loop at
+        * console_unlock(). So make here we touch the VGA MSR register, making
+        * sure vgacon can keep working normally without triggering interrupts
+        * and error messages.
+        */
+       if (power_well->data == SKL_DISP_PW_2) {
+               vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
+               outb(inb(VGA_MSR_READ), VGA_MSR_WRITE);
+               vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
+
+               gen8_irq_power_well_post_enable(dev_priv,
+                                               1 << PIPE_C | 1 << PIPE_B);
+       }
+
+       if (power_well->data == SKL_DISP_PW_1) {
+               intel_prepare_ddi(dev);
+               gen8_irq_power_well_post_enable(dev_priv, 1 << PIPE_A);
+       }
 }
 
 static void hsw_set_power_well(struct drm_i915_private *dev_priv,
@@ -230,6 +261,141 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
        }
 }
 
+#define SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS (                \
+       BIT(POWER_DOMAIN_TRANSCODER_A) |                \
+       BIT(POWER_DOMAIN_PIPE_B) |                      \
+       BIT(POWER_DOMAIN_TRANSCODER_B) |                \
+       BIT(POWER_DOMAIN_PIPE_C) |                      \
+       BIT(POWER_DOMAIN_TRANSCODER_C) |                \
+       BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) |         \
+       BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) |         \
+       BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |          \
+       BIT(POWER_DOMAIN_AUX_B) |                       \
+       BIT(POWER_DOMAIN_AUX_C) |                       \
+       BIT(POWER_DOMAIN_AUX_D) |                       \
+       BIT(POWER_DOMAIN_AUDIO) |                       \
+       BIT(POWER_DOMAIN_VGA) |                         \
+       BIT(POWER_DOMAIN_INIT))
+#define SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS (                \
+       SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS |         \
+       BIT(POWER_DOMAIN_PLLS) |                        \
+       BIT(POWER_DOMAIN_PIPE_A) |                      \
+       BIT(POWER_DOMAIN_TRANSCODER_EDP) |              \
+       BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) |         \
+       BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |          \
+       BIT(POWER_DOMAIN_AUX_A) |                       \
+       BIT(POWER_DOMAIN_INIT))
+#define SKL_DISPLAY_DDI_A_E_POWER_DOMAINS (            \
+       BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |          \
+       BIT(POWER_DOMAIN_INIT))
+#define SKL_DISPLAY_DDI_B_POWER_DOMAINS (              \
+       BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |          \
+       BIT(POWER_DOMAIN_INIT))
+#define SKL_DISPLAY_DDI_C_POWER_DOMAINS (              \
+       BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |          \
+       BIT(POWER_DOMAIN_INIT))
+#define SKL_DISPLAY_DDI_D_POWER_DOMAINS (              \
+       BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |          \
+       BIT(POWER_DOMAIN_INIT))
+#define SKL_DISPLAY_MISC_IO_POWER_DOMAINS (            \
+       SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS)
+#define SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS (          \
+       (POWER_DOMAIN_MASK & ~(SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS |  \
+       SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS |         \
+       SKL_DISPLAY_DDI_A_E_POWER_DOMAINS |             \
+       SKL_DISPLAY_DDI_B_POWER_DOMAINS |               \
+       SKL_DISPLAY_DDI_C_POWER_DOMAINS |               \
+       SKL_DISPLAY_DDI_D_POWER_DOMAINS |               \
+       SKL_DISPLAY_MISC_IO_POWER_DOMAINS)) |           \
+       BIT(POWER_DOMAIN_INIT))
+
+static void skl_set_power_well(struct drm_i915_private *dev_priv,
+                       struct i915_power_well *power_well, bool enable)
+{
+       uint32_t tmp, fuse_status;
+       uint32_t req_mask, state_mask;
+       bool is_enabled, enable_requested, check_fuse_status = false;
+
+       tmp = I915_READ(HSW_PWR_WELL_DRIVER);
+       fuse_status = I915_READ(SKL_FUSE_STATUS);
+
+       switch (power_well->data) {
+       case SKL_DISP_PW_1:
+               if (wait_for((I915_READ(SKL_FUSE_STATUS) &
+                       SKL_FUSE_PG0_DIST_STATUS), 1)) {
+                       DRM_ERROR("PG0 not enabled\n");
+                       return;
+               }
+               break;
+       case SKL_DISP_PW_2:
+               if (!(fuse_status & SKL_FUSE_PG1_DIST_STATUS)) {
+                       DRM_ERROR("PG1 in disabled state\n");
+                       return;
+               }
+               break;
+       case SKL_DISP_PW_DDI_A_E:
+       case SKL_DISP_PW_DDI_B:
+       case SKL_DISP_PW_DDI_C:
+       case SKL_DISP_PW_DDI_D:
+       case SKL_DISP_PW_MISC_IO:
+               break;
+       default:
+               WARN(1, "Unknown power well %lu\n", power_well->data);
+               return;
+       }
+
+       req_mask = SKL_POWER_WELL_REQ(power_well->data);
+       enable_requested = tmp & req_mask;
+       state_mask = SKL_POWER_WELL_STATE(power_well->data);
+       is_enabled = tmp & state_mask;
+
+       if (enable) {
+               if (!enable_requested) {
+                       I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask);
+               }
+
+               if (!is_enabled) {
+                       DRM_DEBUG_KMS("Enabling %s\n", power_well->name);
+                       if (wait_for((I915_READ(HSW_PWR_WELL_DRIVER) &
+                               state_mask), 1))
+                               DRM_ERROR("%s enable timeout\n",
+                                       power_well->name);
+                       check_fuse_status = true;
+               }
+       } else {
+               if (enable_requested) {
+                       I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask);
+                       POSTING_READ(HSW_PWR_WELL_DRIVER);
+                       DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
+               }
+       }
+
+       if (check_fuse_status) {
+               if (power_well->data == SKL_DISP_PW_1) {
+                       if (wait_for((I915_READ(SKL_FUSE_STATUS) &
+                               SKL_FUSE_PG1_DIST_STATUS), 1))
+                               DRM_ERROR("PG1 distributing status timeout\n");
+               } else if (power_well->data == SKL_DISP_PW_2) {
+                       if (wait_for((I915_READ(SKL_FUSE_STATUS) &
+                               SKL_FUSE_PG2_DIST_STATUS), 1))
+                               DRM_ERROR("PG2 distributing status timeout\n");
+               }
+       }
+
+       if (enable && !is_enabled)
+               skl_power_well_post_enable(dev_priv, power_well);
+}
+
 static void hsw_power_well_sync_hw(struct drm_i915_private *dev_priv,
                                   struct i915_power_well *power_well)
 {
@@ -255,6 +421,36 @@ static void hsw_power_well_disable(struct drm_i915_private *dev_priv,
        hsw_set_power_well(dev_priv, power_well, false);
 }
 
+static bool skl_power_well_enabled(struct drm_i915_private *dev_priv,
+                                       struct i915_power_well *power_well)
+{
+       uint32_t mask = SKL_POWER_WELL_REQ(power_well->data) |
+               SKL_POWER_WELL_STATE(power_well->data);
+
+       return (I915_READ(HSW_PWR_WELL_DRIVER) & mask) == mask;
+}
+
+static void skl_power_well_sync_hw(struct drm_i915_private *dev_priv,
+                               struct i915_power_well *power_well)
+{
+       skl_set_power_well(dev_priv, power_well, power_well->count > 0);
+
+       /* Clear any request made by BIOS as driver is taking over */
+       I915_WRITE(HSW_PWR_WELL_BIOS, 0);
+}
+
+static void skl_power_well_enable(struct drm_i915_private *dev_priv,
+                               struct i915_power_well *power_well)
+{
+       skl_set_power_well(dev_priv, power_well, true);
+}
+
+static void skl_power_well_disable(struct drm_i915_private *dev_priv,
+                               struct i915_power_well *power_well)
+{
+       skl_set_power_well(dev_priv, power_well, false);
+}
+
 static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
                                           struct i915_power_well *power_well)
 {
@@ -829,6 +1025,13 @@ static const struct i915_power_well_ops hsw_power_well_ops = {
        .is_enabled = hsw_power_well_enabled,
 };
 
+static const struct i915_power_well_ops skl_power_well_ops = {
+       .sync_hw = skl_power_well_sync_hw,
+       .enable = skl_power_well_enable,
+       .disable = skl_power_well_disable,
+       .is_enabled = skl_power_well_enabled,
+};
+
 static struct i915_power_well hsw_power_wells[] = {
        {
                .name = "always-on",
@@ -1059,6 +1262,57 @@ static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_pr
        return NULL;
 }
 
+static struct i915_power_well skl_power_wells[] = {
+       {
+               .name = "always-on",
+               .always_on = 1,
+               .domains = SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS,
+               .ops = &i9xx_always_on_power_well_ops,
+       },
+       {
+               .name = "power well 1",
+               .domains = SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS,
+               .ops = &skl_power_well_ops,
+               .data = SKL_DISP_PW_1,
+       },
+       {
+               .name = "MISC IO power well",
+               .domains = SKL_DISPLAY_MISC_IO_POWER_DOMAINS,
+               .ops = &skl_power_well_ops,
+               .data = SKL_DISP_PW_MISC_IO,
+       },
+       {
+               .name = "power well 2",
+               .domains = SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS,
+               .ops = &skl_power_well_ops,
+               .data = SKL_DISP_PW_2,
+       },
+       {
+               .name = "DDI A/E power well",
+               .domains = SKL_DISPLAY_DDI_A_E_POWER_DOMAINS,
+               .ops = &skl_power_well_ops,
+               .data = SKL_DISP_PW_DDI_A_E,
+       },
+       {
+               .name = "DDI B power well",
+               .domains = SKL_DISPLAY_DDI_B_POWER_DOMAINS,
+               .ops = &skl_power_well_ops,
+               .data = SKL_DISP_PW_DDI_B,
+       },
+       {
+               .name = "DDI C power well",
+               .domains = SKL_DISPLAY_DDI_C_POWER_DOMAINS,
+               .ops = &skl_power_well_ops,
+               .data = SKL_DISP_PW_DDI_C,
+       },
+       {
+               .name = "DDI D power well",
+               .domains = SKL_DISPLAY_DDI_D_POWER_DOMAINS,
+               .ops = &skl_power_well_ops,
+               .data = SKL_DISP_PW_DDI_D,
+       },
+};
+
 #define set_power_wells(power_domains, __power_wells) ({               \
        (power_domains)->power_wells = (__power_wells);                 \
        (power_domains)->power_well_count = ARRAY_SIZE(__power_wells);  \
@@ -1085,6 +1339,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
                set_power_wells(power_domains, hsw_power_wells);
        } else if (IS_BROADWELL(dev_priv->dev)) {
                set_power_wells(power_domains, bdw_power_wells);
+       } else if (IS_SKYLAKE(dev_priv->dev)) {
+               set_power_wells(power_domains, skl_power_wells);
        } else if (IS_CHERRYVIEW(dev_priv->dev)) {
                set_power_wells(power_domains, chv_power_wells);
        } else if (IS_VALLEYVIEW(dev_priv->dev)) {
@@ -1200,7 +1456,7 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
 }
 
 /**
- * intel_aux_display_runtime_get - grab an auxilliary power domain reference
+ * intel_aux_display_runtime_get - grab an auxiliary power domain reference
  * @dev_priv: i915 device instance
  *
  * This function grabs a power domain reference for the auxiliary power domain
@@ -1217,10 +1473,10 @@ void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
 }
 
 /**
- * intel_aux_display_runtime_put - release an auxilliary power domain reference
+ * intel_aux_display_runtime_put - release an auxiliary power domain reference
  * @dev_priv: i915 device instance
  *
- * This function drops the auxilliary power domain reference obtained by
+ * This function drops the auxiliary power domain reference obtained by
  * intel_aux_display_runtime_get() and might power down the corresponding
  * hardware block right away if this is the last reference.
  */
index 64ad2b40179f7d820133fab7532edc1fee848acf..f5b7e1e7c5e039ffe53023fcb166c9fd9b5f6e76 100644 (file)
@@ -1247,7 +1247,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
 
        switch (crtc->config->pixel_multiplier) {
        default:
-               WARN(1, "unknown pixel mutlipler specified\n");
+               WARN(1, "unknown pixel multiplier specified\n");
        case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
        case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
        case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -2194,6 +2194,7 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_sdvo_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
index 0a52c44ad03d6b21078fe7482ddc3b84813ac9c4..e9ff6fc6126726a24bdf19e4f0f5b50adab8c0d5 100644 (file)
@@ -98,7 +98,7 @@ bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
        if (min <= 0 || max <= 0)
                return false;
 
-       if (WARN_ON(drm_vblank_get(dev, pipe)))
+       if (WARN_ON(drm_crtc_vblank_get(&crtc->base)))
                return false;
 
        local_irq_disable();
@@ -132,7 +132,7 @@ bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
 
        finish_wait(wq, &wait);
 
-       drm_vblank_put(dev, pipe);
+       drm_crtc_vblank_put(&crtc->base);
 
        *start_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
 
@@ -179,7 +179,7 @@ static void intel_update_primary_plane(struct intel_crtc *crtc)
 static void
 skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
                 struct drm_framebuffer *fb,
-                struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
+                int crtc_x, int crtc_y,
                 unsigned int crtc_w, unsigned int crtc_h,
                 uint32_t x, uint32_t y,
                 uint32_t src_w, uint32_t src_h)
@@ -187,23 +187,16 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
        struct drm_device *dev = drm_plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_plane *intel_plane = to_intel_plane(drm_plane);
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        const int pipe = intel_plane->pipe;
        const int plane = intel_plane->plane + 1;
-       u32 plane_ctl, stride;
+       u32 plane_ctl, stride_div;
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey;
+       unsigned long surf_addr;
 
-       plane_ctl = I915_READ(PLANE_CTL(pipe, plane));
-
-       /* Mask out pixel format bits in case we change it */
-       plane_ctl &= ~PLANE_CTL_FORMAT_MASK;
-       plane_ctl &= ~PLANE_CTL_ORDER_RGBX;
-       plane_ctl &= ~PLANE_CTL_YUV422_ORDER_MASK;
-       plane_ctl &= ~PLANE_CTL_TILED_MASK;
-       plane_ctl &= ~PLANE_CTL_ALPHA_MASK;
-       plane_ctl &= ~PLANE_CTL_ROTATE_MASK;
-
-       /* Trickle feed has to be enabled */
-       plane_ctl &= ~PLANE_CTL_TRICKLE_FEED_DISABLE;
+       plane_ctl = PLANE_CTL_ENABLE |
+               PLANE_CTL_PIPE_CSC_ENABLE;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_RGB565:
@@ -245,39 +238,57 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
                BUG();
        }
 
-       switch (obj->tiling_mode) {
-       case I915_TILING_NONE:
-               stride = fb->pitches[0] >> 6;
+       switch (fb->modifier[0]) {
+       case DRM_FORMAT_MOD_NONE:
                break;
-       case I915_TILING_X:
+       case I915_FORMAT_MOD_X_TILED:
                plane_ctl |= PLANE_CTL_TILED_X;
-               stride = fb->pitches[0] >> 9;
+               break;
+       case I915_FORMAT_MOD_Y_TILED:
+               plane_ctl |= PLANE_CTL_TILED_Y;
+               break;
+       case I915_FORMAT_MOD_Yf_TILED:
+               plane_ctl |= PLANE_CTL_TILED_YF;
                break;
        default:
-               BUG();
+               MISSING_CASE(fb->modifier[0]);
        }
+
        if (drm_plane->state->rotation == BIT(DRM_ROTATE_180))
                plane_ctl |= PLANE_CTL_ROTATE_180;
 
-       plane_ctl |= PLANE_CTL_ENABLE;
-       plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE;
-
        intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h,
                                       pixel_size, true,
                                       src_w != crtc_w || src_h != crtc_h);
 
+       stride_div = intel_fb_stride_alignment(dev, fb->modifier[0],
+                                              fb->pixel_format);
+
        /* Sizes are 0 based */
        src_w--;
        src_h--;
        crtc_w--;
        crtc_h--;
 
+       if (key->flags) {
+               I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
+               I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
+               I915_WRITE(PLANE_KEYMSK(pipe, plane), key->channel_mask);
+       }
+
+       if (key->flags & I915_SET_COLORKEY_DESTINATION)
+               plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION;
+       else if (key->flags & I915_SET_COLORKEY_SOURCE)
+               plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
+
+       surf_addr = intel_plane_obj_offset(intel_plane, obj);
+
        I915_WRITE(PLANE_OFFSET(pipe, plane), (y << 16) | x);
-       I915_WRITE(PLANE_STRIDE(pipe, plane), stride);
+       I915_WRITE(PLANE_STRIDE(pipe, plane), fb->pitches[0] / stride_div);
        I915_WRITE(PLANE_POS(pipe, plane), (crtc_y << 16) | crtc_x);
        I915_WRITE(PLANE_SIZE(pipe, plane), (crtc_h << 16) | crtc_w);
        I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
-       I915_WRITE(PLANE_SURF(pipe, plane), i915_gem_obj_ggtt_offset(obj));
+       I915_WRITE(PLANE_SURF(pipe, plane), surf_addr);
        POSTING_READ(PLANE_SURF(pipe, plane));
 }
 
@@ -290,73 +301,15 @@ skl_disable_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc)
        const int pipe = intel_plane->pipe;
        const int plane = intel_plane->plane + 1;
 
-       I915_WRITE(PLANE_CTL(pipe, plane),
-                  I915_READ(PLANE_CTL(pipe, plane)) & ~PLANE_CTL_ENABLE);
+       I915_WRITE(PLANE_CTL(pipe, plane), 0);
 
        /* Activate double buffered register update */
-       I915_WRITE(PLANE_CTL(pipe, plane), 0);
-       POSTING_READ(PLANE_CTL(pipe, plane));
+       I915_WRITE(PLANE_SURF(pipe, plane), 0);
+       POSTING_READ(PLANE_SURF(pipe, plane));
 
        intel_update_sprite_watermarks(drm_plane, crtc, 0, 0, 0, false, false);
 }
 
-static int
-skl_update_colorkey(struct drm_plane *drm_plane,
-                   struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = drm_plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane = to_intel_plane(drm_plane);
-       const int pipe = intel_plane->pipe;
-       const int plane = intel_plane->plane;
-       u32 plane_ctl;
-
-       I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
-       I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
-       I915_WRITE(PLANE_KEYMSK(pipe, plane), key->channel_mask);
-
-       plane_ctl = I915_READ(PLANE_CTL(pipe, plane));
-       plane_ctl &= ~PLANE_CTL_KEY_ENABLE_MASK;
-       if (key->flags & I915_SET_COLORKEY_DESTINATION)
-               plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION;
-       else if (key->flags & I915_SET_COLORKEY_SOURCE)
-               plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
-       I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
-
-       POSTING_READ(PLANE_CTL(pipe, plane));
-
-       return 0;
-}
-
-static void
-skl_get_colorkey(struct drm_plane *drm_plane,
-                struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = drm_plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane = to_intel_plane(drm_plane);
-       const int pipe = intel_plane->pipe;
-       const int plane = intel_plane->plane;
-       u32 plane_ctl;
-
-       key->min_value = I915_READ(PLANE_KEYVAL(pipe, plane));
-       key->max_value = I915_READ(PLANE_KEYMAX(pipe, plane));
-       key->channel_mask = I915_READ(PLANE_KEYMSK(pipe, plane));
-
-       plane_ctl = I915_READ(PLANE_CTL(pipe, plane));
-
-       switch (plane_ctl & PLANE_CTL_KEY_ENABLE_MASK) {
-       case PLANE_CTL_KEY_ENABLE_DESTINATION:
-               key->flags = I915_SET_COLORKEY_DESTINATION;
-               break;
-       case PLANE_CTL_KEY_ENABLE_SOURCE:
-               key->flags = I915_SET_COLORKEY_SOURCE;
-               break;
-       default:
-               key->flags = I915_SET_COLORKEY_NONE;
-       }
-}
-
 static void
 chv_update_csc(struct intel_plane *intel_plane, uint32_t format)
 {
@@ -399,7 +352,7 @@ chv_update_csc(struct intel_plane *intel_plane, uint32_t format)
 static void
 vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
                 struct drm_framebuffer *fb,
-                struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
+                int crtc_x, int crtc_y,
                 unsigned int crtc_w, unsigned int crtc_h,
                 uint32_t x, uint32_t y,
                 uint32_t src_w, uint32_t src_h)
@@ -408,19 +361,15 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_plane *intel_plane = to_intel_plane(dplane);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int pipe = intel_plane->pipe;
        int plane = intel_plane->plane;
        u32 sprctl;
        unsigned long sprsurf_offset, linear_offset;
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey;
 
-       sprctl = I915_READ(SPCNTR(pipe, plane));
-
-       /* Mask out pixel format bits in case we change it */
-       sprctl &= ~SP_PIXFORMAT_MASK;
-       sprctl &= ~SP_YUV_BYTE_ORDER_MASK;
-       sprctl &= ~SP_TILED;
-       sprctl &= ~SP_ROTATE_180;
+       sprctl = SP_ENABLE;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_YUYV:
@@ -474,8 +423,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
        if (obj->tiling_mode != I915_TILING_NONE)
                sprctl |= SP_TILED;
 
-       sprctl |= SP_ENABLE;
-
        intel_update_sprite_watermarks(dplane, crtc, src_w, src_h,
                                       pixel_size, true,
                                       src_w != crtc_w || src_h != crtc_h);
@@ -503,6 +450,15 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 
        intel_update_primary_plane(intel_crtc);
 
+       if (key->flags) {
+               I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value);
+               I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value);
+               I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask);
+       }
+
+       if (key->flags & I915_SET_COLORKEY_SOURCE)
+               sprctl |= SP_SOURCE_KEY;
+
        if (IS_CHERRYVIEW(dev) && pipe == PIPE_B)
                chv_update_csc(intel_plane, fb->pixel_format);
 
@@ -536,8 +492,8 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
 
        intel_update_primary_plane(intel_crtc);
 
-       I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) &
-                  ~SP_ENABLE);
+       I915_WRITE(SPCNTR(pipe, plane), 0);
+
        /* Activate double buffered register update */
        I915_WRITE(SPSURF(pipe, plane), 0);
 
@@ -546,61 +502,11 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
        intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false);
 }
 
-static int
-vlv_update_colorkey(struct drm_plane *dplane,
-                   struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = dplane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane = to_intel_plane(dplane);
-       int pipe = intel_plane->pipe;
-       int plane = intel_plane->plane;
-       u32 sprctl;
-
-       if (key->flags & I915_SET_COLORKEY_DESTINATION)
-               return -EINVAL;
-
-       I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value);
-       I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value);
-       I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask);
-
-       sprctl = I915_READ(SPCNTR(pipe, plane));
-       sprctl &= ~SP_SOURCE_KEY;
-       if (key->flags & I915_SET_COLORKEY_SOURCE)
-               sprctl |= SP_SOURCE_KEY;
-       I915_WRITE(SPCNTR(pipe, plane), sprctl);
-
-       POSTING_READ(SPKEYMSK(pipe, plane));
-
-       return 0;
-}
-
-static void
-vlv_get_colorkey(struct drm_plane *dplane,
-                struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = dplane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane = to_intel_plane(dplane);
-       int pipe = intel_plane->pipe;
-       int plane = intel_plane->plane;
-       u32 sprctl;
-
-       key->min_value = I915_READ(SPKEYMINVAL(pipe, plane));
-       key->max_value = I915_READ(SPKEYMAXVAL(pipe, plane));
-       key->channel_mask = I915_READ(SPKEYMSK(pipe, plane));
-
-       sprctl = I915_READ(SPCNTR(pipe, plane));
-       if (sprctl & SP_SOURCE_KEY)
-               key->flags = I915_SET_COLORKEY_SOURCE;
-       else
-               key->flags = I915_SET_COLORKEY_NONE;
-}
 
 static void
 ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                 struct drm_framebuffer *fb,
-                struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
+                int crtc_x, int crtc_y,
                 unsigned int crtc_w, unsigned int crtc_h,
                 uint32_t x, uint32_t y,
                 uint32_t src_w, uint32_t src_h)
@@ -609,19 +515,14 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_plane->pipe;
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       enum pipe pipe = intel_plane->pipe;
        u32 sprctl, sprscale = 0;
        unsigned long sprsurf_offset, linear_offset;
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey;
 
-       sprctl = I915_READ(SPRCTL(pipe));
-
-       /* Mask out pixel format bits in case we change it */
-       sprctl &= ~SPRITE_PIXFORMAT_MASK;
-       sprctl &= ~SPRITE_RGB_ORDER_RGBX;
-       sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
-       sprctl &= ~SPRITE_TILED;
-       sprctl &= ~SPRITE_ROTATE_180;
+       sprctl = SPRITE_ENABLE;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_XBGR8888:
@@ -660,8 +561,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        else
                sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
 
-       sprctl |= SPRITE_ENABLE;
-
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                sprctl |= SPRITE_PIPE_CSC_ENABLE;
 
@@ -698,6 +597,17 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
        intel_update_primary_plane(intel_crtc);
 
+       if (key->flags) {
+               I915_WRITE(SPRKEYVAL(pipe), key->min_value);
+               I915_WRITE(SPRKEYMAX(pipe), key->max_value);
+               I915_WRITE(SPRKEYMSK(pipe), key->channel_mask);
+       }
+
+       if (key->flags & I915_SET_COLORKEY_DESTINATION)
+               sprctl |= SPRITE_DEST_KEY;
+       else if (key->flags & I915_SET_COLORKEY_SOURCE)
+               sprctl |= SPRITE_SOURCE_KEY;
+
        I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
 
@@ -739,73 +649,12 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
        I915_WRITE(SPRSURF(pipe), 0);
 
        intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
-       /*
-        * Avoid underruns when disabling the sprite.
-        * FIXME remove once watermark updates are done properly.
-        */
-       intel_crtc->atomic.wait_vblank = true;
-       intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
-}
-
-static int
-ivb_update_colorkey(struct drm_plane *plane,
-                   struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane;
-       u32 sprctl;
-       int ret = 0;
-
-       intel_plane = to_intel_plane(plane);
-
-       I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value);
-       I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value);
-       I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask);
-
-       sprctl = I915_READ(SPRCTL(intel_plane->pipe));
-       sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
-       if (key->flags & I915_SET_COLORKEY_DESTINATION)
-               sprctl |= SPRITE_DEST_KEY;
-       else if (key->flags & I915_SET_COLORKEY_SOURCE)
-               sprctl |= SPRITE_SOURCE_KEY;
-       I915_WRITE(SPRCTL(intel_plane->pipe), sprctl);
-
-       POSTING_READ(SPRKEYMSK(intel_plane->pipe));
-
-       return ret;
-}
-
-static void
-ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane;
-       u32 sprctl;
-
-       intel_plane = to_intel_plane(plane);
-
-       key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe));
-       key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe));
-       key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe));
-       key->flags = 0;
-
-       sprctl = I915_READ(SPRCTL(intel_plane->pipe));
-
-       if (sprctl & SPRITE_DEST_KEY)
-               key->flags = I915_SET_COLORKEY_DESTINATION;
-       else if (sprctl & SPRITE_SOURCE_KEY)
-               key->flags = I915_SET_COLORKEY_SOURCE;
-       else
-               key->flags = I915_SET_COLORKEY_NONE;
 }
 
 static void
 ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                 struct drm_framebuffer *fb,
-                struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
+                int crtc_x, int crtc_y,
                 unsigned int crtc_w, unsigned int crtc_h,
                 uint32_t x, uint32_t y,
                 uint32_t src_w, uint32_t src_h)
@@ -814,19 +663,14 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int pipe = intel_plane->pipe;
        unsigned long dvssurf_offset, linear_offset;
        u32 dvscntr, dvsscale;
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey;
 
-       dvscntr = I915_READ(DVSCNTR(pipe));
-
-       /* Mask out pixel format bits in case we change it */
-       dvscntr &= ~DVS_PIXFORMAT_MASK;
-       dvscntr &= ~DVS_RGB_ORDER_XBGR;
-       dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
-       dvscntr &= ~DVS_TILED;
-       dvscntr &= ~DVS_ROTATE_180;
+       dvscntr = DVS_ENABLE;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_XBGR8888:
@@ -862,7 +706,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
        if (IS_GEN6(dev))
                dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
-       dvscntr |= DVS_ENABLE;
 
        intel_update_sprite_watermarks(plane, crtc, src_w, src_h,
                                       pixel_size, true,
@@ -894,6 +737,17 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
        intel_update_primary_plane(intel_crtc);
 
+       if (key->flags) {
+               I915_WRITE(DVSKEYVAL(pipe), key->min_value);
+               I915_WRITE(DVSKEYMAX(pipe), key->max_value);
+               I915_WRITE(DVSKEYMSK(pipe), key->channel_mask);
+       }
+
+       if (key->flags & I915_SET_COLORKEY_DESTINATION)
+               dvscntr |= DVS_DEST_KEY;
+       else if (key->flags & I915_SET_COLORKEY_SOURCE)
+               dvscntr |= DVS_SOURCE_KEY;
+
        I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
 
@@ -922,20 +776,14 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
 
        intel_update_primary_plane(intel_crtc);
 
-       I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
+       I915_WRITE(DVSCNTR(pipe), 0);
        /* Disable the scaler */
        I915_WRITE(DVSSCALE(pipe), 0);
+
        /* Flush double buffered register updates */
        I915_WRITE(DVSSURF(pipe), 0);
 
        intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
-       /*
-        * Avoid underruns when disabling the sprite.
-        * FIXME remove once watermark updates are done properly.
-        */
-       intel_crtc->atomic.wait_vblank = true;
-       intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
 }
 
 /**
@@ -993,7 +841,7 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
        mutex_lock(&dev->struct_mutex);
-       if (dev_priv->fbc.plane == intel_crtc->plane)
+       if (dev_priv->fbc.crtc == intel_crtc)
                intel_fbc_disable(dev);
        mutex_unlock(&dev->struct_mutex);
 
@@ -1006,67 +854,9 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
        hsw_disable_ips(intel_crtc);
 }
 
-static int
-ilk_update_colorkey(struct drm_plane *plane,
-                   struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane;
-       u32 dvscntr;
-       int ret = 0;
-
-       intel_plane = to_intel_plane(plane);
-
-       I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value);
-       I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value);
-       I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask);
-
-       dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
-       dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
-       if (key->flags & I915_SET_COLORKEY_DESTINATION)
-               dvscntr |= DVS_DEST_KEY;
-       else if (key->flags & I915_SET_COLORKEY_SOURCE)
-               dvscntr |= DVS_SOURCE_KEY;
-       I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr);
-
-       POSTING_READ(DVSKEYMSK(intel_plane->pipe));
-
-       return ret;
-}
-
-static void
-ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
-{
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane;
-       u32 dvscntr;
-
-       intel_plane = to_intel_plane(plane);
-
-       key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe));
-       key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe));
-       key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe));
-       key->flags = 0;
-
-       dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
-
-       if (dvscntr & DVS_DEST_KEY)
-               key->flags = I915_SET_COLORKEY_DESTINATION;
-       else if (dvscntr & DVS_SOURCE_KEY)
-               key->flags = I915_SET_COLORKEY_SOURCE;
-       else
-               key->flags = I915_SET_COLORKEY_NONE;
-}
-
 static bool colorkey_enabled(struct intel_plane *intel_plane)
 {
-       struct drm_intel_sprite_colorkey key;
-
-       intel_plane->get_colorkey(&intel_plane->base, &key);
-
-       return key.flags != I915_SET_COLORKEY_NONE;
+       return intel_plane->ckey.flags != I915_SET_COLORKEY_NONE;
 }
 
 static int
@@ -1076,7 +866,6 @@ intel_check_sprite_plane(struct drm_plane *plane,
        struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc);
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *fb = state->base.fb;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int crtc_x, crtc_y;
        unsigned int crtc_w, crtc_h;
        uint32_t src_x, src_y, src_w, src_h;
@@ -1106,16 +895,6 @@ intel_check_sprite_plane(struct drm_plane *plane,
                return -EINVAL;
        }
 
-       /* Sprite planes can be linear or x-tiled surfaces */
-       switch (obj->tiling_mode) {
-               case I915_TILING_NONE:
-               case I915_TILING_X:
-                       break;
-               default:
-                       DRM_DEBUG_KMS("Unsupported tiling mode\n");
-                       return -EINVAL;
-       }
-
        /*
         * FIXME the following code does a bunch of fuzzy adjustments to the
         * coordinates and sizes. We probably need some way to decide whether
@@ -1259,6 +1038,19 @@ finish:
 
                if (!intel_crtc->primary_enabled && !state->hides_primary)
                        intel_crtc->atomic.post_enable_primary = true;
+
+               if (intel_wm_need_update(plane, &state->base))
+                       intel_crtc->atomic.update_wm = true;
+
+               if (!state->visible) {
+                       /*
+                        * Avoid underruns when disabling the sprite.
+                        * FIXME remove once watermark updates are done properly.
+                        */
+                       intel_crtc->atomic.wait_vblank = true;
+                       intel_crtc->atomic.update_sprite_watermarks |=
+                               (1 << drm_plane_index(plane));
+               }
        }
 
        return 0;
@@ -1272,7 +1064,6 @@ intel_commit_sprite_plane(struct drm_plane *plane,
        struct intel_crtc *intel_crtc;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *fb = state->base.fb;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int crtc_x, crtc_y;
        unsigned int crtc_w, crtc_h;
        uint32_t src_x, src_y, src_w, src_h;
@@ -1280,8 +1071,7 @@ intel_commit_sprite_plane(struct drm_plane *plane,
        crtc = crtc ? crtc : plane->crtc;
        intel_crtc = to_intel_crtc(crtc);
 
-       plane->fb = state->base.fb;
-       intel_plane->obj = obj;
+       plane->fb = fb;
 
        if (intel_crtc->active) {
                intel_crtc->primary_enabled = !state->hides_primary;
@@ -1295,7 +1085,7 @@ intel_commit_sprite_plane(struct drm_plane *plane,
                        src_y = state->src.y1;
                        src_w = drm_rect_width(&state->src);
                        src_h = drm_rect_height(&state->src);
-                       intel_plane->update_plane(plane, crtc, fb, obj,
+                       intel_plane->update_plane(plane, crtc, fb,
                                                  crtc_x, crtc_y, crtc_w, crtc_h,
                                                  src_x, src_y, src_w, src_h);
                } else {
@@ -1312,13 +1102,14 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
        struct intel_plane *intel_plane;
        int ret = 0;
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -ENODEV;
-
        /* Make sure we don't try to enable both src & dest simultaneously */
        if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
                return -EINVAL;
 
+       if (IS_VALLEYVIEW(dev) &&
+           set->flags & I915_SET_COLORKEY_DESTINATION)
+               return -EINVAL;
+
        drm_modeset_lock_all(dev);
 
        plane = drm_plane_find(dev, set->plane_id);
@@ -1328,34 +1119,15 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
        }
 
        intel_plane = to_intel_plane(plane);
-       ret = intel_plane->update_colorkey(plane, set);
-
-out_unlock:
-       drm_modeset_unlock_all(dev);
-       return ret;
-}
-
-int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
-                             struct drm_file *file_priv)
-{
-       struct drm_intel_sprite_colorkey *get = data;
-       struct drm_plane *plane;
-       struct intel_plane *intel_plane;
-       int ret = 0;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -ENODEV;
-
-       drm_modeset_lock_all(dev);
-
-       plane = drm_plane_find(dev, get->plane_id);
-       if (!plane) {
-               ret = -ENOENT;
-               goto out_unlock;
-       }
+       intel_plane->ckey = *set;
 
-       intel_plane = to_intel_plane(plane);
-       intel_plane->get_colorkey(plane, get);
+       /*
+        * The only way this could fail would be due to
+        * the current plane state being unsupportable already,
+        * and we dont't consider that an error for the
+        * colorkey ioctl. So just ignore any error.
+        */
+       intel_plane_restore(plane);
 
 out_unlock:
        drm_modeset_unlock_all(dev);
@@ -1364,10 +1136,10 @@ out_unlock:
 
 int intel_plane_restore(struct drm_plane *plane)
 {
-       if (!plane->crtc || !plane->fb)
+       if (!plane->crtc || !plane->state->fb)
                return 0;
 
-       return plane->funcs->update_plane(plane, plane->crtc, plane->fb,
+       return plane->funcs->update_plane(plane, plane->crtc, plane->state->fb,
                                  plane->state->crtc_x, plane->state->crtc_y,
                                  plane->state->crtc_w, plane->state->crtc_h,
                                  plane->state->src_x, plane->state->src_y,
@@ -1448,8 +1220,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
                intel_plane->max_downscale = 16;
                intel_plane->update_plane = ilk_update_plane;
                intel_plane->disable_plane = ilk_disable_plane;
-               intel_plane->update_colorkey = ilk_update_colorkey;
-               intel_plane->get_colorkey = ilk_get_colorkey;
 
                if (IS_GEN6(dev)) {
                        plane_formats = snb_plane_formats;
@@ -1473,16 +1243,12 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
                if (IS_VALLEYVIEW(dev)) {
                        intel_plane->update_plane = vlv_update_plane;
                        intel_plane->disable_plane = vlv_disable_plane;
-                       intel_plane->update_colorkey = vlv_update_colorkey;
-                       intel_plane->get_colorkey = vlv_get_colorkey;
 
                        plane_formats = vlv_plane_formats;
                        num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
                } else {
                        intel_plane->update_plane = ivb_update_plane;
                        intel_plane->disable_plane = ivb_disable_plane;
-                       intel_plane->update_colorkey = ivb_update_colorkey;
-                       intel_plane->get_colorkey = ivb_get_colorkey;
 
                        plane_formats = snb_plane_formats;
                        num_plane_formats = ARRAY_SIZE(snb_plane_formats);
@@ -1497,8 +1263,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
                intel_plane->max_downscale = 1;
                intel_plane->update_plane = skl_update_plane;
                intel_plane->disable_plane = skl_disable_plane;
-               intel_plane->update_colorkey = skl_update_colorkey;
-               intel_plane->get_colorkey = skl_get_colorkey;
 
                plane_formats = skl_plane_formats;
                num_plane_formats = ARRAY_SIZE(skl_plane_formats);
index 892d23c8479d30f7b6c283ba962c60220f68e3b0..bc1d9d74090411acfedacd5df725f80be75a151b 100644 (file)
@@ -1332,7 +1332,7 @@ intel_tv_detect(struct drm_connector *connector, bool force)
 
                if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) {
                        type = intel_tv_detect_type(intel_tv, connector);
-                       intel_release_load_detect_pipe(connector, &tmp);
+                       intel_release_load_detect_pipe(connector, &tmp, &ctx);
                        status = type < 0 ?
                                connector_status_disconnected :
                                connector_status_connected;
@@ -1516,6 +1516,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
        .atomic_get_property = intel_connector_atomic_get_property,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
 
 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
index c47a3baa53d5963cdfc1663320ac2e88398f276d..ab5cc94588e10d1ac1ac81e3330073ea92d17ac7 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "i915_drv.h"
 #include "intel_drv.h"
+#include "i915_vgpu.h"
 
 #include <linux/pm_runtime.h>
 
@@ -210,6 +211,13 @@ static void fw_domains_put_with_fifo(struct drm_i915_private *dev_priv,
        gen6_gt_check_fifodbg(dev_priv);
 }
 
+static inline u32 fifo_free_entries(struct drm_i915_private *dev_priv)
+{
+       u32 count = __raw_i915_read32(dev_priv, GTFIFOCTL);
+
+       return count & GT_FIFO_FREE_ENTRIES_MASK;
+}
+
 static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
 {
        int ret = 0;
@@ -217,16 +225,15 @@ static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
        /* On VLV, FIFO will be shared by both SW and HW.
         * So, we need to read the FREE_ENTRIES everytime */
        if (IS_VALLEYVIEW(dev_priv->dev))
-               dev_priv->uncore.fifo_count =
-                       __raw_i915_read32(dev_priv, GTFIFOCTL) &
-                                               GT_FIFO_FREE_ENTRIES_MASK;
+               dev_priv->uncore.fifo_count = fifo_free_entries(dev_priv);
 
        if (dev_priv->uncore.fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) {
                int loop = 500;
-               u32 fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK;
+               u32 fifo = fifo_free_entries(dev_priv);
+
                while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) {
                        udelay(10);
-                       fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK;
+                       fifo = fifo_free_entries(dev_priv);
                }
                if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES))
                        ++ret;
@@ -314,8 +321,7 @@ void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore)
 
                if (IS_GEN6(dev) || IS_GEN7(dev))
                        dev_priv->uncore.fifo_count =
-                               __raw_i915_read32(dev_priv, GTFIFOCTL) &
-                               GT_FIFO_FREE_ENTRIES_MASK;
+                               fifo_free_entries(dev_priv);
        }
 
        if (!restore)
@@ -328,8 +334,9 @@ static void intel_uncore_ellc_detect(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) &&
-           (__raw_i915_read32(dev_priv, HSW_EDRAM_PRESENT) == 1)) {
+       if ((IS_HASWELL(dev) || IS_BROADWELL(dev) ||
+            INTEL_INFO(dev)->gen >= 9) &&
+           (__raw_i915_read32(dev_priv, HSW_EDRAM_PRESENT) & EDRAM_ENABLED)) {
                /* The docs do not explain exactly how the calculation can be
                 * made. It is somewhat guessable, but for now, it's always
                 * 128MB.
@@ -550,18 +557,24 @@ hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv, u32 reg, bool read,
                WARN(1, "Unclaimed register detected %s %s register 0x%x\n",
                     when, op, reg);
                __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+               i915.mmio_debug--; /* Only report the first N failures */
        }
 }
 
 static void
 hsw_unclaimed_reg_detect(struct drm_i915_private *dev_priv)
 {
-       if (i915.mmio_debug)
+       static bool mmio_debug_once = true;
+
+       if (i915.mmio_debug || !mmio_debug_once)
                return;
 
        if (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM) {
-               DRM_ERROR("Unclaimed register detected. Please use the i915.mmio_debug=1 to debug this problem.");
+               DRM_DEBUG("Unclaimed register detected, "
+                         "enabling oneshot unclaimed register reporting. "
+                         "Please use i915.mmio_debug=N for more information.\n");
                __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+               i915.mmio_debug = mmio_debug_once--;
        }
 }
 
@@ -640,6 +653,14 @@ static inline void __force_wake_get(struct drm_i915_private *dev_priv,
                dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains);
 }
 
+#define __vgpu_read(x) \
+static u##x \
+vgpu_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+       GEN6_READ_HEADER(x); \
+       val = __raw_i915_read##x(dev_priv, reg); \
+       GEN6_READ_FOOTER; \
+}
+
 #define __gen6_read(x) \
 static u##x \
 gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
@@ -703,6 +724,10 @@ gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
        GEN6_READ_FOOTER; \
 }
 
+__vgpu_read(8)
+__vgpu_read(16)
+__vgpu_read(32)
+__vgpu_read(64)
 __gen9_read(8)
 __gen9_read(16)
 __gen9_read(32)
@@ -724,6 +749,7 @@ __gen6_read(64)
 #undef __chv_read
 #undef __vlv_read
 #undef __gen6_read
+#undef __vgpu_read
 #undef GEN6_READ_FOOTER
 #undef GEN6_READ_HEADER
 
@@ -807,6 +833,14 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace)
        GEN6_WRITE_FOOTER; \
 }
 
+#define __vgpu_write(x) \
+static void vgpu_write##x(struct drm_i915_private *dev_priv, \
+                         off_t reg, u##x val, bool trace) { \
+       GEN6_WRITE_HEADER; \
+       __raw_i915_write##x(dev_priv, reg, val); \
+       GEN6_WRITE_FOOTER; \
+}
+
 static const u32 gen8_shadowed_regs[] = {
        FORCEWAKE_MT,
        GEN6_RPNSWREQ,
@@ -924,12 +958,17 @@ __gen6_write(8)
 __gen6_write(16)
 __gen6_write(32)
 __gen6_write(64)
+__vgpu_write(8)
+__vgpu_write(16)
+__vgpu_write(32)
+__vgpu_write(64)
 
 #undef __gen9_write
 #undef __chv_write
 #undef __gen8_write
 #undef __hsw_write
 #undef __gen6_write
+#undef __vgpu_write
 #undef GEN6_WRITE_FOOTER
 #undef GEN6_WRITE_HEADER
 
@@ -972,6 +1011,7 @@ static void fw_domain_init(struct drm_i915_private *dev_priv,
                d->val_set = FORCEWAKE_KERNEL;
                d->val_clear = 0;
        } else {
+               /* WaRsClearFWBitsAtReset:bdw,skl */
                d->val_reset = _MASKED_BIT_DISABLE(0xffff);
                d->val_set = _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL);
                d->val_clear = _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL);
@@ -1048,8 +1088,14 @@ static void intel_uncore_fw_domains_init(struct drm_device *dev)
 
                /* We need to init first for ECOBUS access and then
                 * determine later if we want to reinit, in case of MT access is
-                * not working
+                * not working. In this stage we don't know which flavour this
+                * ivb is, so it is better to reset also the gen6 fw registers
+                * before the ecobus check.
                 */
+
+               __raw_i915_write32(dev_priv, FORCEWAKE, 0);
+               __raw_posting_read(dev_priv, ECOBUS);
+
                fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
                               FORCEWAKE_MT, FORCEWAKE_MT_ACK);
 
@@ -1082,6 +1128,8 @@ void intel_uncore_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       i915_check_vgpu(dev);
+
        intel_uncore_ellc_detect(dev);
        intel_uncore_fw_domains_init(dev);
        __intel_uncore_early_sanitize(dev, false);
@@ -1130,6 +1178,11 @@ void intel_uncore_init(struct drm_device *dev)
                break;
        }
 
+       if (intel_vgpu_active(dev)) {
+               ASSIGN_WRITE_MMIO_VFUNCS(vgpu);
+               ASSIGN_READ_MMIO_VFUNCS(vgpu);
+       }
+
        i915_check_and_clear_faults(dev);
 }
 #undef ASSIGN_WRITE_MMIO_VFUNCS
index 121d30ca2d4448f379c743ac781bb9910ccd2d44..87fe8ed92ebeb8bf996fb95b79731dbebdbed2dd 100644 (file)
@@ -70,7 +70,9 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
                118800000, { 0x091c, 0x091c, 0x06dc },
        }, {
                216000000, { 0x06dc, 0x0b5c, 0x091c },
-       }
+       }, {
+               ~0UL, { 0x0000, 0x0000, 0x0000 },
+       },
 };
 
 static const struct dw_hdmi_sym_term imx_sym_term[] = {
@@ -136,11 +138,34 @@ static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = {
        .destroy = drm_encoder_cleanup,
 };
 
+static enum drm_mode_status imx6q_hdmi_mode_valid(struct drm_connector *con,
+                                                 struct drm_display_mode *mode)
+{
+       if (mode->clock < 13500)
+               return MODE_CLOCK_LOW;
+       if (mode->clock > 266000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con,
+                                                  struct drm_display_mode *mode)
+{
+       if (mode->clock < 13500)
+               return MODE_CLOCK_LOW;
+       if (mode->clock > 270000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
 static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
-       .mpll_cfg = imx_mpll_cfg,
-       .cur_ctr  = imx_cur_ctr,
-       .sym_term = imx_sym_term,
-       .dev_type = IMX6Q_HDMI,
+       .mpll_cfg   = imx_mpll_cfg,
+       .cur_ctr    = imx_cur_ctr,
+       .sym_term   = imx_sym_term,
+       .dev_type   = IMX6Q_HDMI,
+       .mode_valid = imx6q_hdmi_mode_valid,
 };
 
 static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
@@ -148,6 +173,7 @@ static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
        .cur_ctr  = imx_cur_ctr,
        .sym_term = imx_sym_term,
        .dev_type = IMX6DL_HDMI,
+       .mode_valid = imx6dl_hdmi_mode_valid,
 };
 
 static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
index 1b86aac0b341c7083b15e03163338989a1543592..2d6dc94e1e64e973f61a1294c24bba6d2d788ae2 100644 (file)
@@ -163,22 +163,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
 {
        struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
        struct imx_ldb *ldb = imx_ldb_ch->ldb;
-       struct drm_display_mode *mode = &encoder->crtc->hwmode;
        u32 pixel_fmt;
-       unsigned long serial_clk;
-       unsigned long di_clk = mode->clock * 1000;
-       int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
-
-       if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
-               /* dual channel LVDS mode */
-               serial_clk = 3500UL * mode->clock;
-               imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
-               imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
-       } else {
-               serial_clk = 7000UL * mode->clock;
-               imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
-                               di_clk);
-       }
 
        switch (imx_ldb_ch->chno) {
        case 0:
@@ -247,6 +232,9 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
        struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
        struct imx_ldb *ldb = imx_ldb_ch->ldb;
        int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
+       unsigned long serial_clk;
+       unsigned long di_clk = mode->clock * 1000;
+       int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
 
        if (mode->clock > 170000) {
                dev_warn(ldb->dev,
@@ -257,6 +245,16 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
                         "%s: mode exceeds 85 MHz pixel clock\n", __func__);
        }
 
+       if (dual) {
+               serial_clk = 3500UL * mode->clock;
+               imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
+               imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
+       } else {
+               serial_clk = 7000UL * mode->clock;
+               imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
+                                 di_clk);
+       }
+
        /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
        if (imx_ldb_ch == &ldb->channel[0]) {
                if (mode->flags & DRM_MODE_FLAG_NVSYNC)
index 5e83e007080f7ae757b3f6c567cd791a595bd9d1..900dda6a8e71b5501293b8d4be06ddb8288dee27 100644 (file)
@@ -236,8 +236,11 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
        }
 
        panel_node = of_parse_phandle(np, "fsl,panel", 0);
-       if (panel_node)
+       if (panel_node) {
                imxpd->panel = of_drm_find_panel(panel_node);
+               if (!imxpd->panel)
+                       return -EPROBE_DEFER;
+       }
 
        imxpd->dev = dev;
 
index 8edd531cb62166ad1291be18ffc26ba033cbc71d..7369ee7f0c5544a6c44b9850e4ded92217da2596 100644 (file)
@@ -32,7 +32,10 @@ static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
 void mdp4_irq_preinstall(struct msm_kms *kms)
 {
        struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       mdp4_enable(mdp4_kms);
        mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, 0xffffffff);
+       mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
+       mdp4_disable(mdp4_kms);
 }
 
 int mdp4_irq_postinstall(struct msm_kms *kms)
@@ -53,7 +56,9 @@ int mdp4_irq_postinstall(struct msm_kms *kms)
 void mdp4_irq_uninstall(struct msm_kms *kms)
 {
        struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       mdp4_enable(mdp4_kms);
        mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
+       mdp4_disable(mdp4_kms);
 }
 
 irqreturn_t mdp4_irq(struct msm_kms *kms)
index cde25009203aa56e015da468a2c4a1b22bd43535..dbc068988377fee6a274ec4b623cc8ffaeddbb3e 100644 (file)
@@ -83,7 +83,8 @@ static const struct drm_plane_funcs mdp4_plane_funcs = {
 };
 
 static int mdp4_plane_prepare_fb(struct drm_plane *plane,
-               struct drm_framebuffer *fb)
+               struct drm_framebuffer *fb,
+               const struct drm_plane_state *new_state)
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
        struct mdp4_kms *mdp4_kms = get_kms(plane);
@@ -93,7 +94,8 @@ static int mdp4_plane_prepare_fb(struct drm_plane *plane,
 }
 
 static void mdp4_plane_cleanup_fb(struct drm_plane *plane,
-               struct drm_framebuffer *fb)
+               struct drm_framebuffer *fb,
+               const struct drm_plane_state *old_state)
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
        struct mdp4_kms *mdp4_kms = get_kms(plane);
index 09b4a25eb553fa9cad7f68ad8a61afa13a8d90a0..c276624290afedb3f8de9fe9db2ed9271cab5ff4 100644 (file)
@@ -8,17 +8,9 @@ http://github.com/freedreno/envytools/
 git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml            (  27229 bytes, from 2015-02-10 17:00:41)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2014-06-02 18:31:15)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2015-01-23 16:20:19)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -910,6 +902,7 @@ static inline uint32_t __offset_LM(uint32_t idx)
                case 2: return (mdp5_cfg->lm.base[2]);
                case 3: return (mdp5_cfg->lm.base[3]);
                case 4: return (mdp5_cfg->lm.base[4]);
+               case 5: return (mdp5_cfg->lm.base[5]);
                default: return INVALID_IDX(idx);
        }
 }
index 46fac545dc2bb8f84e8d6bc241d88931d926b23e..2f2863cf8b45f21e692e3e50f09c88275d83da63 100644 (file)
@@ -62,8 +62,8 @@ struct mdp5_crtc {
 
                /* current cursor being scanned out: */
                struct drm_gem_object *scanout_bo;
-               uint32_t width;
-               uint32_t height;
+               uint32_t width, height;
+               uint32_t x, y;
        } cursor;
 };
 #define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base)
@@ -103,8 +103,8 @@ static void crtc_flush_all(struct drm_crtc *crtc)
        struct drm_plane *plane;
        uint32_t flush_mask = 0;
 
-       /* we could have already released CTL in the disable path: */
-       if (!mdp5_crtc->ctl)
+       /* this should not happen: */
+       if (WARN_ON(!mdp5_crtc->ctl))
                return;
 
        drm_atomic_crtc_for_each_plane(plane, crtc) {
@@ -143,6 +143,11 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
        drm_atomic_crtc_for_each_plane(plane, crtc) {
                mdp5_plane_complete_flip(plane);
        }
+
+       if (mdp5_crtc->ctl && !crtc->state->enable) {
+               mdp5_ctl_release(mdp5_crtc->ctl);
+               mdp5_crtc->ctl = NULL;
+       }
 }
 
 static void unref_cursor_worker(struct drm_flip_work *work, void *val)
@@ -386,14 +391,17 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc)
        mdp5_crtc->event = crtc->state->event;
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
+       /*
+        * If no CTL has been allocated in mdp5_crtc_atomic_check(),
+        * it means we are trying to flush a CRTC whose state is disabled:
+        * nothing else needs to be done.
+        */
+       if (unlikely(!mdp5_crtc->ctl))
+               return;
+
        blend_setup(crtc);
        crtc_flush_all(crtc);
        request_pending(crtc, PENDING_FLIP);
-
-       if (mdp5_crtc->ctl && !crtc->state->enable) {
-               mdp5_ctl_release(mdp5_crtc->ctl);
-               mdp5_crtc->ctl = NULL;
-       }
 }
 
 static int mdp5_crtc_set_property(struct drm_crtc *crtc,
@@ -403,6 +411,32 @@ static int mdp5_crtc_set_property(struct drm_crtc *crtc,
        return -EINVAL;
 }
 
+static void get_roi(struct drm_crtc *crtc, uint32_t *roi_w, uint32_t *roi_h)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       uint32_t xres = crtc->mode.hdisplay;
+       uint32_t yres = crtc->mode.vdisplay;
+
+       /*
+        * Cursor Region Of Interest (ROI) is a plane read from cursor
+        * buffer to render. The ROI region is determined by the visibility of
+        * the cursor point. In the default Cursor image the cursor point will
+        * be at the top left of the cursor image, unless it is specified
+        * otherwise using hotspot feature.
+        *
+        * If the cursor point reaches the right (xres - x < cursor.width) or
+        * bottom (yres - y < cursor.height) boundary of the screen, then ROI
+        * width and ROI height need to be evaluated to crop the cursor image
+        * accordingly.
+        * (xres-x) will be new cursor width when x > (xres - cursor.width)
+        * (yres-y) will be new cursor height when y > (yres - cursor.height)
+        */
+       *roi_w = min(mdp5_crtc->cursor.width, xres -
+                       mdp5_crtc->cursor.x);
+       *roi_h = min(mdp5_crtc->cursor.height, yres -
+                       mdp5_crtc->cursor.y);
+}
+
 static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
                struct drm_file *file, uint32_t handle,
                uint32_t width, uint32_t height)
@@ -416,6 +450,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
        unsigned int depth;
        enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
        uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
+       uint32_t roi_w, roi_h;
        unsigned long flags;
 
        if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
@@ -446,6 +481,12 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
        spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
        old_bo = mdp5_crtc->cursor.scanout_bo;
 
+       mdp5_crtc->cursor.scanout_bo = cursor_bo;
+       mdp5_crtc->cursor.width = width;
+       mdp5_crtc->cursor.height = height;
+
+       get_roi(crtc, &roi_w, &roi_h);
+
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
                        MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
@@ -453,19 +494,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
                        MDP5_LM_CURSOR_IMG_SIZE_SRC_H(height) |
                        MDP5_LM_CURSOR_IMG_SIZE_SRC_W(width));
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
-                       MDP5_LM_CURSOR_SIZE_ROI_H(height) |
-                       MDP5_LM_CURSOR_SIZE_ROI_W(width));
+                       MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) |
+                       MDP5_LM_CURSOR_SIZE_ROI_W(roi_w));
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm), cursor_addr);
 
-
        blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN;
-       blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN;
        blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha);
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg);
 
-       mdp5_crtc->cursor.scanout_bo = cursor_bo;
-       mdp5_crtc->cursor.width = width;
-       mdp5_crtc->cursor.height = height;
        spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
 
        ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true);
@@ -489,31 +525,18 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
-       uint32_t xres = crtc->mode.hdisplay;
-       uint32_t yres = crtc->mode.vdisplay;
        uint32_t roi_w;
        uint32_t roi_h;
        unsigned long flags;
 
-       x = (x > 0) ? x : 0;
-       y = (y > 0) ? y : 0;
+       /* In case the CRTC is disabled, just drop the cursor update */
+       if (unlikely(!crtc->state->enable))
+               return 0;
 
-       /*
-        * Cursor Region Of Interest (ROI) is a plane read from cursor
-        * buffer to render. The ROI region is determined by the visiblity of
-        * the cursor point. In the default Cursor image the cursor point will
-        * be at the top left of the cursor image, unless it is specified
-        * otherwise using hotspot feature.
-        *
-        * If the cursor point reaches the right (xres - x < cursor.width) or
-        * bottom (yres - y < cursor.height) boundary of the screen, then ROI
-        * width and ROI height need to be evaluated to crop the cursor image
-        * accordingly.
-        * (xres-x) will be new cursor width when x > (xres - cursor.width)
-        * (yres-y) will be new cursor height when y > (yres - cursor.height)
-        */
-       roi_w = min(mdp5_crtc->cursor.width, xres - x);
-       roi_h = min(mdp5_crtc->cursor.height, yres - y);
+       mdp5_crtc->cursor.x = x = max(x, 0);
+       mdp5_crtc->cursor.y = y = max(y, 0);
+
+       get_roi(crtc, &roi_w, &roi_h);
 
        spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(mdp5_crtc->lm),
@@ -544,8 +567,8 @@ static const struct drm_crtc_funcs mdp5_crtc_funcs = {
 static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
        .mode_fixup = mdp5_crtc_mode_fixup,
        .mode_set_nofb = mdp5_crtc_mode_set_nofb,
-       .prepare = mdp5_crtc_disable,
-       .commit = mdp5_crtc_enable,
+       .disable = mdp5_crtc_disable,
+       .enable = mdp5_crtc_enable,
        .atomic_check = mdp5_crtc_atomic_check,
        .atomic_begin = mdp5_crtc_atomic_begin,
        .atomic_flush = mdp5_crtc_atomic_flush,
index d6a14bb99988199db0993dd654255eecf2269539..af0e02fa4f4821ac7a71a4b641fde76db366a8cd 100644 (file)
@@ -267,14 +267,14 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
        mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
 
-       mdp5_encoder->enabled = false;
+       mdp5_encoder->enabled = true;
 }
 
 static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
        .mode_fixup = mdp5_encoder_mode_fixup,
        .mode_set = mdp5_encoder_mode_set,
-       .prepare = mdp5_encoder_disable,
-       .commit = mdp5_encoder_enable,
+       .disable = mdp5_encoder_disable,
+       .enable = mdp5_encoder_enable,
 };
 
 /* initialize encoder */
index 70ac81edd40f3bb7d6de68553b7be350005312ec..a9407105b9b799bea9fc787a923e7dc914bee30a 100644 (file)
@@ -34,7 +34,10 @@ static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
 void mdp5_irq_preinstall(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       mdp5_enable(mdp5_kms);
        mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
+       mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+       mdp5_disable(mdp5_kms);
 }
 
 int mdp5_irq_postinstall(struct msm_kms *kms)
@@ -57,7 +60,9 @@ int mdp5_irq_postinstall(struct msm_kms *kms)
 void mdp5_irq_uninstall(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       mdp5_enable(mdp5_kms);
        mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+       mdp5_disable(mdp5_kms);
 }
 
 static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)
index 05cf9ab2a87691fa2bf403ff6f48c66c921a239f..6bd48e2462833e03e63a2d2967cda30db2cce8da 100644 (file)
@@ -156,7 +156,8 @@ static const struct drm_plane_funcs mdp5_plane_funcs = {
 };
 
 static int mdp5_plane_prepare_fb(struct drm_plane *plane,
-               struct drm_framebuffer *fb)
+               struct drm_framebuffer *fb,
+               const struct drm_plane_state *new_state)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
        struct mdp5_kms *mdp5_kms = get_kms(plane);
@@ -166,7 +167,8 @@ static int mdp5_plane_prepare_fb(struct drm_plane *plane,
 }
 
 static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
-               struct drm_framebuffer *fb)
+               struct drm_framebuffer *fb,
+               const struct drm_plane_state *old_state)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
        struct mdp5_kms *mdp5_kms = get_kms(plane);
index 871aa2108dc694795e74f2b308031c849ad1a966..5b192128cda2b9afb978f8c079d08d20e86f10e4 100644 (file)
@@ -96,11 +96,11 @@ static void complete_commit(struct msm_commit *c)
 
        kms->funcs->prepare_commit(kms, state);
 
-       drm_atomic_helper_commit_pre_planes(dev, state);
+       drm_atomic_helper_commit_modeset_disables(dev, state);
 
        drm_atomic_helper_commit_planes(dev, state);
 
-       drm_atomic_helper_commit_post_planes(dev, state);
+       drm_atomic_helper_commit_modeset_enables(dev, state);
 
        /* NOTE: _wait_for_vblanks() only waits for vblank on
         * enabled CRTCs.  So we end up faulting when disabling
@@ -219,8 +219,10 @@ int msm_atomic_commit(struct drm_device *dev,
         * mark our set of crtc's as busy:
         */
        ret = start_atomic(dev->dev_private, c->crtc_mask);
-       if (ret)
+       if (ret) {
+               kfree(c);
                return ret;
+       }
 
        /*
         * This is the point of no return - everything below never fails except
index 79924e4b1b495577f26822f8f03801b67e4497a6..6751553abe4afe4bc408cd08863a7981b858bece 100644 (file)
@@ -418,7 +418,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
        nouveau_fbcon_zfill(dev, fbcon);
 
        /* To allow resizeing without swapping buffers */
-       NV_INFO(drm, "allocated %dx%d fb: 0x%lx, bo %p\n",
+       NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n",
                nouveau_fb->base.width, nouveau_fb->base.height,
                nvbo->bo.offset, nvbo);
 
index 29bd539af183d6d366ef2cafd79c8a5b0ad49ea9..6efa8f38ff5472b42ec9895c7a5505c9992a50c1 100644 (file)
@@ -340,11 +340,13 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
 
                /* switch mmio to cpu's native endianness */
 #ifndef __BIG_ENDIAN
-               if (ioread32_native(map + 0x000004) != 0x00000000)
+               if (ioread32_native(map + 0x000004) != 0x00000000) {
 #else
-               if (ioread32_native(map + 0x000004) == 0x00000000)
+               if (ioread32_native(map + 0x000004) == 0x00000000) {
 #endif
                        iowrite32_native(0x01000001, map + 0x000004);
+                       ioread32_native(map);
+               }
 
                /* read boot0 and strapping information */
                boot0 = ioread32_native(map + 0x000000);
index 539561ed3281a1602348eb375b2c698ddb8f7afd..108d048da7643f0b97255edf06e205a72d672a48 100644 (file)
@@ -140,6 +140,49 @@ gm100_identify(struct nvkm_device *device)
                device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
                device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
                device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+#endif
+               break;
+       case 0x126:
+               device->cname = "GM206";
+               device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] =  gm204_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gm107_fuse_oclass;
+#if 0
+               /* looks to be some non-trivial changes */
+               device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+               /* priv ring says no to 0x10eb14 writes */
+               device->oclass[NVDEV_SUBDEV_THERM  ] = &gm107_therm_oclass;
+#endif
+               device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm204_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  gm107_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTC    ] =  gm107_ltc_oclass;
+               device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+               device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PMU    ] =  gk208_pmu_oclass;
+#if 0
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  gk208_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  gm107_gr_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DISP   ] =  gm204_disp_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_CE0    ] = &gm204_ce0_oclass;
+               device->oclass[NVDEV_ENGINE_CE1    ] = &gm204_ce1_oclass;
+               device->oclass[NVDEV_ENGINE_CE2    ] = &gm204_ce2_oclass;
+               device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+               device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+               device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
 #endif
                break;
        default:
index b038b6eb51db2f3104dea58562d14913f4c794ed..043e4296084c176695f6e39ff0f046bbe033b1c0 100644 (file)
@@ -502,72 +502,57 @@ nv04_fifo_intr(struct nvkm_subdev *subdev)
 {
        struct nvkm_device *device = nv_device(subdev);
        struct nv04_fifo_priv *priv = (void *)subdev;
-       uint32_t status, reassign;
-       int cnt = 0;
+       u32 mask = nv_rd32(priv, NV03_PFIFO_INTR_EN_0);
+       u32 stat = nv_rd32(priv, NV03_PFIFO_INTR_0) & mask;
+       u32 reassign, chid, get, sem;
 
        reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
-       while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
-               uint32_t chid, get;
-
-               nv_wr32(priv, NV03_PFIFO_CACHES, 0);
-
-               chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
-               get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
+       nv_wr32(priv, NV03_PFIFO_CACHES, 0);
 
-               if (status & NV_PFIFO_INTR_CACHE_ERROR) {
-                       nv04_fifo_cache_error(device, priv, chid, get);
-                       status &= ~NV_PFIFO_INTR_CACHE_ERROR;
-               }
+       chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
+       get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
 
-               if (status & NV_PFIFO_INTR_DMA_PUSHER) {
-                       nv04_fifo_dma_pusher(device, priv, chid);
-                       status &= ~NV_PFIFO_INTR_DMA_PUSHER;
-               }
+       if (stat & NV_PFIFO_INTR_CACHE_ERROR) {
+               nv04_fifo_cache_error(device, priv, chid, get);
+               stat &= ~NV_PFIFO_INTR_CACHE_ERROR;
+       }
 
-               if (status & NV_PFIFO_INTR_SEMAPHORE) {
-                       uint32_t sem;
+       if (stat & NV_PFIFO_INTR_DMA_PUSHER) {
+               nv04_fifo_dma_pusher(device, priv, chid);
+               stat &= ~NV_PFIFO_INTR_DMA_PUSHER;
+       }
 
-                       status &= ~NV_PFIFO_INTR_SEMAPHORE;
-                       nv_wr32(priv, NV03_PFIFO_INTR_0,
-                               NV_PFIFO_INTR_SEMAPHORE);
+       if (stat & NV_PFIFO_INTR_SEMAPHORE) {
+               stat &= ~NV_PFIFO_INTR_SEMAPHORE;
+               nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE);
 
-                       sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
-                       nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
+               sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
+               nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
 
-                       nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
-                       nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-               }
+               nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
+               nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+       }
 
-               if (device->card_type == NV_50) {
-                       if (status & 0x00000010) {
-                               status &= ~0x00000010;
-                               nv_wr32(priv, 0x002100, 0x00000010);
-                       }
-
-                       if (status & 0x40000000) {
-                               nv_wr32(priv, 0x002100, 0x40000000);
-                               nvkm_fifo_uevent(&priv->base);
-                               status &= ~0x40000000;
-                       }
+       if (device->card_type == NV_50) {
+               if (stat & 0x00000010) {
+                       stat &= ~0x00000010;
+                       nv_wr32(priv, 0x002100, 0x00000010);
                }
 
-               if (status) {
-                       nv_warn(priv, "unknown intr 0x%08x, ch %d\n",
-                               status, chid);
-                       nv_wr32(priv, NV03_PFIFO_INTR_0, status);
-                       status = 0;
+               if (stat & 0x40000000) {
+                       nv_wr32(priv, 0x002100, 0x40000000);
+                       nvkm_fifo_uevent(&priv->base);
+                       stat &= ~0x40000000;
                }
-
-               nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
        }
 
-       if (status) {
-               nv_error(priv, "still angry after %d spins, halt\n", cnt);
-               nv_wr32(priv, 0x002140, 0);
-               nv_wr32(priv, 0x000140, 0);
+       if (stat) {
+               nv_warn(priv, "unknown intr 0x%08x\n", stat);
+               nv_mask(priv, NV03_PFIFO_INTR_EN_0, stat, 0x00000000);
+               nv_wr32(priv, NV03_PFIFO_INTR_0, stat);
        }
 
-       nv_wr32(priv, 0x000100, 0x00000100);
+       nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
 }
 
 static int
index 2e7ec389eea7903e1480fce2b0a8901f6e8f1b4f..57e2c5b1312385ab1cf1a52b776f6b1170102bae 100644 (file)
@@ -1032,9 +1032,9 @@ gf100_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418808, 0x00000000, s, b);
-       mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s));
 }
 
 void
index b52300d8861a760b323fc00a89dd90c3e86738af..5e9454ba158fe816e7c381e7518a259efb1565d8 100644 (file)
@@ -851,9 +851,9 @@ gk104_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418808, 0x00000000, s, b);
-       mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s));
        mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
 }
 
index 956f4dce960c7912837c9e16889f6b3db4f6819d..b2fae6e389e24260bb5093ffdd9fa5d90982f277 100644 (file)
@@ -871,9 +871,9 @@ gm107_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418e24, 0x00000000, s, b);
-       mmio_refn(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s));
        mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
 }
 
index d1a89b2bd5c17393d08e441fb2fbeb643fdf5ff1..c4e1f085ee10b810c07ef1557a9438ac6a1eaa77 100644 (file)
@@ -74,7 +74,11 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info)
        u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
        if (ent) {
                if (ver >= 0x41) {
-                       if (!(nv_ro32(bios, ent) & 0x80000000))
+                       u32 ent_value = nv_ro32(bios, ent);
+                       u8 i2c_port = (ent_value >> 27) & 0x1f;
+                       u8 dpaux_port = (ent_value >> 22) & 0x1f;
+                       /* value 0x1f means unused according to DCB 4.x spec */
+                       if (i2c_port == 0x1f && dpaux_port == 0x1f)
                                info->type = DCB_I2C_UNUSED;
                        else
                                info->type = DCB_I2C_PMGR;
index a94b11f7859d807b7fff43ef6f5efc106a4a9997..b41965c2888d9e43ad57e1c7f74f6e55ee70b288 100644 (file)
@@ -271,18 +271,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = {
        .best_encoder = omap_connector_attached_encoder,
 };
 
-/* flush an area of the framebuffer (in case of manual update display that
- * is not automatically flushed)
- */
-void omap_connector_flush(struct drm_connector *connector,
-               int x, int y, int w, int h)
-{
-       struct omap_connector *omap_connector = to_omap_connector(connector);
-
-       /* TODO: enable when supported in dss */
-       VERB("%s: %d,%d, %dx%d", omap_connector->dssdev->name, x, y, w, h);
-}
-
 /* initialize connector */
 struct drm_connector *omap_connector_init(struct drm_device *dev,
                int connector_type, struct omap_dss_device *dssdev,
index b0566a1ca28f3d59c228d9c500b4004ab44895ac..f456544bf300ba89fdea11242afd4656436888dd 100644 (file)
@@ -28,7 +28,6 @@
 
 struct omap_crtc {
        struct drm_crtc base;
-       struct drm_plane *plane;
 
        const char *name;
        int pipe;
@@ -46,7 +45,6 @@ struct omap_crtc {
 
        struct omap_video_timings timings;
        bool enabled;
-       bool full_update;
 
        struct omap_drm_apply apply;
 
@@ -74,8 +72,14 @@ struct omap_crtc {
         * XXX maybe fold into apply_work??
         */
        struct work_struct page_flip_work;
+
+       bool ignore_digit_sync_lost;
 };
 
+/* -----------------------------------------------------------------------------
+ * Helper Functions
+ */
+
 uint32_t pipe2vbl(struct drm_crtc *crtc)
 {
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@@ -83,6 +87,22 @@ uint32_t pipe2vbl(struct drm_crtc *crtc)
        return dispc_mgr_get_vsync_irq(omap_crtc->channel);
 }
 
+const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       return &omap_crtc->timings;
+}
+
+enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       return omap_crtc->channel;
+}
+
+/* -----------------------------------------------------------------------------
+ * DSS Manager Functions
+ */
+
 /*
  * Manager-ops, callbacks from output when they need to configure
  * the upstream part of the video pipe.
@@ -122,7 +142,63 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
 {
 }
 
-static void set_enabled(struct drm_crtc *crtc, bool enable);
+/* Called only from CRTC pre_apply and suspend/resume handlers. */
+static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
+{
+       struct drm_device *dev = crtc->dev;
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       enum omap_channel channel = omap_crtc->channel;
+       struct omap_irq_wait *wait;
+       u32 framedone_irq, vsync_irq;
+       int ret;
+
+       if (dispc_mgr_is_enabled(channel) == enable)
+               return;
+
+       if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
+               /*
+                * Digit output produces some sync lost interrupts during the
+                * first frame when enabling, so we need to ignore those.
+                */
+               omap_crtc->ignore_digit_sync_lost = true;
+       }
+
+       framedone_irq = dispc_mgr_get_framedone_irq(channel);
+       vsync_irq = dispc_mgr_get_vsync_irq(channel);
+
+       if (enable) {
+               wait = omap_irq_wait_init(dev, vsync_irq, 1);
+       } else {
+               /*
+                * When we disable the digit output, we need to wait for
+                * FRAMEDONE to know that DISPC has finished with the output.
+                *
+                * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
+                * that case we need to use vsync interrupt, and wait for both
+                * even and odd frames.
+                */
+
+               if (framedone_irq)
+                       wait = omap_irq_wait_init(dev, framedone_irq, 1);
+               else
+                       wait = omap_irq_wait_init(dev, vsync_irq, 2);
+       }
+
+       dispc_mgr_enable(channel, enable);
+
+       ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
+       if (ret) {
+               dev_err(dev->dev, "%s: timeout waiting for %s\n",
+                               omap_crtc->name, enable ? "enable" : "disable");
+       }
+
+       if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
+               omap_crtc->ignore_digit_sync_lost = false;
+               /* make sure the irq handler sees the value above */
+               mb();
+       }
+}
+
 
 static int omap_crtc_enable(struct omap_overlay_manager *mgr)
 {
@@ -131,7 +207,7 @@ static int omap_crtc_enable(struct omap_overlay_manager *mgr)
        dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
        dispc_mgr_set_timings(omap_crtc->channel,
                        &omap_crtc->timings);
-       set_enabled(&omap_crtc->base, true);
+       omap_crtc_set_enabled(&omap_crtc->base, true);
 
        return 0;
 }
@@ -140,7 +216,7 @@ static void omap_crtc_disable(struct omap_overlay_manager *mgr)
 {
        struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
 
-       set_enabled(&omap_crtc->base, false);
+       omap_crtc_set_enabled(&omap_crtc->base, false);
 }
 
 static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
@@ -149,7 +225,6 @@ static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
        struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
        DBG("%s", omap_crtc->name);
        omap_crtc->timings = *timings;
-       omap_crtc->full_update = true;
 }
 
 static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
@@ -174,19 +249,201 @@ static void omap_crtc_unregister_framedone_handler(
 }
 
 static const struct dss_mgr_ops mgr_ops = {
-               .connect = omap_crtc_connect,
-               .disconnect = omap_crtc_disconnect,
-               .start_update = omap_crtc_start_update,
-               .enable = omap_crtc_enable,
-               .disable = omap_crtc_disable,
-               .set_timings = omap_crtc_set_timings,
-               .set_lcd_config = omap_crtc_set_lcd_config,
-               .register_framedone_handler = omap_crtc_register_framedone_handler,
-               .unregister_framedone_handler = omap_crtc_unregister_framedone_handler,
+       .connect = omap_crtc_connect,
+       .disconnect = omap_crtc_disconnect,
+       .start_update = omap_crtc_start_update,
+       .enable = omap_crtc_enable,
+       .disable = omap_crtc_disable,
+       .set_timings = omap_crtc_set_timings,
+       .set_lcd_config = omap_crtc_set_lcd_config,
+       .register_framedone_handler = omap_crtc_register_framedone_handler,
+       .unregister_framedone_handler = omap_crtc_unregister_framedone_handler,
 };
 
-/*
- * CRTC funcs:
+/* -----------------------------------------------------------------------------
+ * Apply Logic
+ */
+
+static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(irq, struct omap_crtc, error_irq);
+
+       if (omap_crtc->ignore_digit_sync_lost) {
+               irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
+               if (!irqstatus)
+                       return;
+       }
+
+       DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
+}
+
+static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(irq, struct omap_crtc, apply_irq);
+       struct drm_crtc *crtc = &omap_crtc->base;
+
+       if (!dispc_mgr_go_busy(omap_crtc->channel)) {
+               struct omap_drm_private *priv =
+                               crtc->dev->dev_private;
+               DBG("%s: apply done", omap_crtc->name);
+               __omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
+               queue_work(priv->wq, &omap_crtc->apply_work);
+       }
+}
+
+static void apply_worker(struct work_struct *work)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(work, struct omap_crtc, apply_work);
+       struct drm_crtc *crtc = &omap_crtc->base;
+       struct drm_device *dev = crtc->dev;
+       struct omap_drm_apply *apply, *n;
+       bool need_apply;
+
+       /*
+        * Synchronize everything on mode_config.mutex, to keep
+        * the callbacks and list modification all serialized
+        * with respect to modesetting ioctls from userspace.
+        */
+       drm_modeset_lock(&crtc->mutex, NULL);
+       dispc_runtime_get();
+
+       /*
+        * If we are still pending a previous update, wait.. when the
+        * pending update completes, we get kicked again.
+        */
+       if (omap_crtc->apply_irq.registered)
+               goto out;
+
+       /* finish up previous apply's: */
+       list_for_each_entry_safe(apply, n,
+                       &omap_crtc->pending_applies, pending_node) {
+               apply->post_apply(apply);
+               list_del(&apply->pending_node);
+       }
+
+       need_apply = !list_empty(&omap_crtc->queued_applies);
+
+       /* then handle the next round of of queued apply's: */
+       list_for_each_entry_safe(apply, n,
+                       &omap_crtc->queued_applies, queued_node) {
+               apply->pre_apply(apply);
+               list_del(&apply->queued_node);
+               apply->queued = false;
+               list_add_tail(&apply->pending_node,
+                               &omap_crtc->pending_applies);
+       }
+
+       if (need_apply) {
+               enum omap_channel channel = omap_crtc->channel;
+
+               DBG("%s: GO", omap_crtc->name);
+
+               if (dispc_mgr_is_enabled(channel)) {
+                       dispc_mgr_go(channel);
+                       omap_irq_register(dev, &omap_crtc->apply_irq);
+               } else {
+                       struct omap_drm_private *priv = dev->dev_private;
+                       queue_work(priv->wq, &omap_crtc->apply_work);
+               }
+       }
+
+out:
+       dispc_runtime_put();
+       drm_modeset_unlock(&crtc->mutex);
+}
+
+int omap_crtc_apply(struct drm_crtc *crtc,
+               struct omap_drm_apply *apply)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+
+       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
+
+       /* no need to queue it again if it is already queued: */
+       if (apply->queued)
+               return 0;
+
+       apply->queued = true;
+       list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
+
+       /*
+        * If there are no currently pending updates, then go ahead and
+        * kick the worker immediately, otherwise it will run again when
+        * the current update finishes.
+        */
+       if (list_empty(&omap_crtc->pending_applies)) {
+               struct omap_drm_private *priv = crtc->dev->dev_private;
+               queue_work(priv->wq, &omap_crtc->apply_work);
+       }
+
+       return 0;
+}
+
+static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(apply, struct omap_crtc, apply);
+       struct drm_crtc *crtc = &omap_crtc->base;
+       struct omap_drm_private *priv = crtc->dev->dev_private;
+       struct drm_encoder *encoder = NULL;
+       unsigned int i;
+
+       DBG("%s: enabled=%d", omap_crtc->name, omap_crtc->enabled);
+
+       for (i = 0; i < priv->num_encoders; i++) {
+               if (priv->encoders[i]->crtc == crtc) {
+                       encoder = priv->encoders[i];
+                       break;
+               }
+       }
+
+       if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
+               omap_encoder_set_enabled(omap_crtc->current_encoder, false);
+
+       omap_crtc->current_encoder = encoder;
+
+       if (!omap_crtc->enabled) {
+               if (encoder)
+                       omap_encoder_set_enabled(encoder, false);
+       } else {
+               if (encoder) {
+                       omap_encoder_set_enabled(encoder, false);
+                       omap_encoder_update(encoder, omap_crtc->mgr,
+                                       &omap_crtc->timings);
+                       omap_encoder_set_enabled(encoder, true);
+               }
+       }
+}
+
+static void omap_crtc_post_apply(struct omap_drm_apply *apply)
+{
+       /* nothing needed for post-apply */
+}
+
+void omap_crtc_flush(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       int loops = 0;
+
+       while (!list_empty(&omap_crtc->pending_applies) ||
+               !list_empty(&omap_crtc->queued_applies) ||
+               omap_crtc->event || omap_crtc->old_fb) {
+
+               if (++loops > 10) {
+                       dev_err(crtc->dev->dev,
+                               "omap_crtc_flush() timeout\n");
+                       break;
+               }
+
+               schedule_timeout_uninterruptible(msecs_to_jiffies(20));
+       }
+}
+
+/* -----------------------------------------------------------------------------
+ * CRTC Functions
  */
 
 static void omap_crtc_destroy(struct drm_crtc *crtc)
@@ -214,17 +471,13 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
 
        if (enabled != omap_crtc->enabled) {
                omap_crtc->enabled = enabled;
-               omap_crtc->full_update = true;
                omap_crtc_apply(crtc, &omap_crtc->apply);
 
-               /* also enable our private plane: */
-               WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
-
-               /* and any attached overlay planes: */
+               /* Enable/disable all planes associated with the CRTC. */
                for (i = 0; i < priv->num_planes; i++) {
                        struct drm_plane *plane = priv->planes[i];
                        if (plane->crtc == crtc)
-                               WARN_ON(omap_plane_dpms(plane, mode));
+                               WARN_ON(omap_plane_set_enable(plane, enabled));
                }
        }
 }
@@ -256,13 +509,17 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
                        mode->type, mode->flags);
 
        copy_timings_drm_to_omap(&omap_crtc->timings, mode);
-       omap_crtc->full_update = true;
 
-       return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16,
-                       NULL, NULL);
+       /*
+        * The primary plane CRTC can be reset if the plane is disabled directly
+        * through the universal plane API. Set it again here.
+        */
+       crtc->primary->crtc = crtc;
+
+       return omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb,
+                                  0, 0, mode->hdisplay, mode->vdisplay,
+                                  x, y, mode->hdisplay, mode->vdisplay,
+                                  NULL, NULL);
 }
 
 static void omap_crtc_prepare(struct drm_crtc *crtc)
@@ -282,15 +539,13 @@ static void omap_crtc_commit(struct drm_crtc *crtc)
 static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
                struct drm_framebuffer *old_fb)
 {
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       struct drm_plane *plane = omap_crtc->plane;
+       struct drm_plane *plane = crtc->primary;
        struct drm_display_mode *mode = &crtc->mode;
 
        return omap_plane_mode_set(plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16,
-                       NULL, NULL);
+                                  0, 0, mode->hdisplay, mode->vdisplay,
+                                  x, y, mode->hdisplay, mode->vdisplay,
+                                  NULL, NULL);
 }
 
 static void vblank_cb(void *arg)
@@ -299,6 +554,7 @@ static void vblank_cb(void *arg)
        struct drm_device *dev = crtc->dev;
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
        unsigned long flags;
+       struct drm_framebuffer *fb;
 
        spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -306,10 +562,15 @@ static void vblank_cb(void *arg)
        if (omap_crtc->event)
                drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event);
 
+       fb = omap_crtc->old_fb;
+
        omap_crtc->event = NULL;
        omap_crtc->old_fb = NULL;
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       if (fb)
+               drm_framebuffer_unreference(fb);
 }
 
 static void page_flip_worker(struct work_struct *work)
@@ -321,11 +582,10 @@ static void page_flip_worker(struct work_struct *work)
        struct drm_gem_object *bo;
 
        drm_modeset_lock(&crtc->mutex, NULL);
-       omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       crtc->x << 16, crtc->y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16,
-                       vblank_cb, crtc);
+       omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb,
+                           0, 0, mode->hdisplay, mode->vdisplay,
+                           crtc->x, crtc->y, mode->hdisplay, mode->vdisplay,
+                           vblank_cb, crtc);
        drm_modeset_unlock(&crtc->mutex);
 
        bo = omap_framebuffer_bo(crtc->primary->fb, 0);
@@ -361,11 +621,12 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
        if (omap_crtc->old_fb) {
                spin_unlock_irqrestore(&dev->event_lock, flags);
                dev_err(dev->dev, "already a pending flip\n");
-               return -EINVAL;
+               return -EBUSY;
        }
 
        omap_crtc->event = event;
        omap_crtc->old_fb = primary->fb = fb;
+       drm_framebuffer_reference(omap_crtc->old_fb);
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
@@ -385,7 +646,6 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 static int omap_crtc_set_property(struct drm_crtc *crtc,
                struct drm_property *property, uint64_t val)
 {
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
        struct omap_drm_private *priv = crtc->dev->dev_private;
 
        if (property == priv->rotation_prop) {
@@ -393,7 +653,7 @@ static int omap_crtc_set_property(struct drm_crtc *crtc,
                                !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
        }
 
-       return omap_plane_set_property(omap_crtc->plane, property, val);
+       return omap_plane_set_property(crtc->primary, property, val);
 }
 
 static const struct drm_crtc_funcs omap_crtc_funcs = {
@@ -412,256 +672,15 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
        .mode_set_base = omap_crtc_mode_set_base,
 };
 
-const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       return &omap_crtc->timings;
-}
-
-enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       return omap_crtc->channel;
-}
-
-static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(irq, struct omap_crtc, error_irq);
-       struct drm_crtc *crtc = &omap_crtc->base;
-       DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus);
-       /* avoid getting in a flood, unregister the irq until next vblank */
-       __omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
-}
-
-static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(irq, struct omap_crtc, apply_irq);
-       struct drm_crtc *crtc = &omap_crtc->base;
-
-       if (!omap_crtc->error_irq.registered)
-               __omap_irq_register(crtc->dev, &omap_crtc->error_irq);
-
-       if (!dispc_mgr_go_busy(omap_crtc->channel)) {
-               struct omap_drm_private *priv =
-                               crtc->dev->dev_private;
-               DBG("%s: apply done", omap_crtc->name);
-               __omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
-               queue_work(priv->wq, &omap_crtc->apply_work);
-       }
-}
-
-static void apply_worker(struct work_struct *work)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(work, struct omap_crtc, apply_work);
-       struct drm_crtc *crtc = &omap_crtc->base;
-       struct drm_device *dev = crtc->dev;
-       struct omap_drm_apply *apply, *n;
-       bool need_apply;
-
-       /*
-        * Synchronize everything on mode_config.mutex, to keep
-        * the callbacks and list modification all serialized
-        * with respect to modesetting ioctls from userspace.
-        */
-       drm_modeset_lock(&crtc->mutex, NULL);
-       dispc_runtime_get();
-
-       /*
-        * If we are still pending a previous update, wait.. when the
-        * pending update completes, we get kicked again.
-        */
-       if (omap_crtc->apply_irq.registered)
-               goto out;
-
-       /* finish up previous apply's: */
-       list_for_each_entry_safe(apply, n,
-                       &omap_crtc->pending_applies, pending_node) {
-               apply->post_apply(apply);
-               list_del(&apply->pending_node);
-       }
-
-       need_apply = !list_empty(&omap_crtc->queued_applies);
-
-       /* then handle the next round of of queued apply's: */
-       list_for_each_entry_safe(apply, n,
-                       &omap_crtc->queued_applies, queued_node) {
-               apply->pre_apply(apply);
-               list_del(&apply->queued_node);
-               apply->queued = false;
-               list_add_tail(&apply->pending_node,
-                               &omap_crtc->pending_applies);
-       }
-
-       if (need_apply) {
-               enum omap_channel channel = omap_crtc->channel;
-
-               DBG("%s: GO", omap_crtc->name);
-
-               if (dispc_mgr_is_enabled(channel)) {
-                       omap_irq_register(dev, &omap_crtc->apply_irq);
-                       dispc_mgr_go(channel);
-               } else {
-                       struct omap_drm_private *priv = dev->dev_private;
-                       queue_work(priv->wq, &omap_crtc->apply_work);
-               }
-       }
-
-out:
-       dispc_runtime_put();
-       drm_modeset_unlock(&crtc->mutex);
-}
-
-int omap_crtc_apply(struct drm_crtc *crtc,
-               struct omap_drm_apply *apply)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-
-       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
-
-       /* no need to queue it again if it is already queued: */
-       if (apply->queued)
-               return 0;
-
-       apply->queued = true;
-       list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
-
-       /*
-        * If there are no currently pending updates, then go ahead and
-        * kick the worker immediately, otherwise it will run again when
-        * the current update finishes.
-        */
-       if (list_empty(&omap_crtc->pending_applies)) {
-               struct omap_drm_private *priv = crtc->dev->dev_private;
-               queue_work(priv->wq, &omap_crtc->apply_work);
-       }
-
-       return 0;
-}
-
-/* called only from apply */
-static void set_enabled(struct drm_crtc *crtc, bool enable)
-{
-       struct drm_device *dev = crtc->dev;
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       enum omap_channel channel = omap_crtc->channel;
-       struct omap_irq_wait *wait;
-       u32 framedone_irq, vsync_irq;
-       int ret;
-
-       if (dispc_mgr_is_enabled(channel) == enable)
-               return;
-
-       /*
-        * Digit output produces some sync lost interrupts during the first
-        * frame when enabling, so we need to ignore those.
-        */
-       omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
-
-       framedone_irq = dispc_mgr_get_framedone_irq(channel);
-       vsync_irq = dispc_mgr_get_vsync_irq(channel);
-
-       if (enable) {
-               wait = omap_irq_wait_init(dev, vsync_irq, 1);
-       } else {
-               /*
-                * When we disable the digit output, we need to wait for
-                * FRAMEDONE to know that DISPC has finished with the output.
-                *
-                * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
-                * that case we need to use vsync interrupt, and wait for both
-                * even and odd frames.
-                */
-
-               if (framedone_irq)
-                       wait = omap_irq_wait_init(dev, framedone_irq, 1);
-               else
-                       wait = omap_irq_wait_init(dev, vsync_irq, 2);
-       }
-
-       dispc_mgr_enable(channel, enable);
-
-       ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
-       if (ret) {
-               dev_err(dev->dev, "%s: timeout waiting for %s\n",
-                               omap_crtc->name, enable ? "enable" : "disable");
-       }
-
-       omap_irq_register(crtc->dev, &omap_crtc->error_irq);
-}
-
-static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(apply, struct omap_crtc, apply);
-       struct drm_crtc *crtc = &omap_crtc->base;
-       struct drm_encoder *encoder = NULL;
-
-       DBG("%s: enabled=%d, full=%d", omap_crtc->name,
-                       omap_crtc->enabled, omap_crtc->full_update);
-
-       if (omap_crtc->full_update) {
-               struct omap_drm_private *priv = crtc->dev->dev_private;
-               int i;
-               for (i = 0; i < priv->num_encoders; i++) {
-                       if (priv->encoders[i]->crtc == crtc) {
-                               encoder = priv->encoders[i];
-                               break;
-                       }
-               }
-       }
-
-       if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
-               omap_encoder_set_enabled(omap_crtc->current_encoder, false);
-
-       omap_crtc->current_encoder = encoder;
-
-       if (!omap_crtc->enabled) {
-               if (encoder)
-                       omap_encoder_set_enabled(encoder, false);
-       } else {
-               if (encoder) {
-                       omap_encoder_set_enabled(encoder, false);
-                       omap_encoder_update(encoder, omap_crtc->mgr,
-                                       &omap_crtc->timings);
-                       omap_encoder_set_enabled(encoder, true);
-               }
-       }
-
-       omap_crtc->full_update = false;
-}
-
-static void omap_crtc_post_apply(struct omap_drm_apply *apply)
-{
-       /* nothing needed for post-apply */
-}
-
-void omap_crtc_flush(struct drm_crtc *crtc)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       int loops = 0;
-
-       while (!list_empty(&omap_crtc->pending_applies) ||
-               !list_empty(&omap_crtc->queued_applies) ||
-               omap_crtc->event || omap_crtc->old_fb) {
-
-               if (++loops > 10) {
-                       dev_err(crtc->dev->dev,
-                               "omap_crtc_flush() timeout\n");
-                       break;
-               }
-
-               schedule_timeout_uninterruptible(msecs_to_jiffies(20));
-       }
-}
+/* -----------------------------------------------------------------------------
+ * Init and Cleanup
+ */
 
 static const char *channel_names[] = {
-               [OMAP_DSS_CHANNEL_LCD] = "lcd",
-               [OMAP_DSS_CHANNEL_DIGIT] = "tv",
-               [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
-               [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
+       [OMAP_DSS_CHANNEL_LCD] = "lcd",
+       [OMAP_DSS_CHANNEL_DIGIT] = "tv",
+       [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
+       [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
 };
 
 void omap_crtc_pre_init(void)
@@ -681,12 +700,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        struct drm_crtc *crtc = NULL;
        struct omap_crtc *omap_crtc;
        struct omap_overlay_manager_info *info;
+       int ret;
 
        DBG("%s", channel_names[channel]);
 
        omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
        if (!omap_crtc)
-               goto fail;
+               return NULL;
 
        crtc = &omap_crtc->base;
 
@@ -700,8 +720,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        omap_crtc->apply.post_apply = omap_crtc_post_apply;
 
        omap_crtc->channel = channel;
-       omap_crtc->plane = plane;
-       omap_crtc->plane->crtc = crtc;
        omap_crtc->name = channel_names[channel];
        omap_crtc->pipe = id;
 
@@ -723,18 +741,18 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
        info->trans_enabled = false;
 
-       drm_crtc_init(dev, crtc, &omap_crtc_funcs);
+       ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
+                                       &omap_crtc_funcs);
+       if (ret < 0) {
+               kfree(omap_crtc);
+               return NULL;
+       }
+
        drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 
-       omap_plane_install_properties(omap_crtc->plane, &crtc->base);
+       omap_plane_install_properties(crtc->primary, &crtc->base);
 
        omap_crtcs[channel] = omap_crtc;
 
        return crtc;
-
-fail:
-       if (crtc)
-               omap_crtc_destroy(crtc);
-
-       return NULL;
 }
index 58bcd6ae0255dace4ae845c366af35cf62be4f20..9f32a83ca5078a587fccda89947f2dd9a05be83d 100644 (file)
@@ -148,11 +148,15 @@ struct refill_engine {
 
        bool async;
 
-       wait_queue_head_t wait_for_refill;
+       struct completion compl;
 
        struct list_head idle_node;
 };
 
+struct dmm_platform_data {
+       uint32_t cpu_cache_flags;
+};
+
 struct dmm {
        struct device *dev;
        void __iomem *base;
@@ -183,6 +187,8 @@ struct dmm {
 
        /* allocation list and lock */
        struct list_head alloc_head;
+
+       const struct dmm_platform_data *plat_data;
 };
 
 #endif
index 56c60552abba36bbfcc7572ebe2d986cc548141a..042038e8a662b88647726d11d8fbc77eee3c66d2 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mm.h>
 #include <linux/time.h>
 #include <linux/list.h>
+#include <linux/completion.h>
 
 #include "omap_dmm_tiler.h"
 #include "omap_dmm_priv.h"
 static struct tcm *containers[TILFMT_NFORMATS];
 static struct dmm *omap_dmm;
 
+#if defined(CONFIG_OF)
+static const struct of_device_id dmm_of_match[];
+#endif
+
 /* global spinlock for protecting lists */
 static DEFINE_SPINLOCK(list_lock);
 
@@ -58,19 +63,19 @@ static const struct {
        uint32_t slot_w;        /* width of each slot (in pixels) */
        uint32_t slot_h;        /* height of each slot (in pixels) */
 } geom[TILFMT_NFORMATS] = {
-               [TILFMT_8BIT]  = GEOM(0, 0, 1),
-               [TILFMT_16BIT] = GEOM(0, 1, 2),
-               [TILFMT_32BIT] = GEOM(1, 1, 4),
-               [TILFMT_PAGE]  = GEOM(SLOT_WIDTH_BITS, SLOT_HEIGHT_BITS, 1),
+       [TILFMT_8BIT]  = GEOM(0, 0, 1),
+       [TILFMT_16BIT] = GEOM(0, 1, 2),
+       [TILFMT_32BIT] = GEOM(1, 1, 4),
+       [TILFMT_PAGE]  = GEOM(SLOT_WIDTH_BITS, SLOT_HEIGHT_BITS, 1),
 };
 
 
 /* lookup table for registers w/ per-engine instances */
 static const uint32_t reg[][4] = {
-               [PAT_STATUS] = {DMM_PAT_STATUS__0, DMM_PAT_STATUS__1,
-                               DMM_PAT_STATUS__2, DMM_PAT_STATUS__3},
-               [PAT_DESCR]  = {DMM_PAT_DESCR__0, DMM_PAT_DESCR__1,
-                               DMM_PAT_DESCR__2, DMM_PAT_DESCR__3},
+       [PAT_STATUS] = {DMM_PAT_STATUS__0, DMM_PAT_STATUS__1,
+                       DMM_PAT_STATUS__2, DMM_PAT_STATUS__3},
+       [PAT_DESCR]  = {DMM_PAT_DESCR__0, DMM_PAT_DESCR__1,
+                       DMM_PAT_DESCR__2, DMM_PAT_DESCR__3},
 };
 
 /* simple allocator to grab next 16 byte aligned memory from txn */
@@ -142,10 +147,10 @@ static irqreturn_t omap_dmm_irq_handler(int irq, void *arg)
 
        for (i = 0; i < dmm->num_engines; i++) {
                if (status & DMM_IRQSTAT_LST) {
-                       wake_up_interruptible(&dmm->engines[i].wait_for_refill);
-
                        if (dmm->engines[i].async)
                                release_engine(&dmm->engines[i]);
+
+                       complete(&dmm->engines[i].compl);
                }
 
                status >>= 8;
@@ -269,15 +274,17 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait)
 
        /* mark whether it is async to denote list management in IRQ handler */
        engine->async = wait ? false : true;
+       reinit_completion(&engine->compl);
+       /* verify that the irq handler sees the 'async' and completion value */
+       smp_mb();
 
        /* kick reload */
        writel(engine->refill_pa,
                dmm->base + reg[PAT_DESCR][engine->id]);
 
        if (wait) {
-               if (wait_event_interruptible_timeout(engine->wait_for_refill,
-                               wait_status(engine, DMM_PATSTATUS_READY) == 0,
-                               msecs_to_jiffies(1)) <= 0) {
+               if (!wait_for_completion_timeout(&engine->compl,
+                               msecs_to_jiffies(1))) {
                        dev_err(dmm->dev, "timed out waiting for done\n");
                        ret = -ETIMEDOUT;
                }
@@ -529,6 +536,11 @@ size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h)
        return round_up(geom[fmt].cpp * w, PAGE_SIZE) * h;
 }
 
+uint32_t tiler_get_cpu_cache_flags(void)
+{
+       return omap_dmm->plat_data->cpu_cache_flags;
+}
+
 bool dmm_is_available(void)
 {
        return omap_dmm ? true : false;
@@ -592,6 +604,18 @@ static int omap_dmm_probe(struct platform_device *dev)
 
        init_waitqueue_head(&omap_dmm->engine_queue);
 
+       if (dev->dev.of_node) {
+               const struct of_device_id *match;
+
+               match = of_match_node(dmm_of_match, dev->dev.of_node);
+               if (!match) {
+                       dev_err(&dev->dev, "failed to find matching device node\n");
+                       return -ENODEV;
+               }
+
+               omap_dmm->plat_data = match->data;
+       }
+
        /* lookup hwmod data - base address and irq */
        mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (!mem) {
@@ -696,7 +720,7 @@ static int omap_dmm_probe(struct platform_device *dev)
                                                (REFILL_BUFFER_SIZE * i);
                omap_dmm->engines[i].refill_pa = omap_dmm->refill_pa +
                                                (REFILL_BUFFER_SIZE * i);
-               init_waitqueue_head(&omap_dmm->engines[i].wait_for_refill);
+               init_completion(&omap_dmm->engines[i].compl);
 
                list_add(&omap_dmm->engines[i].idle_node, &omap_dmm->idle_head);
        }
@@ -941,7 +965,7 @@ error:
 }
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int omap_dmm_resume(struct device *dev)
 {
        struct tcm_area area;
@@ -965,16 +989,28 @@ static int omap_dmm_resume(struct device *dev)
 
        return 0;
 }
-
-static const struct dev_pm_ops omap_dmm_pm_ops = {
-       .resume = omap_dmm_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(omap_dmm_pm_ops, NULL, omap_dmm_resume);
+
 #if defined(CONFIG_OF)
+static const struct dmm_platform_data dmm_omap4_platform_data = {
+       .cpu_cache_flags = OMAP_BO_WC,
+};
+
+static const struct dmm_platform_data dmm_omap5_platform_data = {
+       .cpu_cache_flags = OMAP_BO_UNCACHED,
+};
+
 static const struct of_device_id dmm_of_match[] = {
-       { .compatible = "ti,omap4-dmm", },
-       { .compatible = "ti,omap5-dmm", },
+       {
+               .compatible = "ti,omap4-dmm",
+               .data = &dmm_omap4_platform_data,
+       },
+       {
+               .compatible = "ti,omap5-dmm",
+               .data = &dmm_omap5_platform_data,
+       },
        {},
 };
 #endif
@@ -986,9 +1022,7 @@ struct platform_driver omap_dmm_driver = {
                .owner = THIS_MODULE,
                .name = DMM_DRIVER_NAME,
                .of_match_table = of_match_ptr(dmm_of_match),
-#ifdef CONFIG_PM
                .pm = &omap_dmm_pm_ops,
-#endif
        },
 };
 
index 4fdd61e54bd28abce8aef29c03e62c6596d31aab..e83c78372db8ea422448d14075cc8c8ac4be1c93 100644 (file)
@@ -106,6 +106,7 @@ uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient);
 size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h);
+uint32_t tiler_get_cpu_cache_flags(void);
 bool dmm_is_available(void);
 
 extern struct platform_driver omap_dmm_driver;
index 8241ed9b353c426176df85f19f9d1dff39aec866..94920d47e3b63f0dcd37bb6ee73f127f9049d7eb 100644 (file)
@@ -128,6 +128,29 @@ cleanup:
        return r;
 }
 
+static int omap_modeset_create_crtc(struct drm_device *dev, int id,
+                                   enum omap_channel channel)
+{
+       struct omap_drm_private *priv = dev->dev_private;
+       struct drm_plane *plane;
+       struct drm_crtc *crtc;
+
+       plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_PRIMARY);
+       if (IS_ERR(plane))
+               return PTR_ERR(plane);
+
+       crtc = omap_crtc_init(dev, plane, channel, id);
+
+       BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
+       priv->crtcs[id] = crtc;
+       priv->num_crtcs++;
+
+       priv->planes[id] = plane;
+       priv->num_planes++;
+
+       return 0;
+}
+
 static int omap_modeset_init(struct drm_device *dev)
 {
        struct omap_drm_private *priv = dev->dev_private;
@@ -136,6 +159,7 @@ static int omap_modeset_init(struct drm_device *dev)
        int num_mgrs = dss_feat_get_num_mgrs();
        int num_crtcs;
        int i, id = 0;
+       int ret;
 
        drm_mode_config_init(dev);
 
@@ -209,18 +233,13 @@ static int omap_modeset_init(struct drm_device *dev)
                 * allocated crtc, we create a new crtc for it
                 */
                if (!channel_used(dev, channel)) {
-                       struct drm_plane *plane;
-                       struct drm_crtc *crtc;
-
-                       plane = omap_plane_init(dev, id, true);
-                       crtc = omap_crtc_init(dev, plane, channel, id);
-
-                       BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
-                       priv->crtcs[id] = crtc;
-                       priv->num_crtcs++;
-
-                       priv->planes[id] = plane;
-                       priv->num_planes++;
+                       ret = omap_modeset_create_crtc(dev, id, channel);
+                       if (ret < 0) {
+                               dev_err(dev->dev,
+                                       "could not create CRTC (channel %u)\n",
+                                       channel);
+                               return ret;
+                       }
 
                        id++;
                }
@@ -234,26 +253,8 @@ static int omap_modeset_init(struct drm_device *dev)
 
                /* find a free manager for this crtc */
                for (i = 0; i < num_mgrs; i++) {
-                       if (!channel_used(dev, i)) {
-                               struct drm_plane *plane;
-                               struct drm_crtc *crtc;
-
-                               plane = omap_plane_init(dev, id, true);
-                               crtc = omap_crtc_init(dev, plane, i, id);
-
-                               BUG_ON(priv->num_crtcs >=
-                                       ARRAY_SIZE(priv->crtcs));
-
-                               priv->crtcs[id] = crtc;
-                               priv->num_crtcs++;
-
-                               priv->planes[id] = plane;
-                               priv->num_planes++;
-
+                       if (!channel_used(dev, i))
                                break;
-                       } else {
-                               continue;
-                       }
                }
 
                if (i == num_mgrs) {
@@ -261,13 +262,24 @@ static int omap_modeset_init(struct drm_device *dev)
                        dev_err(dev->dev, "no managers left for crtc\n");
                        return -ENOMEM;
                }
+
+               ret = omap_modeset_create_crtc(dev, id, i);
+               if (ret < 0) {
+                       dev_err(dev->dev,
+                               "could not create CRTC (channel %u)\n", i);
+                       return ret;
+               }
        }
 
        /*
         * Create normal planes for the remaining overlays:
         */
        for (; id < num_ovls; id++) {
-               struct drm_plane *plane = omap_plane_init(dev, id, false);
+               struct drm_plane *plane;
+
+               plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_OVERLAY);
+               if (IS_ERR(plane))
+                       return PTR_ERR(plane);
 
                BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
                priv->planes[priv->num_planes++] = plane;
@@ -286,14 +298,13 @@ static int omap_modeset_init(struct drm_device *dev)
                for (id = 0; id < priv->num_crtcs; id++) {
                        struct drm_crtc *crtc = priv->crtcs[id];
                        enum omap_channel crtc_channel;
-                       enum omap_dss_output_id supported_outputs;
 
                        crtc_channel = omap_crtc_channel(crtc);
-                       supported_outputs =
-                               dss_feat_get_supported_outputs(crtc_channel);
 
-                       if (supported_outputs & output->id)
+                       if (output->dispc_channel == crtc_channel) {
                                encoder->possible_crtcs |= (1 << id);
+                               break;
+                       }
                }
 
                omap_dss_put_device(output);
@@ -480,6 +491,7 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
 
        priv->wq = alloc_ordered_workqueue("omapdrm", 0);
 
+       spin_lock_init(&priv->list_lock);
        INIT_LIST_HEAD(&priv->obj_list);
 
        omap_gem_init(dev);
@@ -519,7 +531,8 @@ static int dev_unload(struct drm_device *dev)
 
        drm_kms_helper_poll_fini(dev);
 
-       omap_fbdev_free(dev);
+       if (priv->fbdev)
+               omap_fbdev_free(dev);
 
        /* flush crtcs so the fbs get released */
        for (i = 0; i < priv->num_crtcs; i++)
@@ -588,9 +601,11 @@ static void dev_lastclose(struct drm_device *dev)
                }
        }
 
-       ret = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
-       if (ret)
-               DBG("failed to restore crtc mode");
+       if (priv->fbdev) {
+               ret = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
+               if (ret)
+                       DBG("failed to restore crtc mode");
+       }
 }
 
 static void dev_preclose(struct drm_device *dev, struct drm_file *file)
@@ -610,74 +625,57 @@ static const struct vm_operations_struct omap_gem_vm_ops = {
 };
 
 static const struct file_operations omapdriver_fops = {
-               .owner = THIS_MODULE,
-               .open = drm_open,
-               .unlocked_ioctl = drm_ioctl,
-               .release = drm_release,
-               .mmap = omap_gem_mmap,
-               .poll = drm_poll,
-               .read = drm_read,
-               .llseek = noop_llseek,
+       .owner = THIS_MODULE,
+       .open = drm_open,
+       .unlocked_ioctl = drm_ioctl,
+       .release = drm_release,
+       .mmap = omap_gem_mmap,
+       .poll = drm_poll,
+       .read = drm_read,
+       .llseek = noop_llseek,
 };
 
 static struct drm_driver omap_drm_driver = {
-               .driver_features =
-                               DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
-               .load = dev_load,
-               .unload = dev_unload,
-               .open = dev_open,
-               .lastclose = dev_lastclose,
-               .preclose = dev_preclose,
-               .postclose = dev_postclose,
-               .set_busid = drm_platform_set_busid,
-               .get_vblank_counter = drm_vblank_count,
-               .enable_vblank = omap_irq_enable_vblank,
-               .disable_vblank = omap_irq_disable_vblank,
-               .irq_preinstall = omap_irq_preinstall,
-               .irq_postinstall = omap_irq_postinstall,
-               .irq_uninstall = omap_irq_uninstall,
-               .irq_handler = omap_irq_handler,
+       .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM
+                        | DRIVER_PRIME,
+       .load = dev_load,
+       .unload = dev_unload,
+       .open = dev_open,
+       .lastclose = dev_lastclose,
+       .preclose = dev_preclose,
+       .postclose = dev_postclose,
+       .set_busid = drm_platform_set_busid,
+       .get_vblank_counter = drm_vblank_count,
+       .enable_vblank = omap_irq_enable_vblank,
+       .disable_vblank = omap_irq_disable_vblank,
+       .irq_preinstall = omap_irq_preinstall,
+       .irq_postinstall = omap_irq_postinstall,
+       .irq_uninstall = omap_irq_uninstall,
+       .irq_handler = omap_irq_handler,
 #ifdef CONFIG_DEBUG_FS
-               .debugfs_init = omap_debugfs_init,
-               .debugfs_cleanup = omap_debugfs_cleanup,
+       .debugfs_init = omap_debugfs_init,
+       .debugfs_cleanup = omap_debugfs_cleanup,
 #endif
-               .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
-               .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
-               .gem_prime_export = omap_gem_prime_export,
-               .gem_prime_import = omap_gem_prime_import,
-               .gem_free_object = omap_gem_free_object,
-               .gem_vm_ops = &omap_gem_vm_ops,
-               .dumb_create = omap_gem_dumb_create,
-               .dumb_map_offset = omap_gem_dumb_map_offset,
-               .dumb_destroy = drm_gem_dumb_destroy,
-               .ioctls = ioctls,
-               .num_ioctls = DRM_OMAP_NUM_IOCTLS,
-               .fops = &omapdriver_fops,
-               .name = DRIVER_NAME,
-               .desc = DRIVER_DESC,
-               .date = DRIVER_DATE,
-               .major = DRIVER_MAJOR,
-               .minor = DRIVER_MINOR,
-               .patchlevel = DRIVER_PATCHLEVEL,
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export = omap_gem_prime_export,
+       .gem_prime_import = omap_gem_prime_import,
+       .gem_free_object = omap_gem_free_object,
+       .gem_vm_ops = &omap_gem_vm_ops,
+       .dumb_create = omap_gem_dumb_create,
+       .dumb_map_offset = omap_gem_dumb_map_offset,
+       .dumb_destroy = drm_gem_dumb_destroy,
+       .ioctls = ioctls,
+       .num_ioctls = DRM_OMAP_NUM_IOCTLS,
+       .fops = &omapdriver_fops,
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL,
 };
 
-static int pdev_suspend(struct platform_device *pDevice, pm_message_t state)
-{
-       DBG("");
-       return 0;
-}
-
-static int pdev_resume(struct platform_device *device)
-{
-       DBG("");
-       return 0;
-}
-
-static void pdev_shutdown(struct platform_device *device)
-{
-       DBG("");
-}
-
 static int pdev_probe(struct platform_device *device)
 {
        int r;
@@ -709,24 +707,35 @@ static int pdev_remove(struct platform_device *device)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static const struct dev_pm_ops omapdrm_pm_ops = {
-       .resume = omap_gem_resume,
-};
+#ifdef CONFIG_PM_SLEEP
+static int omap_drm_suspend(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+       drm_kms_helper_poll_disable(drm_dev);
+
+       return 0;
+}
+
+static int omap_drm_resume(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+       drm_kms_helper_poll_enable(drm_dev);
+
+       return omap_gem_resume(dev);
+}
 #endif
 
+static SIMPLE_DEV_PM_OPS(omapdrm_pm_ops, omap_drm_suspend, omap_drm_resume);
+
 static struct platform_driver pdev = {
-               .driver = {
-                       .name = DRIVER_NAME,
-#ifdef CONFIG_PM
-                       .pm = &omapdrm_pm_ops,
-#endif
-               },
-               .probe = pdev_probe,
-               .remove = pdev_remove,
-               .suspend = pdev_suspend,
-               .resume = pdev_resume,
-               .shutdown = pdev_shutdown,
+       .driver = {
+               .name = DRIVER_NAME,
+               .pm = &omapdrm_pm_ops,
+       },
+       .probe = pdev_probe,
+       .remove = pdev_remove,
 };
 
 static int __init omap_drm_init(void)
index 60e47b33c8017a788669bd604795438d63794648..b31c79f15aede8481af46d62e8342b59aaa62f4c 100644 (file)
@@ -105,6 +105,9 @@ struct omap_drm_private {
 
        struct workqueue_struct *wq;
 
+       /* lock for obj_list below */
+       spinlock_t list_lock;
+
        /* list of GEM objects: */
        struct list_head obj_list;
 
@@ -160,15 +163,15 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 void omap_crtc_flush(struct drm_crtc *crtc);
 
 struct drm_plane *omap_plane_init(struct drm_device *dev,
-               int plane_id, bool private_plane);
-int omap_plane_dpms(struct drm_plane *plane, int mode);
+               int id, enum drm_plane_type type);
+int omap_plane_set_enable(struct drm_plane *plane, bool enable);
 int omap_plane_mode_set(struct drm_plane *plane,
-               struct drm_crtc *crtc, struct drm_framebuffer *fb,
-               int crtc_x, int crtc_y,
-               unsigned int crtc_w, unsigned int crtc_h,
-               uint32_t src_x, uint32_t src_y,
-               uint32_t src_w, uint32_t src_h,
-               void (*fxn)(void *), void *arg);
+                       struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                       int crtc_x, int crtc_y,
+                       unsigned int crtc_w, unsigned int crtc_h,
+                       unsigned int src_x, unsigned int src_y,
+                       unsigned int src_w, unsigned int src_h,
+                       void (*fxn)(void *), void *arg);
 void omap_plane_install_properties(struct drm_plane *plane,
                struct drm_mode_object *obj);
 int omap_plane_set_property(struct drm_plane *plane,
@@ -186,8 +189,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
                struct drm_encoder *encoder);
 struct drm_encoder *omap_connector_attached_encoder(
                struct drm_connector *connector);
-void omap_connector_flush(struct drm_connector *connector,
-               int x, int y, int w, int h);
 bool omap_connector_get_hdmi_mode(struct drm_connector *connector);
 
 void copy_timings_omap_to_drm(struct drm_display_mode *mode,
@@ -208,8 +209,6 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
                struct omap_drm_window *win, struct omap_overlay_info *info);
 struct drm_connector *omap_framebuffer_get_next_connector(
                struct drm_framebuffer *fb, struct drm_connector *from);
-void omap_framebuffer_flush(struct drm_framebuffer *fb,
-               int x, int y, int w, int h);
 
 void omap_gem_init(struct drm_device *dev);
 void omap_gem_deinit(struct drm_device *dev);
index 2a5cacdc344b621fd182d3e8d053bbc0e227ac60..b2c1a29cc12b4601885da18f4f0cf230f7557f69 100644 (file)
@@ -86,6 +86,7 @@ struct plane {
 
 struct omap_framebuffer {
        struct drm_framebuffer base;
+       int pin_count;
        const struct format *format;
        struct plane planes[4];
 };
@@ -121,18 +122,6 @@ static int omap_framebuffer_dirty(struct drm_framebuffer *fb,
                struct drm_file *file_priv, unsigned flags, unsigned color,
                struct drm_clip_rect *clips, unsigned num_clips)
 {
-       int i;
-
-       drm_modeset_lock_all(fb->dev);
-
-       for (i = 0; i < num_clips; i++) {
-               omap_framebuffer_flush(fb, clips[i].x1, clips[i].y1,
-                                       clips[i].x2 - clips[i].x1,
-                                       clips[i].y2 - clips[i].y1);
-       }
-
-       drm_modeset_unlock_all(fb->dev);
-
        return 0;
 }
 
@@ -261,6 +250,11 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
        int ret, i, n = drm_format_num_planes(fb->pixel_format);
 
+       if (omap_fb->pin_count > 0) {
+               omap_fb->pin_count++;
+               return 0;
+       }
+
        for (i = 0; i < n; i++) {
                struct plane *plane = &omap_fb->planes[i];
                ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true);
@@ -269,6 +263,8 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
                omap_gem_dma_sync(plane->bo, DMA_TO_DEVICE);
        }
 
+       omap_fb->pin_count++;
+
        return 0;
 
 fail:
@@ -287,6 +283,11 @@ int omap_framebuffer_unpin(struct drm_framebuffer *fb)
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
        int ret, i, n = drm_format_num_planes(fb->pixel_format);
 
+       omap_fb->pin_count--;
+
+       if (omap_fb->pin_count > 0)
+               return 0;
+
        for (i = 0; i < n; i++) {
                struct plane *plane = &omap_fb->planes[i];
                ret = omap_gem_put_paddr(plane->bo);
@@ -336,34 +337,6 @@ struct drm_connector *omap_framebuffer_get_next_connector(
        return NULL;
 }
 
-/* flush an area of the framebuffer (in case of manual update display that
- * is not automatically flushed)
- */
-void omap_framebuffer_flush(struct drm_framebuffer *fb,
-               int x, int y, int w, int h)
-{
-       struct drm_connector *connector = NULL;
-
-       VERB("flush: %d,%d %dx%d, fb=%p", x, y, w, h, fb);
-
-       /* FIXME: This is racy - no protection against modeset config changes. */
-       while ((connector = omap_framebuffer_get_next_connector(fb, connector))) {
-               /* only consider connectors that are part of a chain */
-               if (connector->encoder && connector->encoder->crtc) {
-                       /* TODO: maybe this should propagate thru the crtc who
-                        * could do the coordinate translation..
-                        */
-                       struct drm_crtc *crtc = connector->encoder->crtc;
-                       int cx = max(0, x - crtc->x);
-                       int cy = max(0, y - crtc->y);
-                       int cw = w + (x - crtc->x) - cx;
-                       int ch = h + (y - crtc->y) - cy;
-
-                       omap_connector_flush(connector, cx, cy, cw, ch);
-               }
-       }
-}
-
 #ifdef CONFIG_DEBUG_FS
 void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
 {
@@ -407,7 +380,7 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
                struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
 {
-       struct omap_framebuffer *omap_fb;
+       struct omap_framebuffer *omap_fb = NULL;
        struct drm_framebuffer *fb = NULL;
        const struct format *format = NULL;
        int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format);
@@ -450,6 +423,14 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
                        goto fail;
                }
 
+               if (pitch % format->planes[i].stride_bpp != 0) {
+                       dev_err(dev->dev,
+                               "buffer pitch (%d bytes) is not a multiple of pixel size (%d bytes)\n",
+                               pitch, format->planes[i].stride_bpp);
+                       ret = -EINVAL;
+                       goto fail;
+               }
+
                size = pitch * mode_cmd->height / format->planes[i].sub_y;
 
                if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) {
@@ -478,8 +459,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
        return fb;
 
 fail:
-       if (fb)
-               omap_framebuffer_destroy(fb);
+       kfree(omap_fb);
 
        return ERR_PTR(ret);
 }
index d292d24b3a6e673977b9c5f5ebc353bc6c5c18b7..950cd33890922bb8881a63583190322487814f3a 100644 (file)
@@ -42,42 +42,8 @@ struct omap_fbdev {
        struct work_struct work;
 };
 
-static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h);
 static struct drm_fb_helper *get_fb(struct fb_info *fbi);
 
-static ssize_t omap_fbdev_write(struct fb_info *fbi, const char __user *buf,
-               size_t count, loff_t *ppos)
-{
-       ssize_t res;
-
-       res = fb_sys_write(fbi, buf, count, ppos);
-       omap_fbdev_flush(fbi, 0, 0, fbi->var.xres, fbi->var.yres);
-
-       return res;
-}
-
-static void omap_fbdev_fillrect(struct fb_info *fbi,
-               const struct fb_fillrect *rect)
-{
-       sys_fillrect(fbi, rect);
-       omap_fbdev_flush(fbi, rect->dx, rect->dy, rect->width, rect->height);
-}
-
-static void omap_fbdev_copyarea(struct fb_info *fbi,
-               const struct fb_copyarea *area)
-{
-       sys_copyarea(fbi, area);
-       omap_fbdev_flush(fbi, area->dx, area->dy, area->width, area->height);
-}
-
-static void omap_fbdev_imageblit(struct fb_info *fbi,
-               const struct fb_image *image)
-{
-       sys_imageblit(fbi, image);
-       omap_fbdev_flush(fbi, image->dx, image->dy,
-                               image->width, image->height);
-}
-
 static void pan_worker(struct work_struct *work)
 {
        struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work);
@@ -121,10 +87,10 @@ static struct fb_ops omap_fb_ops = {
         * basic fbdev ops which write to the framebuffer
         */
        .fb_read = fb_sys_read,
-       .fb_write = omap_fbdev_write,
-       .fb_fillrect = omap_fbdev_fillrect,
-       .fb_copyarea = omap_fbdev_copyarea,
-       .fb_imageblit = omap_fbdev_imageblit,
+       .fb_write = fb_sys_write,
+       .fb_fillrect = sys_fillrect,
+       .fb_copyarea = sys_copyarea,
+       .fb_imageblit = sys_imageblit,
 
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = drm_fb_helper_set_par,
@@ -294,21 +260,6 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi)
        return fbi->par;
 }
 
-/* flush an area of the framebuffer (in case of manual update display that
- * is not automatically flushed)
- */
-static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h)
-{
-       struct drm_fb_helper *helper = get_fb(fbi);
-
-       if (!helper)
-               return;
-
-       VERB("flush fbdev: %d,%d %dx%d, fbi=%p", x, y, w, h, fbi);
-
-       omap_framebuffer_flush(helper->fb, x, y, w, h);
-}
-
 /* initialize fbdev helper */
 struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev)
 {
index aeb91ed653c9f8d2e410a6b95ed7e194168ef508..e9718b99a8a9f022bdbc2501e9e1005270bc1f6a 100644 (file)
@@ -828,6 +828,7 @@ int omap_gem_put_paddr(struct drm_gem_object *obj)
                                dev_err(obj->dev->dev,
                                        "could not release unmap: %d\n", ret);
                        }
+                       omap_obj->paddr = 0;
                        omap_obj->block = NULL;
                }
        }
@@ -1272,13 +1273,16 @@ unlock:
 void omap_gem_free_object(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
+       struct omap_drm_private *priv = dev->dev_private;
        struct omap_gem_object *omap_obj = to_omap_bo(obj);
 
        evict(obj);
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
+       spin_lock(&priv->list_lock);
        list_del(&omap_obj->mm_list);
+       spin_unlock(&priv->list_lock);
 
        drm_gem_free_mmap_offset(obj);
 
@@ -1358,8 +1362,8 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
                /* currently don't allow cached buffers.. there is some caching
                 * stuff that needs to be handled better
                 */
-               flags &= ~(OMAP_BO_CACHED|OMAP_BO_UNCACHED);
-               flags |= OMAP_BO_WC;
+               flags &= ~(OMAP_BO_CACHED|OMAP_BO_WC|OMAP_BO_UNCACHED);
+               flags |= tiler_get_cpu_cache_flags();
 
                /* align dimensions to slot boundaries... */
                tiler_align(gem2fmt(flags),
@@ -1376,7 +1380,9 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
        if (!omap_obj)
                goto fail;
 
+       spin_lock(&priv->list_lock);
        list_add(&omap_obj->mm_list, &priv->obj_list);
+       spin_unlock(&priv->list_lock);
 
        obj = &omap_obj->base;
 
index a2dbfb1737b4583bf5d1b1b82220ee15185ccce8..b46dabd9faf75690c6782b20a7dd0b1c501bc160 100644 (file)
@@ -156,16 +156,16 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
 }
 
 static struct dma_buf_ops omap_dmabuf_ops = {
-               .map_dma_buf = omap_gem_map_dma_buf,
-               .unmap_dma_buf = omap_gem_unmap_dma_buf,
-               .release = omap_gem_dmabuf_release,
-               .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
-               .end_cpu_access = omap_gem_dmabuf_end_cpu_access,
-               .kmap_atomic = omap_gem_dmabuf_kmap_atomic,
-               .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic,
-               .kmap = omap_gem_dmabuf_kmap,
-               .kunmap = omap_gem_dmabuf_kunmap,
-               .mmap = omap_gem_dmabuf_mmap,
+       .map_dma_buf = omap_gem_map_dma_buf,
+       .unmap_dma_buf = omap_gem_unmap_dma_buf,
+       .release = omap_gem_dmabuf_release,
+       .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
+       .end_cpu_access = omap_gem_dmabuf_end_cpu_access,
+       .kmap_atomic = omap_gem_dmabuf_kmap_atomic,
+       .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic,
+       .kmap = omap_gem_dmabuf_kmap,
+       .kunmap = omap_gem_dmabuf_kunmap,
+       .mmap = omap_gem_dmabuf_mmap,
 };
 
 struct dma_buf *omap_gem_prime_export(struct drm_device *dev,
index f035d2bceae7db358427c689b3a1fdd6cde28334..3eb097efc488476e80b691ef4c6e305520b8186e 100644 (file)
@@ -34,7 +34,7 @@ static void omap_irq_update(struct drm_device *dev)
        struct omap_drm_irq *irq;
        uint32_t irqmask = priv->vblank_mask;
 
-       BUG_ON(!spin_is_locked(&list_lock));
+       assert_spin_locked(&list_lock);
 
        list_for_each_entry(irq, &priv->irq_list, node)
                irqmask |= irq->irqmask;
index ee8e2b3a117ef59c183bd4cd63075ea565be98c1..1c6b63f394741595f110adce51c56188f03787ba 100644 (file)
@@ -65,12 +65,16 @@ struct omap_plane {
        struct callback apply_done_cb;
 };
 
-static void unpin_worker(struct drm_flip_work *work, void *val)
+static void omap_plane_unpin_worker(struct drm_flip_work *work, void *val)
 {
        struct omap_plane *omap_plane =
                        container_of(work, struct omap_plane, unpin_work);
        struct drm_device *dev = omap_plane->base.dev;
 
+       /*
+        * omap_framebuffer_pin/unpin are always called from priv->wq,
+        * so there's no need for locking here.
+        */
        omap_framebuffer_unpin(val);
        mutex_lock(&dev->mode_config.mutex);
        drm_framebuffer_unreference(val);
@@ -78,7 +82,8 @@ static void unpin_worker(struct drm_flip_work *work, void *val)
 }
 
 /* update which fb (if any) is pinned for scanout */
-static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
+static int omap_plane_update_pin(struct drm_plane *plane,
+                                struct drm_framebuffer *fb)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
        struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb;
@@ -121,13 +126,12 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
        struct drm_crtc *crtc = plane->crtc;
        enum omap_channel channel;
        bool enabled = omap_plane->enabled && crtc;
-       bool ilace, replication;
        int ret;
 
        DBG("%s, enabled=%d", omap_plane->name, enabled);
 
        /* if fb has changed, pin new fb: */
-       update_pin(plane, enabled ? plane->fb : NULL);
+       omap_plane_update_pin(plane, enabled ? plane->fb : NULL);
 
        if (!enabled) {
                dispc_ovl_enable(omap_plane->id, false);
@@ -145,20 +149,17 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
        DBG("%d,%d %pad %pad", info->pos_x, info->pos_y,
                        &info->paddr, &info->p_uv_addr);
 
-       /* TODO: */
-       ilace = false;
-       replication = false;
+       dispc_ovl_set_channel_out(omap_plane->id, channel);
 
        /* and finally, update omapdss: */
-       ret = dispc_ovl_setup(omap_plane->id, info,
-                       replication, omap_crtc_timings(crtc), false);
+       ret = dispc_ovl_setup(omap_plane->id, info, false,
+                             omap_crtc_timings(crtc), false);
        if (ret) {
                dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
                return;
        }
 
        dispc_ovl_enable(omap_plane->id, true);
-       dispc_ovl_set_channel_out(omap_plane->id, channel);
 }
 
 static void omap_plane_post_apply(struct omap_drm_apply *apply)
@@ -167,7 +168,6 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
                        container_of(apply, struct omap_plane, apply);
        struct drm_plane *plane = &omap_plane->base;
        struct omap_drm_private *priv = plane->dev->dev_private;
-       struct omap_overlay_info *info = &omap_plane->info;
        struct callback cb;
 
        cb = omap_plane->apply_done_cb;
@@ -177,14 +177,9 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
 
        if (cb.fxn)
                cb.fxn(cb.arg);
-
-       if (omap_plane->enabled) {
-               omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
-                               info->out_width, info->out_height);
-       }
 }
 
-static int apply(struct drm_plane *plane)
+static int omap_plane_apply(struct drm_plane *plane)
 {
        if (plane->crtc) {
                struct omap_plane *omap_plane = to_omap_plane(plane);
@@ -194,12 +189,12 @@ static int apply(struct drm_plane *plane)
 }
 
 int omap_plane_mode_set(struct drm_plane *plane,
-               struct drm_crtc *crtc, struct drm_framebuffer *fb,
-               int crtc_x, int crtc_y,
-               unsigned int crtc_w, unsigned int crtc_h,
-               uint32_t src_x, uint32_t src_y,
-               uint32_t src_w, uint32_t src_h,
-               void (*fxn)(void *), void *arg)
+                       struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                       int crtc_x, int crtc_y,
+                       unsigned int crtc_w, unsigned int crtc_h,
+                       unsigned int src_x, unsigned int src_y,
+                       unsigned int src_w, unsigned int src_h,
+                       void (*fxn)(void *), void *arg)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
        struct omap_drm_window *win = &omap_plane->win;
@@ -209,11 +204,10 @@ int omap_plane_mode_set(struct drm_plane *plane,
        win->crtc_w = crtc_w;
        win->crtc_h = crtc_h;
 
-       /* src values are in Q16 fixed point, convert to integer: */
-       win->src_x = src_x >> 16;
-       win->src_y = src_y >> 16;
-       win->src_w = src_w >> 16;
-       win->src_h = src_h >> 16;
+       win->src_x = src_x;
+       win->src_y = src_y;
+       win->src_w = src_w;
+       win->src_h = src_h;
 
        if (fxn) {
                /* omap_crtc should ensure that a new page flip
@@ -225,15 +219,7 @@ int omap_plane_mode_set(struct drm_plane *plane,
                omap_plane->apply_done_cb.arg = arg;
        }
 
-       if (plane->fb)
-               drm_framebuffer_unreference(plane->fb);
-
-       drm_framebuffer_reference(fb);
-
-       plane->fb = fb;
-       plane->crtc = crtc;
-
-       return apply(plane);
+       return omap_plane_apply(plane);
 }
 
 static int omap_plane_update(struct drm_plane *plane,
@@ -254,17 +240,29 @@ static int omap_plane_update(struct drm_plane *plane,
                break;
        }
 
+       /*
+        * We don't need to take a reference to the framebuffer as the DRM core
+        * has already done so for the purpose of setting plane->fb.
+        */
+       plane->fb = fb;
+       plane->crtc = crtc;
+
+       /* src values are in Q16 fixed point, convert to integer: */
        return omap_plane_mode_set(plane, crtc, fb,
                        crtc_x, crtc_y, crtc_w, crtc_h,
-                       src_x, src_y, src_w, src_h,
+                       src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
                        NULL, NULL);
 }
 
 static int omap_plane_disable(struct drm_plane *plane)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
+
        omap_plane->win.rotation = BIT(DRM_ROTATE_0);
-       return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+       omap_plane->info.zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
+                               ? 0 : omap_plane->id;
+
+       return omap_plane_set_enable(plane, false);
 }
 
 static void omap_plane_destroy(struct drm_plane *plane)
@@ -275,7 +273,6 @@ static void omap_plane_destroy(struct drm_plane *plane)
 
        omap_irq_unregister(plane->dev, &omap_plane->error_irq);
 
-       omap_plane_disable(plane);
        drm_plane_cleanup(plane);
 
        drm_flip_work_cleanup(&omap_plane->unpin_work);
@@ -283,18 +280,15 @@ static void omap_plane_destroy(struct drm_plane *plane)
        kfree(omap_plane);
 }
 
-int omap_plane_dpms(struct drm_plane *plane, int mode)
+int omap_plane_set_enable(struct drm_plane *plane, bool enable)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
-       bool enabled = (mode == DRM_MODE_DPMS_ON);
-       int ret = 0;
 
-       if (enabled != omap_plane->enabled) {
-               omap_plane->enabled = enabled;
-               ret = apply(plane);
-       }
+       if (enable == omap_plane->enabled)
+               return 0;
 
-       return ret;
+       omap_plane->enabled = enable;
+       return omap_plane_apply(plane);
 }
 
 /* helper to install properties which are common to planes and crtcs */
@@ -342,61 +336,63 @@ int omap_plane_set_property(struct drm_plane *plane,
        if (property == priv->rotation_prop) {
                DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
                omap_plane->win.rotation = val;
-               ret = apply(plane);
+               ret = omap_plane_apply(plane);
        } else if (property == priv->zorder_prop) {
                DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
                omap_plane->info.zorder = val;
-               ret = apply(plane);
+               ret = omap_plane_apply(plane);
        }
 
        return ret;
 }
 
 static const struct drm_plane_funcs omap_plane_funcs = {
-               .update_plane = omap_plane_update,
-               .disable_plane = omap_plane_disable,
-               .destroy = omap_plane_destroy,
-               .set_property = omap_plane_set_property,
+       .update_plane = omap_plane_update,
+       .disable_plane = omap_plane_disable,
+       .destroy = omap_plane_destroy,
+       .set_property = omap_plane_set_property,
 };
 
 static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
 {
        struct omap_plane *omap_plane =
                        container_of(irq, struct omap_plane, error_irq);
-       DRM_ERROR("%s: errors: %08x\n", omap_plane->name, irqstatus);
+       DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name,
+               irqstatus);
 }
 
 static const char *plane_names[] = {
-               [OMAP_DSS_GFX] = "gfx",
-               [OMAP_DSS_VIDEO1] = "vid1",
-               [OMAP_DSS_VIDEO2] = "vid2",
-               [OMAP_DSS_VIDEO3] = "vid3",
+       [OMAP_DSS_GFX] = "gfx",
+       [OMAP_DSS_VIDEO1] = "vid1",
+       [OMAP_DSS_VIDEO2] = "vid2",
+       [OMAP_DSS_VIDEO3] = "vid3",
 };
 
 static const uint32_t error_irqs[] = {
-               [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
-               [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
-               [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
-               [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
+       [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
+       [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
+       [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
+       [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
 };
 
 /* initialize plane */
 struct drm_plane *omap_plane_init(struct drm_device *dev,
-               int id, bool private_plane)
+               int id, enum drm_plane_type type)
 {
        struct omap_drm_private *priv = dev->dev_private;
-       struct drm_plane *plane = NULL;
+       struct drm_plane *plane;
        struct omap_plane *omap_plane;
        struct omap_overlay_info *info;
+       int ret;
 
-       DBG("%s: priv=%d", plane_names[id], private_plane);
+       DBG("%s: type=%d", plane_names[id], type);
 
        omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
        if (!omap_plane)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        drm_flip_work_init(&omap_plane->unpin_work,
-                       "unpin", unpin_worker);
+                       "unpin", omap_plane_unpin_worker);
 
        omap_plane->nformats = omap_framebuffer_get_formats(
                        omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
@@ -413,8 +409,11 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
        omap_plane->error_irq.irq = omap_plane_error_irq;
        omap_irq_register(dev, &omap_plane->error_irq);
 
-       drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs,
-                       omap_plane->formats, omap_plane->nformats, private_plane);
+       ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1,
+                                      &omap_plane_funcs, omap_plane->formats,
+                                      omap_plane->nformats, type);
+       if (ret < 0)
+               goto error;
 
        omap_plane_install_properties(plane, &plane->base);
 
@@ -432,10 +431,15 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
         * TODO add ioctl to give userspace an API to change this.. this
         * will come in a subsequent patch.
         */
-       if (private_plane)
+       if (type == DRM_PLANE_TYPE_PRIMARY)
                omap_plane->info.zorder = 0;
        else
                omap_plane->info.zorder = id;
 
        return plane;
+
+error:
+       omap_irq_unregister(plane->dev, &omap_plane->error_irq);
+       kfree(omap_plane);
+       return NULL;
 }
index 4605633e253b1b36a6cde19f4df2d9ff9db0b0c6..dea53e36a2ef3aa77fe5d0e68a2864db619b85c5 100644 (file)
@@ -81,7 +81,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
        rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
        trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
        ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o \
-       radeon_sync.o radeon_audio.o
+       radeon_sync.o radeon_audio.o radeon_dp_auxch.o radeon_dp_mst.o
 
 radeon-$(CONFIG_MMU_NOTIFIER) += radeon_mn.o
 
index ed644a4f6f57c4254349c3881a16955cd42cbc05..dac78ad24b31558aa53d917fb802865b6a122b61 100644 (file)
@@ -330,8 +330,10 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
                misc |= ATOM_COMPOSITESYNC;
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                misc |= ATOM_INTERLACE;
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
                misc |= ATOM_DOUBLE_CLOCK_MODE;
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
 
        args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
        args.ucCRTC = radeon_crtc->crtc_id;
@@ -374,8 +376,10 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc,
                misc |= ATOM_COMPOSITESYNC;
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                misc |= ATOM_INTERLACE;
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
                misc |= ATOM_DOUBLE_CLOCK_MODE;
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
 
        args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
        args.ucCRTC = radeon_crtc->crtc_id;
@@ -606,6 +610,13 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                }
        }
 
+       if (radeon_encoder->is_mst_encoder) {
+               struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv;
+               struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv;
+
+               dp_clock = dig_connector->dp_clock;
+       }
+
        /* use recommended ref_div for ss */
        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
                if (radeon_crtc->ss_enabled) {
@@ -952,7 +963,9 @@ static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_
        radeon_crtc->bpc = 8;
        radeon_crtc->ss_enabled = false;
 
-       if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
+       if (radeon_encoder->is_mst_encoder) {
+               radeon_dp_mst_prepare_pll(crtc, mode);
+       } else if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
            (radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
                struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                struct drm_connector *connector =
@@ -1405,6 +1418,9 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
               (x << 16) | y);
        viewport_w = crtc->mode.hdisplay;
        viewport_h = (crtc->mode.vdisplay + 1) & ~1;
+       if ((rdev->family >= CHIP_BONAIRE) &&
+           (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE))
+               viewport_h *= 2;
        WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
               (viewport_w << 16) | viewport_h);
 
@@ -2066,6 +2082,12 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
                radeon_crtc->connector = NULL;
                return false;
        }
+       if (radeon_crtc->encoder) {
+               struct radeon_encoder *radeon_encoder =
+                       to_radeon_encoder(radeon_crtc->encoder);
+
+               radeon_crtc->output_csc = radeon_encoder->output_csc;
+       }
        if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
                return false;
        if (!atombios_crtc_prepare_pll(crtc, adjusted_mode))
index 5bf825dfaa098ec6b6ad8f479856ce676f51ba21..3e3290c203c625d781f7dfacc13977c50c54d34b 100644 (file)
@@ -158,7 +158,7 @@ done:
 #define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)
 
 static ssize_t
-radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
+radeon_dp_aux_transfer_atom(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 {
        struct radeon_i2c_chan *chan =
                container_of(aux, struct radeon_i2c_chan, aux);
@@ -178,6 +178,13 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        switch (msg->request & ~DP_AUX_I2C_MOT) {
        case DP_AUX_NATIVE_WRITE:
        case DP_AUX_I2C_WRITE:
+               /* The atom implementation only supports writes with a max payload of
+                * 12 bytes since it uses 4 bits for the total count (header + payload)
+                * in the parameter space.  The atom interface supports 16 byte
+                * payloads for reads. The hw itself supports up to 16 bytes of payload.
+                */
+               if (WARN_ON_ONCE(msg->size > 12))
+                       return -E2BIG;
                /* tx_size needs to be 4 even for bare address packets since the atom
                 * table needs the info in tx_buf[3].
                 */
@@ -219,11 +226,20 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 
 void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
 {
+       struct drm_device *dev = radeon_connector->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
        int ret;
 
        radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd;
        radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev;
-       radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer;
+       if (ASIC_IS_DCE5(rdev)) {
+               if (radeon_auxch)
+                       radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_native;
+               else
+                       radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_atom;
+       } else {
+               radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_atom;
+       }
 
        ret = drm_dp_aux_register(&radeon_connector->ddc_bus->aux);
        if (!ret)
@@ -294,8 +310,8 @@ static int dp_get_max_dp_pix_clock(int link_rate,
 
 /***** radeon specific DP functions *****/
 
-static int radeon_dp_get_max_link_rate(struct drm_connector *connector,
-                                      u8 dpcd[DP_DPCD_SIZE])
+int radeon_dp_get_max_link_rate(struct drm_connector *connector,
+                               u8 dpcd[DP_DPCD_SIZE])
 {
        int max_link_rate;
 
index 7c9df1eac065948df99491b3819427e32ad425d7..f57c1ab617bc877b4576e828ee203381626b177c 100644 (file)
@@ -671,7 +671,15 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        struct drm_connector *connector;
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *dig_connector;
+       struct radeon_encoder_atom_dig *dig_enc;
 
+       if (radeon_encoder_is_digital(encoder)) {
+               dig_enc = radeon_encoder->enc_priv;
+               if (dig_enc->active_mst_links)
+                       return ATOM_ENCODER_MODE_DP_MST;
+       }
+       if (radeon_encoder->is_mst_encoder || radeon_encoder->offset)
+               return ATOM_ENCODER_MODE_DP_MST;
        /* dp bridges are always DP */
        if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)
                return ATOM_ENCODER_MODE_DP;
@@ -731,7 +739,9 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                dig_connector = radeon_connector->con_priv;
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
-                       if (radeon_audio != 0 && ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
+                       if (radeon_audio != 0 &&
+                           drm_detect_monitor_audio(radeon_connector_edid(connector)) &&
+                           ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
                                return ATOM_ENCODER_MODE_DP_AUDIO;
                        return ATOM_ENCODER_MODE_DP;
                } else if (radeon_audio != 0) {
@@ -747,7 +757,9 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                }
                break;
        case DRM_MODE_CONNECTOR_eDP:
-               if (radeon_audio != 0 && ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
+               if (radeon_audio != 0 &&
+                   drm_detect_monitor_audio(radeon_connector_edid(connector)) &&
+                   ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
                        return ATOM_ENCODER_MODE_DP_AUDIO;
                return ATOM_ENCODER_MODE_DP;
        case DRM_MODE_CONNECTOR_DVIA:
@@ -819,7 +831,7 @@ union dig_encoder_control {
 };
 
 void
-atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
+atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -916,7 +928,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
 
                        if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000))
                                args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
-                       args.v3.acConfig.ucDigSel = dig->dig_encoder;
+                       if (enc_override != -1)
+                               args.v3.acConfig.ucDigSel = enc_override;
+                       else
+                               args.v3.acConfig.ucDigSel = dig->dig_encoder;
                        args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder);
                        break;
                case 4:
@@ -944,7 +959,11 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
                                else
                                        args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ;
                        }
-                       args.v4.acConfig.ucDigSel = dig->dig_encoder;
+
+                       if (enc_override != -1)
+                               args.v4.acConfig.ucDigSel = enc_override;
+                       else
+                               args.v4.acConfig.ucDigSel = dig->dig_encoder;
                        args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
                        if (hpd_id == RADEON_HPD_NONE)
                                args.v4.ucHPD_ID = 0;
@@ -965,6 +984,12 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
 
 }
 
+void
+atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
+{
+       atombios_dig_encoder_setup2(encoder, action, panel_mode, -1);
+}
+
 union dig_transmitter_control {
        DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
        DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
@@ -974,7 +999,7 @@ union dig_transmitter_control {
 };
 
 void
-atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
+atombios_dig_transmitter_setup2(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set, int fe)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -1324,7 +1349,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                                args.v5.asConfig.ucHPDSel = 0;
                        else
                                args.v5.asConfig.ucHPDSel = hpd_id + 1;
-                       args.v5.ucDigEncoderSel = 1 << dig_encoder;
+                       args.v5.ucDigEncoderSel = (fe != -1) ? (1 << fe) : (1 << dig_encoder);
                        args.v5.ucDPLaneSet = lane_set;
                        break;
                default:
@@ -1340,6 +1365,12 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+void
+atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
+{
+       atombios_dig_transmitter_setup2(encoder, action, lane_num, lane_set, -1);
+}
+
 bool
 atombios_set_edp_panel_power(struct drm_connector *connector, int action)
 {
@@ -1622,7 +1653,6 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
        struct radeon_connector *radeon_connector = NULL;
        struct radeon_connector_atom_dig *radeon_dig_connector = NULL;
        bool travis_quirk = false;
-       int encoder_mode;
 
        if (connector) {
                radeon_connector = to_radeon_connector(connector);
@@ -1684,6 +1714,11 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
        case DRM_MODE_DPMS_OFF:
+
+               /* don't power off encoders with active MST links */
+               if (dig->active_mst_links)
+                       return;
+
                if (ASIC_IS_DCE4(rdev)) {
                        if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector)
                                atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
@@ -1718,11 +1753,6 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
                }
                break;
        }
-
-       encoder_mode = atombios_get_encoder_mode(encoder);
-       if (radeon_audio != 0 &&
-               (encoder_mode == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(encoder_mode)))
-               radeon_audio_dpms(encoder, mode);
 }
 
 static void
@@ -1731,10 +1761,19 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       int encoder_mode = atombios_get_encoder_mode(encoder);
 
        DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
                  radeon_encoder->encoder_id, mode, radeon_encoder->devices,
                  radeon_encoder->active_device);
+
+       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)))))
+               radeon_audio_dpms(encoder, mode);
+
        switch (radeon_encoder->encoder_id) {
        case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
@@ -1948,6 +1987,53 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
        radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
 }
 
+void
+atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder, int fe)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
+       uint8_t frev, crev;
+       union crtc_source_param args;
+
+       memset(&args, 0, sizeof(args));
+
+       if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+               return;
+
+       if (frev != 1 && crev != 2)
+               DRM_ERROR("Unknown table for MST %d, %d\n", frev, crev);
+
+       args.v2.ucCRTC = radeon_crtc->crtc_id;
+       args.v2.ucEncodeMode = ATOM_ENCODER_MODE_DP_MST;
+
+       switch (fe) {
+       case 0:
+               args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+               break;
+       case 1:
+               args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
+               break;
+       case 2:
+               args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
+               break;
+       case 3:
+               args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
+               break;
+       case 4:
+               args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
+               break;
+       case 5:
+               args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
+               break;
+       case 6:
+               args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
+               break;
+       }
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
 static void
 atombios_apply_encoder_quirks(struct drm_encoder *encoder,
                              struct drm_display_mode *mode)
@@ -1996,7 +2082,14 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
        }
 }
 
-static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
+void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx)
+{
+       if (enc_idx < 0)
+               return;
+       rdev->mode_info.active_encoders &= ~(1 << enc_idx);
+}
+
+int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -2005,71 +2098,79 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        struct drm_encoder *test_encoder;
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
        uint32_t dig_enc_in_use = 0;
+       int enc_idx = -1;
 
+       if (fe_idx >= 0) {
+               enc_idx = fe_idx;
+               goto assigned;
+       }
        if (ASIC_IS_DCE6(rdev)) {
                /* DCE6 */
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                        if (dig->linkb)
-                               return 1;
+                               enc_idx = 1;
                        else
-                               return 0;
+                               enc_idx = 0;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
                        if (dig->linkb)
-                               return 3;
+                               enc_idx = 3;
                        else
-                               return 2;
+                               enc_idx = 2;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
                        if (dig->linkb)
-                               return 5;
+                               enc_idx = 5;
                        else
-                               return 4;
+                               enc_idx = 4;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
-                       return 6;
+                       enc_idx = 6;
                        break;
                }
+               goto assigned;
        } else if (ASIC_IS_DCE4(rdev)) {
                /* DCE4/5 */
                if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) {
                        /* ontario follows DCE4 */
                        if (rdev->family == CHIP_PALM) {
                                if (dig->linkb)
-                                       return 1;
+                                       enc_idx = 1;
                                else
-                                       return 0;
+                                       enc_idx = 0;
                        } else
                                /* llano follows DCE3.2 */
-                               return radeon_crtc->crtc_id;
+                               enc_idx = radeon_crtc->crtc_id;
                } else {
                        switch (radeon_encoder->encoder_id) {
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                                if (dig->linkb)
-                                       return 1;
+                                       enc_idx = 1;
                                else
-                                       return 0;
+                                       enc_idx = 0;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
                                if (dig->linkb)
-                                       return 3;
+                                       enc_idx = 3;
                                else
-                                       return 2;
+                                       enc_idx = 2;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
                                if (dig->linkb)
-                                       return 5;
+                                       enc_idx = 5;
                                else
-                                       return 4;
+                                       enc_idx = 4;
                                break;
                        }
                }
+               goto assigned;
        }
 
        /* on DCE32 and encoder can driver any block so just crtc id */
        if (ASIC_IS_DCE32(rdev)) {
-               return radeon_crtc->crtc_id;
+               enc_idx = radeon_crtc->crtc_id;
+               goto assigned;
        }
 
        /* on DCE3 - LVTMA can only be driven by DIGB */
@@ -2097,6 +2198,17 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        if (!(dig_enc_in_use & 1))
                return 0;
        return 1;
+
+assigned:
+       if (enc_idx == -1) {
+               DRM_ERROR("Got encoder index incorrect - returning 0\n");
+               return 0;
+       }
+       if (rdev->mode_info.active_encoders & (1 << enc_idx)) {
+               DRM_ERROR("chosen encoder in use %d\n", enc_idx);
+       }
+       rdev->mode_info.active_encoders |= (1 << enc_idx);
+       return enc_idx;
 }
 
 /* This only needs to be called once at startup */
@@ -2136,6 +2248,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        int encoder_mode;
 
        radeon_encoder->pixel_clock = adjusted_mode->clock;
@@ -2163,10 +2276,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
                /* handled in dpms */
-               encoder_mode = atombios_get_encoder_mode(encoder);
-               if (radeon_audio != 0 &&
-                       (encoder_mode == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(encoder_mode)))
-                       radeon_audio_mode_set(encoder, adjusted_mode);
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DDI:
        case ENCODER_OBJECT_ID_INTERNAL_DVO1:
@@ -2188,6 +2297,13 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        atombios_apply_encoder_quirks(encoder, adjusted_mode);
+
+       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)))))
+               radeon_audio_mode_set(encoder, adjusted_mode);
 }
 
 static bool
@@ -2351,7 +2467,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
             ENCODER_OBJECT_ID_NONE)) {
                struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                if (dig) {
-                       dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
+                       if (dig->dig_encoder >= 0)
+                               radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
+                       dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1);
                        if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) {
                                if (rdev->family >= CHIP_R600)
                                        dig->afmt = rdev->mode_info.afmt[dig->dig_encoder];
@@ -2453,10 +2571,18 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
 
 disable_done:
        if (radeon_encoder_is_digital(encoder)) {
-               dig = radeon_encoder->enc_priv;
-               dig->dig_encoder = -1;
-       }
-       radeon_encoder->active_device = 0;
+               if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
+                       if (rdev->asic->display.hdmi_enable)
+                               radeon_hdmi_enable(rdev, encoder, false);
+               }
+               if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) {
+                       dig = radeon_encoder->enc_priv;
+                       radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
+                       dig->dig_encoder = -1;
+                       radeon_encoder->active_device = 0;
+               }
+       } else
+               radeon_encoder->active_device = 0;
 }
 
 /* these are handled by the primary encoders */
index db08f17be76b47ea0d312e57ff292f5d83eba221..69556f5e247e7f1b78a19da8201c970a98fd462d 100644 (file)
@@ -2751,13 +2751,54 @@ void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                else /* current_index == 2 */
                        pl = &ps->high;
                seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
-               if (rdev->family >= CHIP_CEDAR) {
-                       seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n",
-                                  current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
-               } else {
-                       seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u\n",
-                                  current_index, pl->sclk, pl->mclk, pl->vddc);
-               }
+               seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+                          current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+       }
+}
+
+u32 btc_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->sclk;
+       }
+}
+
+u32 btc_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->mclk;
        }
 }
 
index bcd2f1fe803fa9e35fc654625c496d98efe29f69..8730562323a8b77d0dd86ec399207806a6807ddc 100644 (file)
@@ -5922,6 +5922,20 @@ void ci_dpm_print_power_state(struct radeon_device *rdev,
        r600_dpm_print_ps_status(rdev, rps);
 }
 
+u32 ci_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       u32 sclk = ci_get_average_sclk_freq(rdev);
+
+       return sclk;
+}
+
+u32 ci_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       u32 mclk = ci_get_average_mclk_freq(rdev);
+
+       return mclk;
+}
+
 u32 ci_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
index e6a4ba236c703dc812d8bc57035408cb9ac5821f..28faea9996f9e111d6b35e547587025aa93c3089 100644 (file)
@@ -141,6 +141,39 @@ static void cik_fini_cg(struct radeon_device *rdev);
 static void cik_enable_gui_idle_interrupt(struct radeon_device *rdev,
                                          bool enable);
 
+/**
+ * cik_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int cik_get_allowed_info_register(struct radeon_device *rdev,
+                                 u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS2:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case GRBM_STATUS_SE2:
+       case GRBM_STATUS_SE3:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case (SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET):
+       case (SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET):
+       case UVD_STATUS:
+       /* TODO VCE */
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 /* get temperature in millidegrees */
 int ci_get_temp(struct radeon_device *rdev)
 {
@@ -3613,6 +3646,8 @@ static void cik_gpu_init(struct radeon_device *rdev)
        }
 
        WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+       WREG32(SRBM_INT_CNTL, 0x1);
+       WREG32(SRBM_INT_ACK, 0x1);
 
        WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
 
@@ -7230,6 +7265,8 @@ static void cik_disable_interrupt_state(struct radeon_device *rdev)
        WREG32(CP_ME2_PIPE3_INT_CNTL, 0);
        /* grbm */
        WREG32(GRBM_INT_CNTL, 0);
+       /* SRBM */
+       WREG32(SRBM_INT_CNTL, 0);
        /* vline/vblank, etc. */
        WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
        WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
@@ -7390,12 +7427,12 @@ int cik_irq_set(struct radeon_device *rdev)
                (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
        cp_int_cntl |= PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
 
-       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
 
        dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
        dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
@@ -7482,27 +7519,27 @@ int cik_irq_set(struct radeon_device *rdev)
        }
        if (rdev->irq.hpd[0]) {
                DRM_DEBUG("cik_irq_set: hpd 1\n");
-               hpd1 |= DC_HPDx_INT_EN;
+               hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[1]) {
                DRM_DEBUG("cik_irq_set: hpd 2\n");
-               hpd2 |= DC_HPDx_INT_EN;
+               hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[2]) {
                DRM_DEBUG("cik_irq_set: hpd 3\n");
-               hpd3 |= DC_HPDx_INT_EN;
+               hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[3]) {
                DRM_DEBUG("cik_irq_set: hpd 4\n");
-               hpd4 |= DC_HPDx_INT_EN;
+               hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[4]) {
                DRM_DEBUG("cik_irq_set: hpd 5\n");
-               hpd5 |= DC_HPDx_INT_EN;
+               hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[5]) {
                DRM_DEBUG("cik_irq_set: hpd 6\n");
-               hpd6 |= DC_HPDx_INT_EN;
+               hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
 
        WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
@@ -7551,6 +7588,9 @@ int cik_irq_set(struct radeon_device *rdev)
        WREG32(DC_HPD5_INT_CONTROL, hpd5);
        WREG32(DC_HPD6_INT_CONTROL, hpd6);
 
+       /* posting read */
+       RREG32(SRBM_STATUS);
+
        return 0;
 }
 
@@ -7671,6 +7711,36 @@ static inline void cik_irq_ack(struct radeon_device *rdev)
                tmp |= DC_HPDx_INT_ACK;
                WREG32(DC_HPD6_INT_CONTROL, tmp);
        }
+       if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD1_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD1_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD2_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD2_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD3_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD3_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD4_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD4_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD5_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD6_INT_CONTROL, tmp);
+       }
 }
 
 /**
@@ -7796,6 +7866,7 @@ int cik_irq_process(struct radeon_device *rdev)
        u8 me_id, pipe_id, queue_id;
        u32 ring_index;
        bool queue_hotplug = false;
+       bool queue_dp = false;
        bool queue_reset = false;
        u32 addr, status, mc_client;
        bool queue_thermal = false;
@@ -8041,11 +8112,57 @@ restart_ih:
                                        DRM_DEBUG("IH: HPD6\n");
                                }
                                break;
+                       case 6:
+                               if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 1\n");
+                               }
+                               break;
+                       case 7:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 2\n");
+                               }
+                               break;
+                       case 8:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 3\n");
+                               }
+                               break;
+                       case 9:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 4\n");
+                               }
+                               break;
+                       case 10:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 5\n");
+                               }
+                               break;
+                       case 11:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 6\n");
+                               }
+                               break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
                        }
                        break;
+               case 96:
+                       DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
+                       WREG32(SRBM_INT_ACK, 0x1);
+                       break;
                case 124: /* UVD */
                        DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
                        radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
@@ -8245,6 +8362,8 @@ restart_ih:
                rptr &= rdev->ih.ptr_mask;
                WREG32(IH_RB_RPTR, rptr);
        }
+       if (queue_dp)
+               schedule_work(&rdev->dp_work);
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_reset) {
index 03003f8a6de63ba00c741824c053070a009cd319..4870df898230cb3c4f02f160be9cf024e8a003ac 100644 (file)
 #define                SOFT_RESET_ORB                          (1 << 23)
 #define                SOFT_RESET_VCE                          (1 << 24)
 
+#define SRBM_READ_ERROR                                        0xE98
+#define SRBM_INT_CNTL                                  0xEA0
+#define SRBM_INT_ACK                                   0xEA8
+
 #define VM_L2_CNTL                                     0x1400
 #define                ENABLE_L2_CACHE                                 (1 << 0)
 #define                ENABLE_L2_FRAGMENT_PROCESSING                   (1 << 1)
 #      define CLK_OD(x)                                ((x) << 6)
 #      define CLK_OD_MASK                              (0x1f << 6)
 
+#define UVD_STATUS                                     0xf6bc
+
 /* UVD clocks */
 
 #define CG_DCLK_CNTL                   0xC050009C
index 192c8038915187df6714fbd6d653f57dba449c13..3adc2afe32aa6be372abcdd925001bbc79176745 100644 (file)
@@ -26,6 +26,9 @@
 #include "radeon_audio.h"
 #include "sid.h"
 
+#define DCE8_DCCG_AUDIO_DTO1_PHASE     0x05b8
+#define DCE8_DCCG_AUDIO_DTO1_MODULE    0x05bc
+
 u32 dce6_endpoint_rreg(struct radeon_device *rdev,
                              u32 block_offset, u32 reg)
 {
@@ -252,72 +255,67 @@ 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)
 {
-    /* Two dtos; generally use dto0 for HDMI */
+       /* Two dtos; generally use dto0 for HDMI */
        u32 value = 0;
 
-    if (crtc)
+       if (crtc)
                value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
 
        WREG32(DCCG_AUDIO_DTO_SOURCE, value);
 
-    /* Express [24MHz / target pixel clock] as an exact rational
-     * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
-     * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
-     */
-    WREG32(DCCG_AUDIO_DTO0_PHASE, 24000);
-    WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
+       /* Express [24MHz / target pixel clock] as an exact rational
+        * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+        * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+        */
+       WREG32(DCCG_AUDIO_DTO0_PHASE, 24000);
+       WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
 }
 
 void dce6_dp_audio_set_dto(struct radeon_device *rdev,
        struct radeon_crtc *crtc, unsigned int clock)
 {
-    /* Two dtos; generally use dto1 for DP */
+       /* Two dtos; generally use dto1 for DP */
        u32 value = 0;
        value |= DCCG_AUDIO_DTO_SEL;
 
-    if (crtc)
+       if (crtc)
                value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
 
        WREG32(DCCG_AUDIO_DTO_SOURCE, value);
 
-    /* Express [24MHz / target pixel clock] as an exact rational
-     * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
-     * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
-     */
-    WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
-    WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
+       /* Express [24MHz / target pixel clock] as an exact rational
+        * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+        * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+        */
+       if (ASIC_IS_DCE8(rdev)) {
+               WREG32(DCE8_DCCG_AUDIO_DTO1_PHASE, 24000);
+               WREG32(DCE8_DCCG_AUDIO_DTO1_MODULE, clock);
+       } else {
+               WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
+               WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
+       }
 }
 
-void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
+void dce6_dp_enable(struct drm_encoder *encoder, bool enable)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       uint32_t offset;
 
        if (!dig || !dig->afmt)
                return;
 
-       offset = dig->afmt->offset;
-
        if (enable) {
-        if (dig->afmt->enabled)
-            return;
-
-               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset,
-                       EVERGREEN_DP_SEC_ASP_ENABLE |           /* Audio packet transmission */
-                       EVERGREEN_DP_SEC_ATP_ENABLE |           /* Audio timestamp packet transmission */
-                       EVERGREEN_DP_SEC_AIP_ENABLE |           /* Audio infoframe packet transmission */
-                       EVERGREEN_DP_SEC_STREAM_ENABLE);        /* Master enable for secondary stream engine */
-               radeon_audio_enable(rdev, dig->afmt->pin, true);
+               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset,
+                      EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset,
+                      EVERGREEN_DP_SEC_ASP_ENABLE |            /* Audio packet transmission */
+                      EVERGREEN_DP_SEC_ATP_ENABLE |            /* Audio timestamp packet transmission */
+                      EVERGREEN_DP_SEC_AIP_ENABLE |            /* Audio infoframe packet transmission */
+                      EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */
        } else {
-               if (!dig->afmt->enabled)
-                       return;
-
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
-               radeon_audio_enable(rdev, dig->afmt->pin, false);
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0);
        }
 
        dig->afmt->enabled = enable;
index 78600f534c804b745b99f7aea8688381b4204182..f848acfd3fc8a94fb4674cf13d9442857e367567 100644 (file)
@@ -1006,6 +1006,34 @@ static void evergreen_init_golden_registers(struct radeon_device *rdev)
        }
 }
 
+/**
+ * evergreen_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int evergreen_get_allowed_info_register(struct radeon_device *rdev,
+                                       u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case DMA_STATUS_REG:
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
                             unsigned *bankh, unsigned *mtaspect,
                             unsigned *tile_split)
@@ -3253,6 +3281,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        }
 
        WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+       WREG32(SRBM_INT_CNTL, 0x1);
+       WREG32(SRBM_INT_ACK, 0x1);
 
        evergreen_fix_pci_max_read_req_size(rdev);
 
@@ -4324,6 +4354,7 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev)
        tmp = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
        WREG32(DMA_CNTL, tmp);
        WREG32(GRBM_INT_CNTL, 0);
+       WREG32(SRBM_INT_CNTL, 0);
        WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
        WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
        if (rdev->num_crtc >= 4) {
@@ -4389,12 +4420,12 @@ int evergreen_irq_set(struct radeon_device *rdev)
                return 0;
        }
 
-       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
        if (rdev->family == CHIP_ARUBA)
                thermal_int = RREG32(TN_CG_THERMAL_INT_CTRL) &
                        ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
@@ -4483,27 +4514,27 @@ int evergreen_irq_set(struct radeon_device *rdev)
        }
        if (rdev->irq.hpd[0]) {
                DRM_DEBUG("evergreen_irq_set: hpd 1\n");
-               hpd1 |= DC_HPDx_INT_EN;
+               hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[1]) {
                DRM_DEBUG("evergreen_irq_set: hpd 2\n");
-               hpd2 |= DC_HPDx_INT_EN;
+               hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[2]) {
                DRM_DEBUG("evergreen_irq_set: hpd 3\n");
-               hpd3 |= DC_HPDx_INT_EN;
+               hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[3]) {
                DRM_DEBUG("evergreen_irq_set: hpd 4\n");
-               hpd4 |= DC_HPDx_INT_EN;
+               hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[4]) {
                DRM_DEBUG("evergreen_irq_set: hpd 5\n");
-               hpd5 |= DC_HPDx_INT_EN;
+               hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[5]) {
                DRM_DEBUG("evergreen_irq_set: hpd 6\n");
-               hpd6 |= DC_HPDx_INT_EN;
+               hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.afmt[0]) {
                DRM_DEBUG("evergreen_irq_set: hdmi 0\n");
@@ -4590,6 +4621,9 @@ int evergreen_irq_set(struct radeon_device *rdev)
        WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, afmt5);
        WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, afmt6);
 
+       /* posting read */
+       RREG32(SRBM_STATUS);
+
        return 0;
 }
 
@@ -4694,6 +4728,38 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
                tmp |= DC_HPDx_INT_ACK;
                WREG32(DC_HPD6_INT_CONTROL, tmp);
        }
+
+       if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD1_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD1_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD2_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD2_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD3_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD3_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD4_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD4_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD5_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD6_INT_CONTROL, tmp);
+       }
+
        if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
                tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
                tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
@@ -4774,6 +4840,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
        u32 ring_index;
        bool queue_hotplug = false;
        bool queue_hdmi = false;
+       bool queue_dp = false;
        bool queue_thermal = false;
        u32 status, addr;
 
@@ -5013,6 +5080,48 @@ restart_ih:
                                        DRM_DEBUG("IH: HPD6\n");
                                }
                                break;
+                       case 6:
+                               if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 1\n");
+                               }
+                               break;
+                       case 7:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 2\n");
+                               }
+                               break;
+                       case 8:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 3\n");
+                               }
+                               break;
+                       case 9:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 4\n");
+                               }
+                               break;
+                       case 10:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 5\n");
+                               }
+                               break;
+                       case 11:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 6\n");
+                               }
+                               break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
@@ -5066,6 +5175,10 @@ restart_ih:
                                DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
                        }
+               case 96:
+                       DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
+                       WREG32(SRBM_INT_ACK, 0x1);
+                       break;
                case 124: /* UVD */
                        DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
                        radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
@@ -5141,6 +5254,8 @@ restart_ih:
                rptr &= rdev->ih.ptr_mask;
                WREG32(IH_RB_RPTR, rptr);
        }
+       if (queue_dp)
+               schedule_work(&rdev->dp_work);
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_hdmi)
index 1d9aebc79595d050dd52d6e28da01939b908bc16..c18d4ecbd95d02baa907d4d15b6da43f282f4e67 100644 (file)
@@ -272,7 +272,7 @@ void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
 }
 
 void dce4_dp_audio_set_dto(struct radeon_device *rdev,
-       struct radeon_crtc *crtc, unsigned int clock)
+                          struct radeon_crtc *crtc, unsigned int clock)
 {
        u32 value;
 
@@ -294,7 +294,7 @@ void dce4_dp_audio_set_dto(struct radeon_device *rdev,
         * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
         */
        WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
-       WREG32(DCCG_AUDIO_DTO1_MODULE, rdev->clock.max_pixel_clock * 10);
+       WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
 }
 
 void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
@@ -350,20 +350,9 @@ void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset)
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
 
-       WREG32(HDMI_INFOFRAME_CONTROL0 + offset,
-               HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
-               HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
-
        WREG32(AFMT_INFOFRAME_CONTROL0 + offset,
                AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
 
-       WREG32(HDMI_INFOFRAME_CONTROL1 + offset,
-               HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
-
-       WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
-               HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
-               HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
-
        WREG32(AFMT_60958_0 + offset,
                AFMT_60958_CS_CHANNEL_NUMBER_L(1));
 
@@ -408,15 +397,19 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!dig || !dig->afmt)
                return;
 
-       /* Silent, r600_hdmi_enable will raise WARN for us */
-       if (enable && dig->afmt->enabled)
-               return;
-       if (!enable && !dig->afmt->enabled)
-               return;
+       if (enable) {
+               WREG32(HDMI_INFOFRAME_CONTROL1 + dig->afmt->offset,
+                      HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
+
+               WREG32(HDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset,
+                      HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
+                      HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
 
-       if (!enable && dig->afmt->pin) {
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
-               dig->afmt->pin = NULL;
+               WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset,
+                      HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+                      HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
+       } else {
+               WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, 0);
        }
 
        dig->afmt->enabled = enable;
@@ -425,33 +418,28 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
                  enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id);
 }
 
-void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
+void evergreen_dp_enable(struct drm_encoder *encoder, bool enable)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       uint32_t offset;
 
        if (!dig || !dig->afmt)
                return;
 
-       offset = dig->afmt->offset;
-
        if (enable) {
                struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                struct radeon_connector_atom_dig *dig_connector;
                uint32_t val;
 
-               if (dig->afmt->enabled)
-                       return;
-
-               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
+               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset,
+                      EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
 
                if (radeon_connector->con_priv) {
                        dig_connector = radeon_connector->con_priv;
-                       val = RREG32(EVERGREEN_DP_SEC_AUD_N + offset);
+                       val = RREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset);
                        val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf);
 
                        if (dig_connector->dp_clock == 162000)
@@ -459,21 +447,16 @@ void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
                        else
                                val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(5);
 
-                       WREG32(EVERGREEN_DP_SEC_AUD_N + offset, val);
+                       WREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset, val);
                }
 
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset,
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset,
                        EVERGREEN_DP_SEC_ASP_ENABLE |           /* Audio packet transmission */
                        EVERGREEN_DP_SEC_ATP_ENABLE |           /* Audio timestamp packet transmission */
                        EVERGREEN_DP_SEC_AIP_ENABLE |           /* Audio infoframe packet transmission */
                        EVERGREEN_DP_SEC_STREAM_ENABLE);        /* Master enable for secondary stream engine */
-               radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
        } else {
-               if (!dig->afmt->enabled)
-                       return;
-
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0);
        }
 
        dig->afmt->enabled = enable;
index ee83d2a88750aafb865c30dd89e42c2041700a61..4aa5f755572b1593a8b6f7876cf5f7aed183715d 100644 (file)
 #define                SOFT_RESET_REGBB                        (1 << 22)
 #define                SOFT_RESET_ORB                          (1 << 23)
 
+#define SRBM_READ_ERROR                                        0xE98
+#define SRBM_INT_CNTL                                  0xEA0
+#define SRBM_INT_ACK                                   0xEA8
+
 /* display watermarks */
 #define        DC_LB_MEMORY_SPLIT                                0x6b0c
 #define        PRIORITY_A_CNT                                    0x6b18
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xef54
 #define UVD_RBC_RB_RPTR                                        0xf690
 #define UVD_RBC_RB_WPTR                                        0xf694
+#define UVD_STATUS                                     0xf6bc
 
 /*
  * PM4
index 0e236d067d6648a5a5a17c5a60ead839372d0c0d..2d71da448487d40401e45e80fb4331f247e62249 100644 (file)
@@ -2820,6 +2820,29 @@ void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
        }
 }
 
+u32 kv_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct kv_power_info *pi = kv_get_pi(rdev);
+       u32 current_index =
+               (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >>
+               CURR_SCLK_INDEX_SHIFT;
+       u32 sclk;
+
+       if (current_index >= SMU__NUM_SCLK_DPM_STATE) {
+               return 0;
+       } else {
+               sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency);
+               return sclk;
+       }
+}
+
+u32 kv_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct kv_power_info *pi = kv_get_pi(rdev);
+
+       return pi->sys_info.bootup_uma_clk;
+}
+
 void kv_dpm_print_power_state(struct radeon_device *rdev,
                              struct radeon_ps *rps)
 {
index 24242a7f0ac3d728c4c69366f8af1077ecc25190..e8a496ff007ee680d30a2bd688f30d094b58461c 100644 (file)
@@ -828,6 +828,35 @@ out:
        return err;
 }
 
+/**
+ * cayman_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int cayman_get_allowed_info_register(struct radeon_device *rdev,
+                                    u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case (DMA_STATUS_REG + DMA0_REGISTER_OFFSET):
+       case (DMA_STATUS_REG + DMA1_REGISTER_OFFSET):
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 int tn_get_temp(struct radeon_device *rdev)
 {
        u32 temp = RREG32_SMC(TN_CURRENT_GNB_TEMP) & 0x7ff;
@@ -962,6 +991,8 @@ static void cayman_gpu_init(struct radeon_device *rdev)
        }
 
        WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+       WREG32(SRBM_INT_CNTL, 0x1);
+       WREG32(SRBM_INT_ACK, 0x1);
 
        evergreen_fix_pci_max_read_req_size(rdev);
 
@@ -1086,12 +1117,12 @@ static void cayman_gpu_init(struct radeon_device *rdev)
 
        if ((rdev->config.cayman.max_backends_per_se == 1) &&
            (rdev->flags & RADEON_IS_IGP)) {
-               if ((disabled_rb_mask & 3) == 1) {
-                       /* RB0 disabled, RB1 enabled */
-                       tmp = 0x11111111;
-               } else {
+               if ((disabled_rb_mask & 3) == 2) {
                        /* RB1 disabled, RB0 enabled */
                        tmp = 0x00000000;
+               } else {
+                       /* RB0 disabled, RB1 enabled */
+                       tmp = 0x11111111;
                }
        } else {
                tmp = gb_addr_config & NUM_PIPES_MASK;
index 7bc9f8d9804aa18db5bf63f6e93dc5557bcdce11..c3d531a1114b69b5b882d895c59eb698f6b4e5de 100644 (file)
@@ -4319,6 +4319,42 @@ void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
        }
 }
 
+u32 ni_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 ni_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->mclk;
+       }
+}
+
 u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
index 5db7b7d6feb0d2379d076ef8ae80d868a42ae74d..da310a70c0f01b880f8bac9bf7bb2abe6da5d7a1 100644 (file)
 #       define NI_REGAMMA_PROG_B                       4
 #       define NI_OVL_REGAMMA_MODE(x)                  (((x) & 0x7) << 4)
 
+#define NI_DP_MSE_LINK_TIMING                          0x73a0
+#      define NI_DP_MSE_LINK_FRAME                     (((x) & 0x3ff) << 0)
+#      define NI_DP_MSE_LINK_LINE                      (((x) & 0x3) << 16)
+
+#define NI_DP_MSE_MISC_CNTL                            0x736c
+#       define NI_DP_MSE_BLANK_CODE                    (((x) & 0x1) << 0)
+#       define NI_DP_MSE_TIMESTAMP_MODE                (((x) & 0x1) << 4)
+#       define NI_DP_MSE_ZERO_ENCODER                  (((x) & 0x1) << 8)
+
+#define NI_DP_MSE_RATE_CNTL                            0x7384
+#       define NI_DP_MSE_RATE_Y(x)                   (((x) & 0x3ffffff) << 0)
+#       define NI_DP_MSE_RATE_X(x)                   (((x) & 0x3f) << 26)
+
+#define NI_DP_MSE_RATE_UPDATE                          0x738c
+
+#define NI_DP_MSE_SAT0                                 0x7390
+#       define NI_DP_MSE_SAT_SRC0(x)                   (((x) & 0x7) << 0)
+#       define NI_DP_MSE_SAT_SLOT_COUNT0(x)            (((x) & 0x3f) << 8)
+#       define NI_DP_MSE_SAT_SRC1(x)                   (((x) & 0x7) << 16)
+#       define NI_DP_MSE_SAT_SLOT_COUNT1(x)            (((x) & 0x3f) << 24)
+
+#define NI_DP_MSE_SAT1                                 0x7394
+
+#define NI_DP_MSE_SAT2                                 0x7398
+
+#define NI_DP_MSE_SAT_UPDATE                           0x739c
+
+#define NI_DIG_BE_CNTL                                 0x7140
+#       define NI_DIG_FE_SOURCE_SELECT(x)              (((x) & 0x7f) << 8)
+#       define NI_DIG_FE_DIG_MODE(x)                   (((x) & 0x7) << 16)
+#       define NI_DIG_MODE_DP_SST                      0
+#       define NI_DIG_MODE_LVDS                        1
+#       define NI_DIG_MODE_TMDS_DVI                    2
+#       define NI_DIG_MODE_TMDS_HDMI                   3
+#       define NI_DIG_MODE_DP_MST                      5
+#       define NI_DIG_HPD_SELECT(x)                    (((x) & 0x7) << 28)
+
+#define NI_DIG_FE_CNTL                                 0x7000
+#       define NI_DIG_SOURCE_SELECT(x)                 (((x) & 0x3) << 0)
+#       define NI_DIG_STEREOSYNC_SELECT(x)             (((x) & 0x3) << 4)
+#       define NI_DIG_STEREOSYNC_GATE_EN(x)            (((x) & 0x1) << 8)
+#       define NI_DIG_DUAL_LINK_ENABLE(x)              (((x) & 0x1) << 16)
+#       define NI_DIG_SWAP(x)                          (((x) & 0x1) << 18)
+#       define NI_DIG_SYMCLK_FE_ON                     (0x1 << 24)
 #endif
index ad7125486894d18ae90b0bc507d248d92baaf3e6..3b290838918cfc3d04910616c25fd20df810fa89 100644 (file)
 #define                SOFT_RESET_REGBB                        (1 << 22)
 #define                SOFT_RESET_ORB                          (1 << 23)
 
+#define SRBM_READ_ERROR                                        0xE98
+#define SRBM_INT_CNTL                                  0xEA0
+#define SRBM_INT_ACK                                   0xEA8
+
 #define        SRBM_STATUS2                                    0x0EC4
 #define                DMA_BUSY                                (1 << 5)
 #define                DMA1_BUSY                               (1 << 6)
 #define MC_PMG_CMD_MRS2                                 0x2b5c
 #define MC_SEQ_PMG_CMD_MRS2_LP                          0x2b60
 
+#define AUX_CONTROL                                    0x6200
+#define        AUX_EN                                  (1 << 0)
+#define        AUX_LS_READ_EN                          (1 << 8)
+#define        AUX_LS_UPDATE_DISABLE(x)                (((x) & 0x1) << 12)
+#define        AUX_HPD_DISCON(x)                       (((x) & 0x1) << 16)
+#define        AUX_DET_EN                              (1 << 18)
+#define        AUX_HPD_SEL(x)                          (((x) & 0x7) << 20)
+#define        AUX_IMPCAL_REQ_EN                       (1 << 24)
+#define        AUX_TEST_MODE                           (1 << 28)
+#define        AUX_DEGLITCH_EN                         (1 << 29)
+#define AUX_SW_CONTROL                                 0x6204
+#define        AUX_SW_GO                               (1 << 0)
+#define        AUX_LS_READ_TRIG                        (1 << 2)
+#define        AUX_SW_START_DELAY(x)                   (((x) & 0xf) << 4)
+#define        AUX_SW_WR_BYTES(x)                      (((x) & 0x1f) << 16)
+
+#define AUX_SW_INTERRUPT_CONTROL                       0x620c
+#define        AUX_SW_DONE_INT                         (1 << 0)
+#define        AUX_SW_DONE_ACK                         (1 << 1)
+#define        AUX_SW_DONE_MASK                        (1 << 2)
+#define        AUX_SW_LS_DONE_INT                      (1 << 4)
+#define        AUX_SW_LS_DONE_MASK                     (1 << 6)
+#define AUX_SW_STATUS                                  0x6210
+#define        AUX_SW_DONE                             (1 << 0)
+#define        AUX_SW_REQ                              (1 << 1)
+#define        AUX_SW_RX_TIMEOUT_STATE(x)              (((x) & 0x7) << 4)
+#define        AUX_SW_RX_TIMEOUT                       (1 << 7)
+#define        AUX_SW_RX_OVERFLOW                      (1 << 8)
+#define        AUX_SW_RX_HPD_DISCON                    (1 << 9)
+#define        AUX_SW_RX_PARTIAL_BYTE                  (1 << 10)
+#define        AUX_SW_NON_AUX_MODE                     (1 << 11)
+#define        AUX_SW_RX_MIN_COUNT_VIOL                (1 << 12)
+#define        AUX_SW_RX_INVALID_STOP                  (1 << 14)
+#define        AUX_SW_RX_SYNC_INVALID_L                (1 << 17)
+#define        AUX_SW_RX_SYNC_INVALID_H                (1 << 18)
+#define        AUX_SW_RX_INVALID_START                 (1 << 19)
+#define        AUX_SW_RX_RECV_NO_DET                   (1 << 20)
+#define        AUX_SW_RX_RECV_INVALID_H                (1 << 22)
+#define        AUX_SW_RX_RECV_INVALID_V                (1 << 23)
+
+#define AUX_SW_DATA                                    0x6218
+#define AUX_SW_DATA_RW                                 (1 << 0)
+#define AUX_SW_DATA_MASK(x)                            (((x) & 0xff) << 8)
+#define AUX_SW_DATA_INDEX(x)                           (((x) & 0x1f) << 16)
+#define AUX_SW_AUTOINCREMENT_DISABLE                   (1 << 31)
+
 #define        LB_SYNC_RESET_SEL                               0x6b28
 #define                LB_SYNC_RESET_SEL_MASK                  (3 << 0)
 #define                LB_SYNC_RESET_SEL_SHIFT                 0
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xEF54
 #define UVD_RBC_RB_RPTR                                        0xF690
 #define UVD_RBC_RB_WPTR                                        0xF694
+#define UVD_STATUS                                     0xf6bc
 
 /*
  * PM4
index 279801ca5110aff68d80ea452751d7f9b0bf748f..04f2514f756453bfdc7275a52c65549e631cfc6c 100644 (file)
@@ -728,6 +728,10 @@ int r100_irq_set(struct radeon_device *rdev)
                tmp |= RADEON_FP2_DETECT_MASK;
        }
        WREG32(RADEON_GEN_INT_CNTL, tmp);
+
+       /* read back to post the write */
+       RREG32(RADEON_GEN_INT_CNTL);
+
        return 0;
 }
 
index 07a71a2488c93404f0803e3fbefe4c6204a4b5da..8f6d862a188228101dc9070f5ab2ada5f819d1a6 100644 (file)
@@ -108,6 +108,32 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev);
 extern int evergreen_rlc_resume(struct radeon_device *rdev);
 extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev);
 
+/**
+ * r600_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int r600_get_allowed_info_register(struct radeon_device *rdev,
+                                  u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS2:
+       case R_000E50_SRBM_STATUS:
+       case DMA_STATUS_REG:
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 /**
  * r600_get_xclk - get the xclk
  *
@@ -3784,6 +3810,9 @@ int r600_irq_set(struct radeon_device *rdev)
                WREG32(RV770_CG_THERMAL_INT, thermal_int);
        }
 
+       /* posting read */
+       RREG32(R_000E50_SRBM_STATUS);
+
        return 0;
 }
 
index 843b65f46ece168a8694a8a86a974befda12290b..fa2154493cf1537dee269149b1924468a6035325 100644 (file)
@@ -188,7 +188,7 @@ u32 r600_dpm_get_vrefresh(struct radeon_device *rdev)
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                        radeon_crtc = to_radeon_crtc(crtc);
                        if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
-                               vrefresh = radeon_crtc->hw_mode.vrefresh;
+                               vrefresh = drm_mode_vrefresh(&radeon_crtc->hw_mode);
                                break;
                        }
                }
index 62c91ed669ce24bdf4f96ea3eb0c7c446e457b1b..dd6606b8e23ca9a3bfd3f7be414b17d01af2aacb 100644 (file)
@@ -476,17 +476,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!dig || !dig->afmt)
                return;
 
-       /* Silent, r600_hdmi_enable will raise WARN for us */
-       if (enable && dig->afmt->enabled)
-               return;
-       if (!enable && !dig->afmt->enabled)
-               return;
-
-       if (!enable && dig->afmt->pin) {
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
-               dig->afmt->pin = NULL;
-       }
-
        /* Older chipsets require setting HDMI and routing manually */
        if (!ASIC_IS_DCE3(rdev)) {
                if (enable)
index 5587603b4a891c1f2cfcf7873dd8aa9e173907df..35ab65d53cc1cbdd6c7530000b203e4f4f6ef010 100644 (file)
@@ -111,6 +111,8 @@ extern int radeon_deep_color;
 extern int radeon_use_pflipirq;
 extern int radeon_bapm;
 extern int radeon_backlight;
+extern int radeon_auxch;
+extern int radeon_mst;
 
 /*
  * Copy from radeon_drv.h so we don't have to include both and have conflicting
@@ -1856,6 +1858,8 @@ struct radeon_asic {
        u32 (*get_xclk)(struct radeon_device *rdev);
        /* get the gpu clock counter */
        uint64_t (*get_gpu_clock_counter)(struct radeon_device *rdev);
+       /* get register for info ioctl */
+       int (*get_allowed_info_register)(struct radeon_device *rdev, u32 reg, u32 *val);
        /* gart */
        struct {
                void (*tlb_flush)(struct radeon_device *rdev);
@@ -1984,6 +1988,8 @@ struct radeon_asic {
                u32 (*fan_ctrl_get_mode)(struct radeon_device *rdev);
                int (*set_fan_speed_percent)(struct radeon_device *rdev, u32 speed);
                int (*get_fan_speed_percent)(struct radeon_device *rdev, u32 *speed);
+               u32 (*get_current_sclk)(struct radeon_device *rdev);
+               u32 (*get_current_mclk)(struct radeon_device *rdev);
        } dpm;
        /* pageflipping */
        struct {
@@ -2407,6 +2413,7 @@ struct radeon_device {
        struct radeon_rlc rlc;
        struct radeon_mec mec;
        struct work_struct hotplug_work;
+       struct work_struct dp_work;
        struct work_struct audio_work;
        int num_crtc; /* number of crtcs */
        struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
@@ -2931,6 +2938,7 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
 #define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))
 #define radeon_get_xclk(rdev) (rdev)->asic->get_xclk((rdev))
 #define radeon_get_gpu_clock_counter(rdev) (rdev)->asic->get_gpu_clock_counter((rdev))
+#define radeon_get_allowed_info_register(rdev, r, v) (rdev)->asic->get_allowed_info_register((rdev), (r), (v))
 #define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev))
 #define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev))
 #define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev))
@@ -2949,6 +2957,8 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
 #define radeon_dpm_vblank_too_short(rdev) rdev->asic->dpm.vblank_too_short((rdev))
 #define radeon_dpm_powergate_uvd(rdev, g) rdev->asic->dpm.powergate_uvd((rdev), (g))
 #define radeon_dpm_enable_bapm(rdev, e) rdev->asic->dpm.enable_bapm((rdev), (e))
+#define radeon_dpm_get_current_sclk(rdev) rdev->asic->dpm.get_current_sclk((rdev))
+#define radeon_dpm_get_current_mclk(rdev) rdev->asic->dpm.get_current_mclk((rdev))
 
 /* Common functions */
 /* AGP */
index c0ecd128b14bf584964b0787637740ff76ba845c..fafd8ce4d58fc6a844b9615aa3b013cf793123c6 100644 (file)
@@ -136,6 +136,11 @@ static void radeon_register_accessor_init(struct radeon_device *rdev)
        }
 }
 
+static int radeon_invalid_get_allowed_info_register(struct radeon_device *rdev,
+                                                   u32 reg, u32 *val)
+{
+       return -EINVAL;
+}
 
 /* helper to disable agp */
 /**
@@ -199,6 +204,7 @@ static struct radeon_asic r100_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r100_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
                .get_page_entry = &r100_pci_gart_get_page_entry,
@@ -266,6 +272,7 @@ static struct radeon_asic r200_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r100_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
                .get_page_entry = &r100_pci_gart_get_page_entry,
@@ -361,6 +368,7 @@ static struct radeon_asic r300_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
                .get_page_entry = &r100_pci_gart_get_page_entry,
@@ -428,6 +436,7 @@ static struct radeon_asic r300_asic_pcie = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -495,6 +504,7 @@ static struct radeon_asic r420_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -562,6 +572,7 @@ static struct radeon_asic rs400_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rs400_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rs400_gart_tlb_flush,
                .get_page_entry = &rs400_gart_get_page_entry,
@@ -629,6 +640,7 @@ static struct radeon_asic rs600_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rs600_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rs600_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -696,6 +708,7 @@ static struct radeon_asic rs690_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rs690_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rs400_gart_tlb_flush,
                .get_page_entry = &rs400_gart_get_page_entry,
@@ -763,6 +776,7 @@ static struct radeon_asic rv515_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rv515_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -830,6 +844,7 @@ static struct radeon_asic r520_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r520_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -925,6 +940,7 @@ static struct radeon_asic r600_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1009,6 +1025,7 @@ static struct radeon_asic rv6xx_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1080,6 +1097,8 @@ static struct radeon_asic rv6xx_asic = {
                .print_power_state = &rv6xx_dpm_print_power_state,
                .debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv6xx_dpm_force_performance_level,
+               .get_current_sclk = &rv6xx_dpm_get_current_sclk,
+               .get_current_mclk = &rv6xx_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &rs600_page_flip,
@@ -1099,6 +1118,7 @@ static struct radeon_asic rs780_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1170,6 +1190,8 @@ static struct radeon_asic rs780_asic = {
                .print_power_state = &rs780_dpm_print_power_state,
                .debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rs780_dpm_force_performance_level,
+               .get_current_sclk = &rs780_dpm_get_current_sclk,
+               .get_current_mclk = &rs780_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &rs600_page_flip,
@@ -1202,6 +1224,7 @@ static struct radeon_asic rv770_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1274,6 +1297,8 @@ static struct radeon_asic rv770_asic = {
                .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv770_dpm_force_performance_level,
                .vblank_too_short = &rv770_dpm_vblank_too_short,
+               .get_current_sclk = &rv770_dpm_get_current_sclk,
+               .get_current_mclk = &rv770_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &rv770_page_flip,
@@ -1319,6 +1344,7 @@ static struct radeon_asic evergreen_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = evergreen_get_allowed_info_register,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1391,6 +1417,8 @@ static struct radeon_asic evergreen_asic = {
                .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv770_dpm_force_performance_level,
                .vblank_too_short = &cypress_dpm_vblank_too_short,
+               .get_current_sclk = &rv770_dpm_get_current_sclk,
+               .get_current_mclk = &rv770_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1410,6 +1438,7 @@ static struct radeon_asic sumo_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = evergreen_get_allowed_info_register,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1481,6 +1510,8 @@ static struct radeon_asic sumo_asic = {
                .print_power_state = &sumo_dpm_print_power_state,
                .debugfs_print_current_performance_level = &sumo_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &sumo_dpm_force_performance_level,
+               .get_current_sclk = &sumo_dpm_get_current_sclk,
+               .get_current_mclk = &sumo_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1500,6 +1531,7 @@ static struct radeon_asic btc_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = evergreen_get_allowed_info_register,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1572,6 +1604,8 @@ static struct radeon_asic btc_asic = {
                .debugfs_print_current_performance_level = &btc_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv770_dpm_force_performance_level,
                .vblank_too_short = &btc_dpm_vblank_too_short,
+               .get_current_sclk = &btc_dpm_get_current_sclk,
+               .get_current_mclk = &btc_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1634,6 +1668,7 @@ static struct radeon_asic cayman_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = cayman_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cayman_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1717,6 +1752,8 @@ static struct radeon_asic cayman_asic = {
                .debugfs_print_current_performance_level = &ni_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &ni_dpm_force_performance_level,
                .vblank_too_short = &ni_dpm_vblank_too_short,
+               .get_current_sclk = &ni_dpm_get_current_sclk,
+               .get_current_mclk = &ni_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1736,6 +1773,7 @@ static struct radeon_asic trinity_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = cayman_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cayman_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1819,6 +1857,8 @@ static struct radeon_asic trinity_asic = {
                .debugfs_print_current_performance_level = &trinity_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &trinity_dpm_force_performance_level,
                .enable_bapm = &trinity_dpm_enable_bapm,
+               .get_current_sclk = &trinity_dpm_get_current_sclk,
+               .get_current_mclk = &trinity_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1868,6 +1908,7 @@ static struct radeon_asic si_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &si_get_xclk,
        .get_gpu_clock_counter = &si_get_gpu_clock_counter,
+       .get_allowed_info_register = si_get_allowed_info_register,
        .gart = {
                .tlb_flush = &si_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1955,6 +1996,8 @@ static struct radeon_asic si_asic = {
                .fan_ctrl_get_mode = &si_fan_ctrl_get_mode,
                .get_fan_speed_percent = &si_fan_ctrl_get_fan_speed_percent,
                .set_fan_speed_percent = &si_fan_ctrl_set_fan_speed_percent,
+               .get_current_sclk = &si_dpm_get_current_sclk,
+               .get_current_mclk = &si_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -2032,6 +2075,7 @@ static struct radeon_asic ci_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &cik_get_xclk,
        .get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+       .get_allowed_info_register = cik_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cik_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -2123,6 +2167,8 @@ static struct radeon_asic ci_asic = {
                .fan_ctrl_get_mode = &ci_fan_ctrl_get_mode,
                .get_fan_speed_percent = &ci_fan_ctrl_get_fan_speed_percent,
                .set_fan_speed_percent = &ci_fan_ctrl_set_fan_speed_percent,
+               .get_current_sclk = &ci_dpm_get_current_sclk,
+               .get_current_mclk = &ci_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -2142,6 +2188,7 @@ static struct radeon_asic kv_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &cik_get_xclk,
        .get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+       .get_allowed_info_register = cik_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cik_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -2229,6 +2276,8 @@ static struct radeon_asic kv_asic = {
                .force_performance_level = &kv_dpm_force_performance_level,
                .powergate_uvd = &kv_dpm_powergate_uvd,
                .enable_bapm = &kv_dpm_enable_bapm,
+               .get_current_sclk = &kv_dpm_get_current_sclk,
+               .get_current_mclk = &kv_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
index 72bdd3bf0d8e1208e6eace5d4c9cd2735f99e110..cf0a90bb61cab3a7bce074a931440a3d12cfa115 100644 (file)
@@ -384,6 +384,8 @@ u32 r600_gfx_get_wptr(struct radeon_device *rdev,
                      struct radeon_ring *ring);
 void r600_gfx_set_wptr(struct radeon_device *rdev,
                       struct radeon_ring *ring);
+int r600_get_allowed_info_register(struct radeon_device *rdev,
+                                  u32 reg, u32 *val);
 /* r600 irq */
 int r600_irq_process(struct radeon_device *rdev);
 int r600_irq_init(struct radeon_device *rdev);
@@ -433,6 +435,8 @@ void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                                                       struct seq_file *m);
 int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level);
+u32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev);
 /* rs780 dpm */
 int rs780_dpm_init(struct radeon_device *rdev);
 int rs780_dpm_enable(struct radeon_device *rdev);
@@ -449,6 +453,8 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                                                       struct seq_file *m);
 int rs780_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level);
+u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /*
  * rv770,rv730,rv710,rv740
@@ -488,6 +494,8 @@ void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
 int rv770_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level);
 bool rv770_dpm_vblank_too_short(struct radeon_device *rdev);
+u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /*
  * evergreen
@@ -540,6 +548,8 @@ struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
                                        unsigned num_gpu_pages,
                                        struct reservation_object *resv);
 int evergreen_get_temp(struct radeon_device *rdev);
+int evergreen_get_allowed_info_register(struct radeon_device *rdev,
+                                       u32 reg, u32 *val);
 int sumo_get_temp(struct radeon_device *rdev);
 int tn_get_temp(struct radeon_device *rdev);
 int cypress_dpm_init(struct radeon_device *rdev);
@@ -563,6 +573,8 @@ u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);
 bool btc_dpm_vblank_too_short(struct radeon_device *rdev);
 void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                     struct seq_file *m);
+u32 btc_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 btc_dpm_get_current_mclk(struct radeon_device *rdev);
 int sumo_dpm_init(struct radeon_device *rdev);
 int sumo_dpm_enable(struct radeon_device *rdev);
 int sumo_dpm_late_enable(struct radeon_device *rdev);
@@ -581,6 +593,8 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev
                                                      struct seq_file *m);
 int sumo_dpm_force_performance_level(struct radeon_device *rdev,
                                     enum radeon_dpm_forced_level level);
+u32 sumo_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 sumo_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /*
  * cayman
@@ -637,6 +651,8 @@ uint32_t cayman_dma_get_wptr(struct radeon_device *rdev,
                             struct radeon_ring *ring);
 void cayman_dma_set_wptr(struct radeon_device *rdev,
                         struct radeon_ring *ring);
+int cayman_get_allowed_info_register(struct radeon_device *rdev,
+                                    u32 reg, u32 *val);
 
 int ni_dpm_init(struct radeon_device *rdev);
 void ni_dpm_setup_asic(struct radeon_device *rdev);
@@ -655,6 +671,8 @@ void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
 int ni_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 bool ni_dpm_vblank_too_short(struct radeon_device *rdev);
+u32 ni_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 ni_dpm_get_current_mclk(struct radeon_device *rdev);
 int trinity_dpm_init(struct radeon_device *rdev);
 int trinity_dpm_enable(struct radeon_device *rdev);
 int trinity_dpm_late_enable(struct radeon_device *rdev);
@@ -674,6 +692,8 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r
 int trinity_dpm_force_performance_level(struct radeon_device *rdev,
                                        enum radeon_dpm_forced_level level);
 void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
+u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /* DCE6 - SI */
 void dce6_bandwidth_update(struct radeon_device *rdev);
@@ -726,6 +746,8 @@ u32 si_get_xclk(struct radeon_device *rdev);
 uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev);
 int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
 int si_get_temp(struct radeon_device *rdev);
+int si_get_allowed_info_register(struct radeon_device *rdev,
+                                u32 reg, u32 *val);
 int si_dpm_init(struct radeon_device *rdev);
 void si_dpm_setup_asic(struct radeon_device *rdev);
 int si_dpm_enable(struct radeon_device *rdev);
@@ -746,6 +768,8 @@ int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
                                                 u32 speed);
 u32 si_fan_ctrl_get_mode(struct radeon_device *rdev);
 void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode);
+u32 si_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 si_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /* DCE8 - CIK */
 void dce8_bandwidth_update(struct radeon_device *rdev);
@@ -841,6 +865,8 @@ void cik_sdma_set_wptr(struct radeon_device *rdev,
                       struct radeon_ring *ring);
 int ci_get_temp(struct radeon_device *rdev);
 int kv_get_temp(struct radeon_device *rdev);
+int cik_get_allowed_info_register(struct radeon_device *rdev,
+                                 u32 reg, u32 *val);
 
 int ci_dpm_init(struct radeon_device *rdev);
 int ci_dpm_enable(struct radeon_device *rdev);
@@ -862,6 +888,8 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 bool ci_dpm_vblank_too_short(struct radeon_device *rdev);
 void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
+u32 ci_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 ci_dpm_get_current_mclk(struct radeon_device *rdev);
 
 int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
                                                 u32 *speed);
@@ -890,6 +918,8 @@ int kv_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
 void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
+u32 kv_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 kv_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /* uvd v1.0 */
 uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,
index fc1b3f34cf1827c7498512e7b9f4e36039787d41..8f285244c839a8c85ad186a1b877f94749776a58 100644 (file)
@@ -845,6 +845,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
 
        radeon_link_encoder_connector(dev);
 
+       radeon_setup_mst_connector(dev);
        return true;
 }
 
index a3ceef6d9632509b5d1d4cb760539af02a033efe..48d49e651a30cf94212fe2b4482178e7870ed029 100644 (file)
@@ -101,8 +101,8 @@ static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
        struct drm_display_mode *mode);
 void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
-void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable);
-void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable);
+void evergreen_dp_enable(struct drm_encoder *encoder, bool enable);
+void dce6_dp_enable(struct drm_encoder *encoder, bool enable);
 
 static const u32 pin_offsets[7] =
 {
@@ -210,7 +210,7 @@ static struct radeon_audio_funcs dce4_dp_funcs = {
        .set_avi_packet = evergreen_set_avi_packet,
        .set_audio_packet = dce4_set_audio_packet,
        .mode_set = radeon_audio_dp_mode_set,
-       .dpms = evergreen_enable_dp_audio_packets,
+       .dpms = evergreen_dp_enable,
 };
 
 static struct radeon_audio_funcs dce6_hdmi_funcs = {
@@ -240,7 +240,7 @@ static struct radeon_audio_funcs dce6_dp_funcs = {
        .set_avi_packet = evergreen_set_avi_packet,
        .set_audio_packet = dce4_set_audio_packet,
        .mode_set = radeon_audio_dp_mode_set,
-       .dpms = dce6_enable_dp_audio_packets,
+       .dpms = dce6_dp_enable,
 };
 
 static void radeon_audio_interface_init(struct radeon_device *rdev)
@@ -452,7 +452,7 @@ void radeon_audio_enable(struct radeon_device *rdev,
 }
 
 void radeon_audio_detect(struct drm_connector *connector,
-       enum drm_connector_status status)
+                        enum drm_connector_status status)
 {
        struct radeon_device *rdev;
        struct radeon_encoder *radeon_encoder;
@@ -483,14 +483,11 @@ void radeon_audio_detect(struct drm_connector *connector,
                else
                        radeon_encoder->audio = rdev->audio.hdmi_funcs;
 
-               radeon_audio_write_speaker_allocation(connector->encoder);
-               radeon_audio_write_sad_regs(connector->encoder);
-               if (connector->encoder->crtc)
-                       radeon_audio_write_latency_fields(connector->encoder,
-                               &connector->encoder->crtc->mode);
+               dig->afmt->pin = radeon_audio_get_pin(connector->encoder);
                radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
        } else {
                radeon_audio_enable(rdev, dig->afmt->pin, 0);
+               dig->afmt->pin = NULL;
        }
 }
 
@@ -523,16 +520,40 @@ static int radeon_audio_set_avi_packet(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;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector = NULL;
        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;
+       }
+
        err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
        if (err < 0) {
                DRM_ERROR("failed to setup AVI infoframe: %d\n", err);
                return err;
        }
 
+       if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) {
+               if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB)
+                       frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED;
+               else
+                       frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
+       } else {
+               frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
+       }
+
        err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
        if (err < 0) {
                DRM_ERROR("failed to pack AVI infoframe: %d\n", err);
@@ -694,23 +715,22 @@ static void radeon_audio_set_mute(struct drm_encoder *encoder, bool mute)
  * update the info frames with the data from the current display mode
  */
 static void radeon_audio_hdmi_mode_set(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;
 
        if (!dig || !dig->afmt)
                return;
 
-       /* disable audio prior to setting up hw */
-       dig->afmt->pin = radeon_audio_get_pin(encoder);
-       radeon_audio_enable(rdev, dig->afmt->pin, 0);
+       radeon_audio_set_mute(encoder, true);
 
+       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_set_mute(encoder, false);
        radeon_audio_update_acr(encoder, mode->clock);
        radeon_audio_set_audio_packet(encoder);
        radeon_audio_select_pin(encoder);
@@ -718,8 +738,7 @@ static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
        if (radeon_audio_set_avi_packet(encoder, mode) < 0)
                return;
 
-       /* enable audio after to setting up hw */
-       radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+       radeon_audio_set_mute(encoder, false);
 }
 
 static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
@@ -729,23 +748,26 @@ static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector_atom_dig *dig_connector =
+               radeon_connector->con_priv;
 
        if (!dig || !dig->afmt)
                return;
 
-       /* disable audio prior to setting up hw */
-       dig->afmt->pin = radeon_audio_get_pin(encoder);
-       radeon_audio_enable(rdev, dig->afmt->pin, 0);
-
-       radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
+       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;
-
-       /* enable audio after to setting up hw */
-       radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
 }
 
 void radeon_audio_mode_set(struct drm_encoder *encoder,
index 27def67cb6beb31ca398956cf911ebdc0658755a..7ffa7d5563b9df9bdabd6a1b4afedf76061c371f 100644 (file)
@@ -27,6 +27,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_dp_mst_helper.h>
 #include <drm/radeon_drm.h>
 #include "radeon.h"
 #include "radeon_audio.h"
 
 #include <linux/pm_runtime.h>
 
+static int radeon_dp_handle_hpd(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       int ret;
+
+       ret = radeon_dp_mst_check_status(radeon_connector);
+       if (ret == -EINVAL)
+               return 1;
+       return 0;
+}
 void radeon_connector_hotplug(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 
+       if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+               struct radeon_connector_atom_dig *dig_connector =
+                       radeon_connector->con_priv;
+
+               if (radeon_connector->is_mst_connector)
+                       return;
+               if (dig_connector->is_mst) {
+                       radeon_dp_handle_hpd(connector);
+                       return;
+               }
+       }
        /* bail if the connector does not have hpd pin, e.g.,
         * VGA, TV, etc.
         */
@@ -725,6 +747,30 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct
                radeon_property_change_mode(&radeon_encoder->base);
        }
 
+       if (property == rdev->mode_info.output_csc_property) {
+               if (connector->encoder)
+                       radeon_encoder = to_radeon_encoder(connector->encoder);
+               else {
+                       struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+                       radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
+               }
+
+               if (radeon_encoder->output_csc == val)
+                       return 0;
+
+               radeon_encoder->output_csc = val;
+
+               if (connector->encoder->crtc) {
+                       struct drm_crtc *crtc  = connector->encoder->crtc;
+                       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+                       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
+                       radeon_crtc->output_csc = radeon_encoder->output_csc;
+
+                       (*crtc_funcs->load_lut)(crtc);
+               }
+       }
+
        return 0;
 }
 
@@ -1585,6 +1631,9 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
        struct drm_encoder *encoder = radeon_best_single_encoder(connector);
        int r;
 
+       if (radeon_dig_connector->is_mst)
+               return connector_status_disconnected;
+
        r = pm_runtime_get_sync(connector->dev->dev);
        if (r < 0)
                return connector_status_disconnected;
@@ -1643,12 +1692,21 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
                if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
                        ret = connector_status_connected;
-                       if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+                       if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
                                radeon_dp_getdpcd(radeon_connector);
+                               r = radeon_dp_mst_probe(radeon_connector);
+                               if (r == 1)
+                                       ret = connector_status_disconnected;
+                       }
                } else {
                        if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-                               if (radeon_dp_getdpcd(radeon_connector))
-                                       ret = connector_status_connected;
+                               if (radeon_dp_getdpcd(radeon_connector)) {
+                                       r = radeon_dp_mst_probe(radeon_connector);
+                                       if (r == 1)
+                                               ret = connector_status_disconnected;
+                                       else
+                                               ret = connector_status_connected;
+                               }
                        } else {
                                /* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
                                if (radeon_ddc_probe(radeon_connector, false))
@@ -1872,6 +1930,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_object_attach_property(&radeon_connector->base.base,
                                                   dev->mode_config.scaling_mode_property,
                                                   DRM_MODE_SCALE_NONE);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        break;
                case DRM_MODE_CONNECTOR_DVII:
                case DRM_MODE_CONNECTOR_DVID:
@@ -1904,6 +1966,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
 
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
@@ -1950,6 +2016,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           dev->mode_config.scaling_mode_property,
                                                           DRM_MODE_SCALE_NONE);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        /* no HPD on analog connectors */
                        radeon_connector->hpd.hpd = RADEON_HPD_NONE;
                        connector->polled = DRM_CONNECTOR_POLL_CONNECT;
@@ -1972,6 +2042,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           dev->mode_config.scaling_mode_property,
                                                           DRM_MODE_SCALE_NONE);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        /* no HPD on analog connectors */
                        radeon_connector->hpd.hpd = RADEON_HPD_NONE;
                        connector->interlace_allowed = true;
@@ -2023,6 +2097,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.load_detect_property,
                                                              1);
                        }
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_DVII)
                                connector->doublescan_allowed = true;
@@ -2068,6 +2146,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
                        }
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
@@ -2116,6 +2198,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
                        }
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        connector->interlace_allowed = true;
                        /* in theory with a DP to VGA converter... */
                        connector->doublescan_allowed = false;
@@ -2352,3 +2438,27 @@ radeon_add_legacy_connector(struct drm_device *dev,
        connector->display_info.subpixel_order = subpixel_order;
        drm_connector_register(connector);
 }
+
+void radeon_setup_mst_connector(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+
+       if (!ASIC_IS_DCE5(rdev))
+               return;
+
+       if (radeon_mst == 0)
+               return;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               int ret;
+
+               radeon_connector = to_radeon_connector(connector);
+
+               if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+                       continue;
+
+               ret = radeon_dp_mst_init(radeon_connector);
+       }
+}
index c830863bc98aa0cb55e84aedfbbc76606945ee01..4d0f96cc3da4488b0a324058533d26500011293f 100644 (file)
@@ -256,11 +256,13 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
        u32 ring = RADEON_CS_RING_GFX;
        s32 priority = 0;
 
+       INIT_LIST_HEAD(&p->validated);
+
        if (!cs->num_chunks) {
                return 0;
        }
+
        /* get chunks */
-       INIT_LIST_HEAD(&p->validated);
        p->idx = 0;
        p->ib.sa_bo = NULL;
        p->const_ib.sa_bo = NULL;
@@ -715,6 +717,7 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p,
        struct radeon_cs_chunk *ib_chunk = p->chunk_ib;
        struct radeon_device *rdev = p->rdev;
        uint32_t header;
+       int ret = 0, i;
 
        if (idx >= ib_chunk->length_dw) {
                DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
@@ -743,14 +746,25 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p,
                break;
        default:
                DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto dump_ib;
        }
        if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) {
                DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n",
                          pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto dump_ib;
        }
        return 0;
+
+dump_ib:
+       for (i = 0; i < ib_chunk->length_dw; i++) {
+               if (i == idx)
+                       printk("\t0x%08x <---\n", radeon_get_ib_value(p, i));
+               else
+                       printk("\t0x%08x\n", radeon_get_ib_value(p, i));
+       }
+       return ret;
 }
 
 /**
index bd7519fdd3f431cbce8c2bc6bd3e588e525be5cd..b7ca4c51462120fab3ab146dd74f653e8bcb91cb 100644 (file)
@@ -1442,6 +1442,11 @@ int radeon_device_init(struct radeon_device *rdev,
                DRM_ERROR("registering gem debugfs failed (%d).\n", r);
        }
 
+       r = radeon_mst_debugfs_init(rdev);
+       if (r) {
+               DRM_ERROR("registering mst debugfs failed (%d).\n", r);
+       }
+
        if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) {
                /* Acceleration not working on AGP card try again
                 * with fallback to PCI or PCIE GART
index 913fafa597ad210180c03e03618002a702cda441..d2e9e9efc159c053b954aed21840ebe7d91f2739 100644 (file)
@@ -154,7 +154,7 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc)
               (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) |
                NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS)));
        WREG32(NI_OUTPUT_CSC_CONTROL + radeon_crtc->crtc_offset,
-              (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) |
+              (NI_OUTPUT_CSC_GRPH_MODE(radeon_crtc->output_csc) |
                NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
        /* XXX match this to the depth of the crtc fmt block, move to modeset? */
        WREG32(0x6940 + radeon_crtc->crtc_offset, 0);
@@ -1382,6 +1382,13 @@ static struct drm_prop_enum_list radeon_dither_enum_list[] =
        { RADEON_FMT_DITHER_ENABLE, "on" },
 };
 
+static struct drm_prop_enum_list radeon_output_csc_enum_list[] =
+{      { RADEON_OUTPUT_CSC_BYPASS, "bypass" },
+       { RADEON_OUTPUT_CSC_TVRGB, "tvrgb" },
+       { RADEON_OUTPUT_CSC_YCBCR601, "ycbcr601" },
+       { RADEON_OUTPUT_CSC_YCBCR709, "ycbcr709" },
+};
+
 static int radeon_modeset_create_props(struct radeon_device *rdev)
 {
        int sz;
@@ -1444,6 +1451,12 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
                                         "dither",
                                         radeon_dither_enum_list, sz);
 
+       sz = ARRAY_SIZE(radeon_output_csc_enum_list);
+       rdev->mode_info.output_csc_property =
+               drm_property_create_enum(rdev->ddev, 0,
+                                        "output_csc",
+                                        radeon_output_csc_enum_list, sz);
+
        return 0;
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_dp_auxch.c b/drivers/gpu/drm/radeon/radeon_dp_auxch.c
new file mode 100644 (file)
index 0000000..bf1fecc
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2015 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ */
+#include <drm/drmP.h>
+#include <drm/radeon_drm.h>
+#include "radeon.h"
+#include "nid.h"
+
+#define AUX_RX_ERROR_FLAGS (AUX_SW_RX_OVERFLOW |            \
+                           AUX_SW_RX_HPD_DISCON |           \
+                           AUX_SW_RX_PARTIAL_BYTE |         \
+                           AUX_SW_NON_AUX_MODE |            \
+                           AUX_SW_RX_MIN_COUNT_VIOL |       \
+                           AUX_SW_RX_INVALID_STOP |         \
+                           AUX_SW_RX_SYNC_INVALID_L |       \
+                           AUX_SW_RX_SYNC_INVALID_H |       \
+                           AUX_SW_RX_INVALID_START |        \
+                           AUX_SW_RX_RECV_NO_DET |          \
+                           AUX_SW_RX_RECV_INVALID_H |       \
+                           AUX_SW_RX_RECV_INVALID_V)
+
+#define AUX_SW_REPLY_GET_BYTE_COUNT(x) (((x) >> 24) & 0x1f)
+
+#define BARE_ADDRESS_SIZE 3
+
+static const u32 aux_offset[] =
+{
+       0x6200 - 0x6200,
+       0x6250 - 0x6200,
+       0x62a0 - 0x6200,
+       0x6300 - 0x6200,
+       0x6350 - 0x6200,
+       0x63a0 - 0x6200,
+};
+
+ssize_t
+radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+       struct radeon_i2c_chan *chan =
+               container_of(aux, struct radeon_i2c_chan, aux);
+       struct drm_device *dev = chan->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int ret = 0, i;
+       uint32_t tmp, ack = 0;
+       int instance = chan->rec.i2c_id & 0xf;
+       u8 byte;
+       u8 *buf = msg->buffer;
+       int retry_count = 0;
+       int bytes;
+       int msize;
+       bool is_write = false;
+
+       if (WARN_ON(msg->size > 16))
+               return -E2BIG;
+
+       switch (msg->request & ~DP_AUX_I2C_MOT) {
+       case DP_AUX_NATIVE_WRITE:
+       case DP_AUX_I2C_WRITE:
+               is_write = true;
+               break;
+       case DP_AUX_NATIVE_READ:
+       case DP_AUX_I2C_READ:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* work out two sizes required */
+       msize = 0;
+       bytes = BARE_ADDRESS_SIZE;
+       if (msg->size) {
+               msize = msg->size - 1;
+               bytes++;
+               if (is_write)
+                       bytes += msg->size;
+       }
+
+       mutex_lock(&chan->mutex);
+
+       /* switch the pad to aux mode */
+       tmp = RREG32(chan->rec.mask_clk_reg);
+       tmp |= (1 << 16);
+       WREG32(chan->rec.mask_clk_reg, tmp);
+
+       /* setup AUX control register with correct HPD pin */
+       tmp = RREG32(AUX_CONTROL + aux_offset[instance]);
+
+       tmp &= AUX_HPD_SEL(0x7);
+       tmp |= AUX_HPD_SEL(chan->rec.hpd);
+       tmp |= AUX_EN | AUX_LS_READ_EN;
+
+       WREG32(AUX_CONTROL + aux_offset[instance], tmp);
+
+       /* atombios appears to write this twice lets copy it */
+       WREG32(AUX_SW_CONTROL + aux_offset[instance],
+              AUX_SW_WR_BYTES(bytes));
+       WREG32(AUX_SW_CONTROL + aux_offset[instance],
+              AUX_SW_WR_BYTES(bytes));
+
+       /* write the data header into the registers */
+       /* request, addres, msg size */
+       byte = (msg->request << 4);
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte) | AUX_SW_AUTOINCREMENT_DISABLE);
+
+       byte = (msg->address >> 8) & 0xff;
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte));
+
+       byte = msg->address & 0xff;
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte));
+
+       byte = msize;
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte));
+
+       /* if we are writing - write the msg buffer */
+       if (is_write) {
+               for (i = 0; i < msg->size; i++) {
+                       WREG32(AUX_SW_DATA + aux_offset[instance],
+                              AUX_SW_DATA_MASK(buf[i]));
+               }
+       }
+
+       /* clear the ACK */
+       WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
+
+       /* write the size and GO bits */
+       WREG32(AUX_SW_CONTROL + aux_offset[instance],
+              AUX_SW_WR_BYTES(bytes) | AUX_SW_GO);
+
+       /* poll the status registers - TODO irq support */
+       do {
+               tmp = RREG32(AUX_SW_STATUS + aux_offset[instance]);
+               if (tmp & AUX_SW_DONE) {
+                       break;
+               }
+               usleep_range(100, 200);
+       } while (retry_count++ < 1000);
+
+       if (retry_count >= 1000) {
+               DRM_ERROR("auxch hw never signalled completion, error %08x\n", tmp);
+               ret = -EIO;
+               goto done;
+       }
+
+       if (tmp & AUX_SW_RX_TIMEOUT) {
+               DRM_DEBUG_KMS("dp_aux_ch timed out\n");
+               ret = -ETIMEDOUT;
+               goto done;
+       }
+       if (tmp & AUX_RX_ERROR_FLAGS) {
+               DRM_DEBUG_KMS("dp_aux_ch flags not zero: %08x\n", tmp);
+               ret = -EIO;
+               goto done;
+       }
+
+       bytes = AUX_SW_REPLY_GET_BYTE_COUNT(tmp);
+       if (bytes) {
+               WREG32(AUX_SW_DATA + aux_offset[instance],
+                      AUX_SW_DATA_RW | AUX_SW_AUTOINCREMENT_DISABLE);
+
+               tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
+               ack = (tmp >> 8) & 0xff;
+
+               for (i = 0; i < bytes - 1; i++) {
+                       tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
+                       if (buf)
+                               buf[i] = (tmp >> 8) & 0xff;
+               }
+               if (buf)
+                       ret = bytes - 1;
+       }
+
+       WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
+
+       if (is_write)
+               ret = msg->size;
+done:
+       mutex_unlock(&chan->mutex);
+
+       if (ret >= 0)
+               msg->reply = ack >> 4;
+       return ret;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c
new file mode 100644 (file)
index 0000000..5952ff2
--- /dev/null
@@ -0,0 +1,782 @@
+
+#include <drm/drmP.h>
+#include <drm/drm_dp_mst_helper.h>
+#include <drm/drm_fb_helper.h>
+
+#include "radeon.h"
+#include "atom.h"
+#include "ni_reg.h"
+
+static struct radeon_encoder *radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector);
+
+static int radeon_atom_set_enc_offset(int id)
+{
+       static const int offsets[] = { EVERGREEN_CRTC0_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC1_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC2_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC3_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC4_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC5_REGISTER_OFFSET,
+                                      0x13830 - 0x7030 };
+
+       return offsets[id];
+}
+
+static int radeon_dp_mst_set_be_cntl(struct radeon_encoder *primary,
+                                    struct radeon_encoder_mst *mst_enc,
+                                    enum radeon_hpd_id hpd, bool enable)
+{
+       struct drm_device *dev = primary->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t reg;
+       int retries = 0;
+       uint32_t temp;
+
+       reg = RREG32(NI_DIG_BE_CNTL + primary->offset);
+
+       /* set MST mode */
+       reg &= ~NI_DIG_FE_DIG_MODE(7);
+       reg |= NI_DIG_FE_DIG_MODE(NI_DIG_MODE_DP_MST);
+
+       if (enable)
+               reg |= NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe);
+       else
+               reg &= ~NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe);
+
+       reg |= NI_DIG_HPD_SELECT(hpd);
+       DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DIG_BE_CNTL + primary->offset, reg);
+       WREG32(NI_DIG_BE_CNTL + primary->offset, reg);
+
+       if (enable) {
+               uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe);
+
+               do {
+                       temp = RREG32(NI_DIG_FE_CNTL + offset);
+               } while ((temp & NI_DIG_SYMCLK_FE_ON) && retries++ < 10000);
+               if (retries == 10000)
+                       DRM_ERROR("timed out waiting for FE %d %d\n", primary->offset, mst_enc->fe);
+       }
+       return 0;
+}
+
+static int radeon_dp_mst_set_stream_attrib(struct radeon_encoder *primary,
+                                          int stream_number,
+                                          int fe,
+                                          int slots)
+{
+       struct drm_device *dev = primary->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       u32 temp, val;
+       int retries  = 0;
+       int satreg, satidx;
+
+       satreg = stream_number >> 1;
+       satidx = stream_number & 1;
+
+       temp = RREG32(NI_DP_MSE_SAT0 + satreg + primary->offset);
+
+       val = NI_DP_MSE_SAT_SLOT_COUNT0(slots) | NI_DP_MSE_SAT_SRC0(fe);
+
+       val <<= (16 * satidx);
+
+       temp &= ~(0xffff << (16 * satidx));
+
+       temp |= val;
+
+       DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DP_MSE_SAT0 + satreg + primary->offset, temp);
+       WREG32(NI_DP_MSE_SAT0 + satreg + primary->offset, temp);
+
+       WREG32(NI_DP_MSE_SAT_UPDATE + primary->offset, 1);
+
+       do {
+               temp = RREG32(NI_DP_MSE_SAT_UPDATE + primary->offset);
+       } while ((temp & 0x1) && retries++ < 10000);
+
+       if (retries == 10000)
+               DRM_ERROR("timed out waitin for SAT update %d\n", primary->offset);
+
+       /* MTP 16 ? */
+       return 0;
+}
+
+static int radeon_dp_mst_update_stream_attribs(struct radeon_connector *mst_conn,
+                                              struct radeon_encoder *primary)
+{
+       struct drm_device *dev = mst_conn->base.dev;
+       struct stream_attribs new_attribs[6];
+       int i;
+       int idx = 0;
+       struct radeon_connector *radeon_connector;
+       struct drm_connector *connector;
+
+       memset(new_attribs, 0, sizeof(new_attribs));
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct radeon_encoder *subenc;
+               struct radeon_encoder_mst *mst_enc;
+
+               radeon_connector = to_radeon_connector(connector);
+               if (!radeon_connector->is_mst_connector)
+                       continue;
+
+               if (radeon_connector->mst_port != mst_conn)
+                       continue;
+
+               subenc = radeon_connector->mst_encoder;
+               mst_enc = subenc->enc_priv;
+
+               if (!mst_enc->enc_active)
+                       continue;
+
+               new_attribs[idx].fe = mst_enc->fe;
+               new_attribs[idx].slots = drm_dp_mst_get_vcpi_slots(&mst_conn->mst_mgr, mst_enc->port);
+               idx++;
+       }
+
+       for (i = 0; i < idx; i++) {
+               if (new_attribs[i].fe != mst_conn->cur_stream_attribs[i].fe ||
+                   new_attribs[i].slots != mst_conn->cur_stream_attribs[i].slots) {
+                       radeon_dp_mst_set_stream_attrib(primary, i, new_attribs[i].fe, new_attribs[i].slots);
+                       mst_conn->cur_stream_attribs[i].fe = new_attribs[i].fe;
+                       mst_conn->cur_stream_attribs[i].slots = new_attribs[i].slots;
+               }
+       }
+
+       for (i = idx; i < mst_conn->enabled_attribs; i++) {
+               radeon_dp_mst_set_stream_attrib(primary, i, 0, 0);
+               mst_conn->cur_stream_attribs[i].fe = 0;
+               mst_conn->cur_stream_attribs[i].slots = 0;
+       }
+       mst_conn->enabled_attribs = idx;
+       return 0;
+}
+
+static int radeon_dp_mst_set_vcp_size(struct radeon_encoder *mst, uint32_t x, uint32_t y)
+{
+       struct drm_device *dev = mst->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder_mst *mst_enc = mst->enc_priv;
+       uint32_t val, temp;
+       uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe);
+       int retries = 0;
+
+       val = NI_DP_MSE_RATE_X(x) | NI_DP_MSE_RATE_Y(y);
+
+       WREG32(NI_DP_MSE_RATE_CNTL + offset, val);
+
+       do {
+               temp = RREG32(NI_DP_MSE_RATE_UPDATE + offset);
+       } while ((temp & 0x1) && (retries++ < 10000));
+
+       if (retries >= 10000)
+               DRM_ERROR("timed out wait for rate cntl %d\n", mst_enc->fe);
+       return 0;
+}
+
+static int radeon_dp_mst_get_ddc_modes(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector *master = radeon_connector->mst_port;
+       struct edid *edid;
+       int ret = 0;
+
+       edid = drm_dp_mst_get_edid(connector, &master->mst_mgr, radeon_connector->port);
+       radeon_connector->edid = edid;
+       DRM_DEBUG_KMS("edid retrieved %p\n", edid);
+       if (radeon_connector->edid) {
+               drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
+               ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
+               drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid);
+               return ret;
+       }
+       drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
+
+       return ret;
+}
+
+static int radeon_dp_mst_get_modes(struct drm_connector *connector)
+{
+       return radeon_dp_mst_get_ddc_modes(connector);
+}
+
+static enum drm_mode_status
+radeon_dp_mst_mode_valid(struct drm_connector *connector,
+                       struct drm_display_mode *mode)
+{
+       /* TODO - validate mode against available PBN for link */
+       if (mode->clock < 10000)
+               return MODE_CLOCK_LOW;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+               return MODE_H_ILLEGAL;
+
+       return MODE_OK;
+}
+
+struct drm_encoder *radeon_mst_best_encoder(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+
+       return &radeon_connector->mst_encoder->base;
+}
+
+static const struct drm_connector_helper_funcs radeon_dp_mst_connector_helper_funcs = {
+       .get_modes = radeon_dp_mst_get_modes,
+       .mode_valid = radeon_dp_mst_mode_valid,
+       .best_encoder = radeon_mst_best_encoder,
+};
+
+static enum drm_connector_status
+radeon_dp_mst_detect(struct drm_connector *connector, bool force)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector *master = radeon_connector->mst_port;
+
+       return drm_dp_mst_detect_port(connector, &master->mst_mgr, radeon_connector->port);
+}
+
+static void
+radeon_dp_mst_connector_destroy(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_encoder *radeon_encoder = radeon_connector->mst_encoder;
+
+       drm_encoder_cleanup(&radeon_encoder->base);
+       kfree(radeon_encoder);
+       drm_connector_cleanup(connector);
+       kfree(radeon_connector);
+}
+
+static void radeon_connector_dpms(struct drm_connector *connector, int mode)
+{
+       DRM_DEBUG_KMS("\n");
+}
+
+static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = {
+       .dpms = radeon_connector_dpms,
+       .detect = radeon_dp_mst_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = radeon_dp_mst_connector_destroy,
+};
+
+static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+                                                        struct drm_dp_mst_port *port,
+                                                        const char *pathprop)
+{
+       struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
+       struct drm_device *dev = master->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_connector *radeon_connector;
+       struct drm_connector *connector;
+
+       radeon_connector = kzalloc(sizeof(*radeon_connector), GFP_KERNEL);
+       if (!radeon_connector)
+               return NULL;
+
+       radeon_connector->is_mst_connector = true;
+       connector = &radeon_connector->base;
+       radeon_connector->port = port;
+       radeon_connector->mst_port = master;
+       DRM_DEBUG_KMS("\n");
+
+       drm_connector_init(dev, connector, &radeon_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort);
+       drm_connector_helper_add(connector, &radeon_dp_mst_connector_helper_funcs);
+       radeon_connector->mst_encoder = radeon_dp_create_fake_mst_encoder(master);
+
+       drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
+       drm_mode_connector_set_path_property(connector, pathprop);
+       drm_reinit_primary_mode_group(dev);
+
+       mutex_lock(&dev->mode_config.mutex);
+       radeon_fb_add_connector(rdev, connector);
+       mutex_unlock(&dev->mode_config.mutex);
+
+       drm_connector_register(connector);
+       return connector;
+}
+
+static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+                                           struct drm_connector *connector)
+{
+       struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
+       struct drm_device *dev = master->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+
+       drm_connector_unregister(connector);
+       /* need to nuke the connector */
+       mutex_lock(&dev->mode_config.mutex);
+       /* dpms off */
+       radeon_fb_remove_connector(rdev, connector);
+
+       drm_connector_cleanup(connector);
+       mutex_unlock(&dev->mode_config.mutex);
+       drm_reinit_primary_mode_group(dev);
+
+
+       kfree(connector);
+       DRM_DEBUG_KMS("\n");
+}
+
+static void radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
+{
+       struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
+       struct drm_device *dev = master->base.dev;
+
+       drm_kms_helper_hotplug_event(dev);
+}
+
+struct drm_dp_mst_topology_cbs mst_cbs = {
+       .add_connector = radeon_dp_add_mst_connector,
+       .destroy_connector = radeon_dp_destroy_mst_connector,
+       .hotplug = radeon_dp_mst_hotplug,
+};
+
+struct radeon_connector *radeon_mst_find_connector(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+               if (!connector->encoder)
+                       continue;
+               if (!radeon_connector->is_mst_connector)
+                       continue;
+
+               DRM_DEBUG_KMS("checking %p vs %p\n", connector->encoder, encoder);
+               if (connector->encoder == encoder)
+                       return radeon_connector;
+       }
+       return NULL;
+}
+
+void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(radeon_crtc->encoder);
+       struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv;
+       struct radeon_connector *radeon_connector = radeon_mst_find_connector(&radeon_encoder->base);
+       int dp_clock;
+       struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv;
+
+       if (radeon_connector) {
+               radeon_connector->pixelclock_for_modeset = mode->clock;
+               if (radeon_connector->base.display_info.bpc)
+                       radeon_crtc->bpc = radeon_connector->base.display_info.bpc;
+               else
+                       radeon_crtc->bpc = 8;
+       }
+
+       DRM_DEBUG_KMS("dp_clock %p %d\n", dig_connector, dig_connector->dp_clock);
+       dp_clock = dig_connector->dp_clock;
+       radeon_crtc->ss_enabled =
+               radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss,
+                                                ASIC_INTERNAL_SS_ON_DP,
+                                                dp_clock);
+}
+
+static void
+radeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder, *primary;
+       struct radeon_encoder_mst *mst_enc;
+       struct radeon_encoder_atom_dig *dig_enc;
+       struct radeon_connector *radeon_connector;
+       struct drm_crtc *crtc;
+       struct radeon_crtc *radeon_crtc;
+       int ret, slots;
+
+       if (!ASIC_IS_DCE5(rdev)) {
+               DRM_ERROR("got mst dpms on non-DCE5\n");
+               return;
+       }
+
+       radeon_connector = radeon_mst_find_connector(encoder);
+       if (!radeon_connector)
+               return;
+
+       radeon_encoder = to_radeon_encoder(encoder);
+
+       mst_enc = radeon_encoder->enc_priv;
+
+       primary = mst_enc->primary;
+
+       dig_enc = primary->enc_priv;
+
+       crtc = encoder->crtc;
+       DRM_DEBUG_KMS("got connector %d\n", dig_enc->active_mst_links);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               dig_enc->active_mst_links++;
+
+               radeon_crtc = to_radeon_crtc(crtc);
+
+               if (dig_enc->active_mst_links == 1) {
+                       mst_enc->fe = dig_enc->dig_encoder;
+                       mst_enc->fe_from_be = true;
+                       atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe);
+
+                       atombios_dig_encoder_setup(&primary->base, ATOM_ENCODER_CMD_SETUP, 0);
+                       atombios_dig_transmitter_setup2(&primary->base, ATOM_TRANSMITTER_ACTION_ENABLE,
+                                                       0, 0, dig_enc->dig_encoder);
+
+                       if (radeon_dp_needs_link_train(mst_enc->connector) ||
+                           dig_enc->active_mst_links == 1) {
+                               radeon_dp_link_train(&primary->base, &mst_enc->connector->base);
+                       }
+
+               } else {
+                       mst_enc->fe = radeon_atom_pick_dig_encoder(encoder, radeon_crtc->crtc_id);
+                       if (mst_enc->fe == -1)
+                               DRM_ERROR("failed to get frontend for dig encoder\n");
+                       mst_enc->fe_from_be = false;
+                       atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe);
+               }
+
+               DRM_DEBUG_KMS("dig encoder is %d %d %d\n", dig_enc->dig_encoder,
+                             dig_enc->linkb, radeon_crtc->crtc_id);
+
+               ret = drm_dp_mst_allocate_vcpi(&radeon_connector->mst_port->mst_mgr,
+                                              radeon_connector->port,
+                                              mst_enc->pbn, &slots);
+               ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr);
+
+               radeon_dp_mst_set_be_cntl(primary, mst_enc,
+                                         radeon_connector->mst_port->hpd.hpd, true);
+
+               mst_enc->enc_active = true;
+               radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary);
+               radeon_dp_mst_set_vcp_size(radeon_encoder, slots, 0);
+
+               atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0,
+                                           mst_enc->fe);
+               ret = drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr);
+
+               ret = drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr);
+
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               DRM_ERROR("DPMS OFF %d\n", dig_enc->active_mst_links);
+
+               if (!mst_enc->enc_active)
+                       return;
+
+               drm_dp_mst_reset_vcpi_slots(&radeon_connector->mst_port->mst_mgr, mst_enc->port);
+               ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr);
+
+               drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr);
+               /* and this can also fail */
+               drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr);
+
+               drm_dp_mst_deallocate_vcpi(&radeon_connector->mst_port->mst_mgr, mst_enc->port);
+
+               mst_enc->enc_active = false;
+               radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary);
+
+               radeon_dp_mst_set_be_cntl(primary, mst_enc,
+                                         radeon_connector->mst_port->hpd.hpd, false);
+               atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0,
+                                           mst_enc->fe);
+
+               if (!mst_enc->fe_from_be)
+                       radeon_atom_release_dig_encoder(rdev, mst_enc->fe);
+
+               mst_enc->fe_from_be = false;
+               dig_enc->active_mst_links--;
+               if (dig_enc->active_mst_links == 0) {
+                       /* drop link */
+               }
+
+               break;
+       }
+
+}
+
+static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
+                                  const struct drm_display_mode *mode,
+                                  struct drm_display_mode *adjusted_mode)
+{
+       struct radeon_encoder_mst *mst_enc;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       int bpp = 24;
+
+       mst_enc = radeon_encoder->enc_priv;
+
+       mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp);
+
+       mst_enc->primary->active_device = mst_enc->primary->devices & mst_enc->connector->devices;
+       DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n",
+                     mst_enc->primary->active_device, mst_enc->primary->devices,
+                     mst_enc->connector->devices, mst_enc->primary->base.encoder_type);
+
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+       {
+         struct radeon_connector_atom_dig *dig_connector;
+
+         dig_connector = mst_enc->connector->con_priv;
+         dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
+         dig_connector->dp_clock = radeon_dp_get_max_link_rate(&mst_enc->connector->base,
+                                                               dig_connector->dpcd);
+         DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
+                       dig_connector->dp_lane_count, dig_connector->dp_clock);
+       }
+       return true;
+}
+
+static void radeon_mst_encoder_prepare(struct drm_encoder *encoder)
+{
+       struct radeon_connector *radeon_connector;
+       struct radeon_encoder *radeon_encoder, *primary;
+       struct radeon_encoder_mst *mst_enc;
+       struct radeon_encoder_atom_dig *dig_enc;
+
+       radeon_connector = radeon_mst_find_connector(encoder);
+       if (!radeon_connector) {
+               DRM_DEBUG_KMS("failed to find connector %p\n", encoder);
+               return;
+       }
+       radeon_encoder = to_radeon_encoder(encoder);
+
+       radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+       mst_enc = radeon_encoder->enc_priv;
+
+       primary = mst_enc->primary;
+
+       dig_enc = primary->enc_priv;
+
+       mst_enc->port = radeon_connector->port;
+
+       if (dig_enc->dig_encoder == -1) {
+               dig_enc->dig_encoder = radeon_atom_pick_dig_encoder(&primary->base, -1);
+               primary->offset = radeon_atom_set_enc_offset(dig_enc->dig_encoder);
+               atombios_set_mst_encoder_crtc_source(encoder, dig_enc->dig_encoder);
+
+
+       }
+       DRM_DEBUG_KMS("%d %d\n", dig_enc->dig_encoder, primary->offset);
+}
+
+static void
+radeon_mst_encoder_mode_set(struct drm_encoder *encoder,
+                            struct drm_display_mode *mode,
+                            struct drm_display_mode *adjusted_mode)
+{
+       DRM_DEBUG_KMS("\n");
+}
+
+static void radeon_mst_encoder_commit(struct drm_encoder *encoder)
+{
+       radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+       DRM_DEBUG_KMS("\n");
+}
+
+static const struct drm_encoder_helper_funcs radeon_mst_helper_funcs = {
+       .dpms = radeon_mst_encoder_dpms,
+       .mode_fixup = radeon_mst_mode_fixup,
+       .prepare = radeon_mst_encoder_prepare,
+       .mode_set = radeon_mst_encoder_mode_set,
+       .commit = radeon_mst_encoder_commit,
+};
+
+void radeon_dp_mst_encoder_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+       kfree(encoder);
+}
+
+static const struct drm_encoder_funcs radeon_dp_mst_enc_funcs = {
+       .destroy = radeon_dp_mst_encoder_destroy,
+};
+
+static struct radeon_encoder *
+radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder;
+       struct radeon_encoder_mst *mst_enc;
+       struct drm_encoder *encoder;
+       struct drm_connector_helper_funcs *connector_funcs = connector->base.helper_private;
+       struct drm_encoder *enc_master = connector_funcs->best_encoder(&connector->base);
+
+       DRM_DEBUG_KMS("enc master is %p\n", enc_master);
+       radeon_encoder = kzalloc(sizeof(*radeon_encoder), GFP_KERNEL);
+       if (!radeon_encoder)
+               return NULL;
+
+       radeon_encoder->enc_priv = kzalloc(sizeof(*mst_enc), GFP_KERNEL);
+       if (!radeon_encoder->enc_priv) {
+               kfree(radeon_encoder);
+               return NULL;
+       }
+       encoder = &radeon_encoder->base;
+       switch (rdev->num_crtc) {
+       case 1:
+               encoder->possible_crtcs = 0x1;
+               break;
+       case 2:
+       default:
+               encoder->possible_crtcs = 0x3;
+               break;
+       case 4:
+               encoder->possible_crtcs = 0xf;
+               break;
+       case 6:
+               encoder->possible_crtcs = 0x3f;
+               break;
+       }
+
+       drm_encoder_init(dev, &radeon_encoder->base, &radeon_dp_mst_enc_funcs,
+                        DRM_MODE_ENCODER_DPMST);
+       drm_encoder_helper_add(encoder, &radeon_mst_helper_funcs);
+
+       mst_enc = radeon_encoder->enc_priv;
+       mst_enc->connector = connector;
+       mst_enc->primary = to_radeon_encoder(enc_master);
+       radeon_encoder->is_mst_encoder = true;
+       return radeon_encoder;
+}
+
+int
+radeon_dp_mst_init(struct radeon_connector *radeon_connector)
+{
+       struct drm_device *dev = radeon_connector->base.dev;
+
+       if (!radeon_connector->ddc_bus->has_aux)
+               return 0;
+
+       radeon_connector->mst_mgr.cbs = &mst_cbs;
+       return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev->dev,
+                                           &radeon_connector->ddc_bus->aux, 16, 6,
+                                           radeon_connector->base.base.id);
+}
+
+int
+radeon_dp_mst_probe(struct radeon_connector *radeon_connector)
+{
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       int ret;
+       u8 msg[1];
+
+       if (dig_connector->dpcd[DP_DPCD_REV] < 0x12)
+               return 0;
+
+       ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_MSTM_CAP, msg,
+                              1);
+       if (ret) {
+               if (msg[0] & DP_MST_CAP) {
+                       DRM_DEBUG_KMS("Sink is MST capable\n");
+                       dig_connector->is_mst = true;
+               } else {
+                       DRM_DEBUG_KMS("Sink is not MST capable\n");
+                       dig_connector->is_mst = false;
+               }
+
+       }
+       drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr,
+                                       dig_connector->is_mst);
+       return dig_connector->is_mst;
+}
+
+int
+radeon_dp_mst_check_status(struct radeon_connector *radeon_connector)
+{
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       int retry;
+
+       if (dig_connector->is_mst) {
+               u8 esi[16] = { 0 };
+               int dret;
+               int ret = 0;
+               bool handled;
+
+               dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux,
+                                      DP_SINK_COUNT_ESI, esi, 8);
+go_again:
+               if (dret == 8) {
+                       DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+                       ret = drm_dp_mst_hpd_irq(&radeon_connector->mst_mgr, esi, &handled);
+
+                       if (handled) {
+                               for (retry = 0; retry < 3; retry++) {
+                                       int wret;
+                                       wret = drm_dp_dpcd_write(&radeon_connector->ddc_bus->aux,
+                                                                DP_SINK_COUNT_ESI + 1, &esi[1], 3);
+                                       if (wret == 3)
+                                               break;
+                               }
+
+                               dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux,
+                                                       DP_SINK_COUNT_ESI, esi, 8);
+                               if (dret == 8) {
+                                       DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+                                       goto go_again;
+                               }
+                       } else
+                               ret = 0;
+
+                       return ret;
+               } else {
+                       DRM_DEBUG_KMS("failed to get ESI - device may have failed %d\n", ret);
+                       dig_connector->is_mst = false;
+                       drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr,
+                                                       dig_connector->is_mst);
+                       /* send a hotplug event */
+               }
+       }
+       return -EINVAL;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+
+static int radeon_debugfs_mst_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *)m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       struct radeon_connector_atom_dig *dig_connector;
+       int i;
+
+       drm_modeset_lock_all(dev);
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+                       continue;
+
+               radeon_connector = to_radeon_connector(connector);
+               dig_connector = radeon_connector->con_priv;
+               if (radeon_connector->is_mst_connector)
+                       continue;
+               if (!dig_connector->is_mst)
+                       continue;
+               drm_dp_mst_dump_topology(m, &radeon_connector->mst_mgr);
+
+               for (i = 0; i < radeon_connector->enabled_attribs; i++)
+                       seq_printf(m, "attrib %d: %d %d\n", i,
+                                  radeon_connector->cur_stream_attribs[i].fe,
+                                  radeon_connector->cur_stream_attribs[i].slots);
+       }
+       drm_modeset_unlock_all(dev);
+       return 0;
+}
+
+static struct drm_info_list radeon_debugfs_mst_list[] = {
+       {"radeon_mst_info", &radeon_debugfs_mst_info, 0, NULL},
+};
+#endif
+
+int radeon_mst_debugfs_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, radeon_debugfs_mst_list, 1);
+#endif
+       return 0;
+}
index 5d684beb48d32b9597fc604f6dee6790953fbf70..d688f6cd1ae4500a0de3741d35a0a7275489998f 100644 (file)
@@ -190,6 +190,8 @@ int radeon_deep_color = 0;
 int radeon_use_pflipirq = 2;
 int radeon_bapm = -1;
 int radeon_backlight = -1;
+int radeon_auxch = -1;
+int radeon_mst = 0;
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -239,7 +241,7 @@ module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444);
 MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)");
 module_param_named(msi, radeon_msi, int, 0444);
 
-MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)");
+MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (default 10000 = 10 seconds, 0 = disable)");
 module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444);
 
 MODULE_PARM_DESC(fastfb, "Direct FB access for IGP chips (0 = disable, 1 = enable)");
@@ -275,6 +277,12 @@ module_param_named(bapm, radeon_bapm, int, 0444);
 MODULE_PARM_DESC(backlight, "backlight support (1 = enable, 0 = disable, -1 = auto)");
 module_param_named(backlight, radeon_backlight, int, 0444);
 
+MODULE_PARM_DESC(auxch, "Use native auxch experimental support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(auxch, radeon_auxch, int, 0444);
+
+MODULE_PARM_DESC(mst, "DisplayPort MST experimental support (1 = enable, 0 = disable)");
+module_param_named(mst, radeon_mst, int, 0444);
+
 static struct pci_device_id pciidlist[] = {
        radeon_PCI_IDS
 };
index 6b670b0bc47bb9dca0238ef35dcff1cc2f686c34..ef99917f000d96a7dcf3fc88f089bdf08e0afc28 100644 (file)
@@ -179,9 +179,12 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder,
                    (rdev->pdev->subsystem_vendor == 0x1734) &&
                    (rdev->pdev->subsystem_device == 0x1107))
                        use_bl = false;
+/* Older PPC macs use on-GPU backlight controller */
+#ifndef CONFIG_PPC_PMAC
                /* disable native backlight control on older asics */
                else if (rdev->family < CHIP_R600)
                        use_bl = false;
+#endif
                else
                        use_bl = true;
        }
@@ -244,7 +247,16 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                radeon_connector = to_radeon_connector(connector);
-               if (radeon_encoder->active_device & radeon_connector->devices)
+               if (radeon_encoder->is_mst_encoder) {
+                       struct radeon_encoder_mst *mst_enc;
+
+                       if (!radeon_connector->is_mst_connector)
+                               continue;
+
+                       mst_enc = radeon_encoder->enc_priv;
+                       if (mst_enc->connector == radeon_connector->mst_port)
+                               return connector;
+               } else if (radeon_encoder->active_device & radeon_connector->devices)
                        return connector;
        }
        return NULL;
@@ -390,6 +402,9 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
        case DRM_MODE_CONNECTOR_DVID:
        case DRM_MODE_CONNECTOR_HDMIA:
        case DRM_MODE_CONNECTOR_DisplayPort:
+               if (radeon_connector->is_mst_connector)
+                       return false;
+
                dig_connector = radeon_connector->con_priv;
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
index ea276ff6d174283d0fee755530c90ea36c6d526d..aeb676708e60cfb1871326bfc5a689631bb98741 100644 (file)
@@ -257,6 +257,7 @@ static int radeonfb_create(struct drm_fb_helper *helper,
        }
 
        info->par = rfbdev;
+       info->skip_vt_switch = true;
 
        ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
        if (ret) {
@@ -434,3 +435,13 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
                return true;
        return false;
 }
+
+void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector)
+{
+       drm_fb_helper_add_one_connector(&rdev->mode_info.rfbdev->helper, connector);
+}
+
+void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector)
+{
+       drm_fb_helper_remove_one_connector(&rdev->mode_info.rfbdev->helper, connector);
+}
index d13d1b5a859f5b4d6aa69adc18cf85a2375398d1..df09ca7c488949896f68ff1d78ad7e152f0fd9a5 100644 (file)
@@ -1030,37 +1030,59 @@ static inline bool radeon_test_signaled(struct radeon_fence *fence)
        return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags);
 }
 
+struct radeon_wait_cb {
+       struct fence_cb base;
+       struct task_struct *task;
+};
+
+static void
+radeon_fence_wait_cb(struct fence *fence, struct fence_cb *cb)
+{
+       struct radeon_wait_cb *wait =
+               container_of(cb, struct radeon_wait_cb, base);
+
+       wake_up_process(wait->task);
+}
+
 static signed long radeon_fence_default_wait(struct fence *f, bool intr,
                                             signed long t)
 {
        struct radeon_fence *fence = to_radeon_fence(f);
        struct radeon_device *rdev = fence->rdev;
-       bool signaled;
+       struct radeon_wait_cb cb;
 
-       fence_enable_sw_signaling(&fence->base);
+       cb.task = current;
 
-       /*
-        * This function has to return -EDEADLK, but cannot hold
-        * exclusive_lock during the wait because some callers
-        * may already hold it. This means checking needs_reset without
-        * lock, and not fiddling with any gpu internals.
-        *
-        * The callback installed with fence_enable_sw_signaling will
-        * run before our wait_event_*timeout call, so we will see
-        * both the signaled fence and the changes to needs_reset.
-        */
+       if (fence_add_callback(f, &cb.base, radeon_fence_wait_cb))
+               return t;
+
+       while (t > 0) {
+               if (intr)
+                       set_current_state(TASK_INTERRUPTIBLE);
+               else
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+
+               /*
+                * radeon_test_signaled must be called after
+                * set_current_state to prevent a race with wake_up_process
+                */
+               if (radeon_test_signaled(fence))
+                       break;
+
+               if (rdev->needs_reset) {
+                       t = -EDEADLK;
+                       break;
+               }
+
+               t = schedule_timeout(t);
+
+               if (t > 0 && intr && signal_pending(current))
+                       t = -ERESTARTSYS;
+       }
+
+       __set_current_state(TASK_RUNNING);
+       fence_remove_callback(f, &cb.base);
 
-       if (intr)
-               t = wait_event_interruptible_timeout(rdev->fence_queue,
-                       ((signaled = radeon_test_signaled(fence)) ||
-                        rdev->needs_reset), t);
-       else
-               t = wait_event_timeout(rdev->fence_queue,
-                       ((signaled = radeon_test_signaled(fence)) ||
-                        rdev->needs_reset), t);
-
-       if (t > 0 && !signaled)
-               return -EDEADLK;
        return t;
 }
 
index 00fc59762e0df3bba0758d1f18e90328e5726635..7162c935371c66a3abcf3fcf3734c1d234e3bb37 100644 (file)
@@ -87,6 +87,20 @@ static void radeon_hotplug_work_func(struct work_struct *work)
        drm_helper_hpd_irq_event(dev);
 }
 
+static void radeon_dp_work_func(struct work_struct *work)
+{
+       struct radeon_device *rdev = container_of(work, struct radeon_device,
+                                                 dp_work);
+       struct drm_device *dev = rdev->ddev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+
+       /* this should take a mutex */
+       if (mode_config->num_connector) {
+               list_for_each_entry(connector, &mode_config->connector_list, head)
+                       radeon_connector_hotplug(connector);
+       }
+}
 /**
  * radeon_driver_irq_preinstall_kms - drm irq preinstall callback
  *
@@ -276,6 +290,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
        }
 
        INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
+       INIT_WORK(&rdev->dp_work, radeon_dp_work_func);
        INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
 
        rdev->irq.installed = true;
index 061eaa9c19c7c0d9add6d7fbf84145fc12afb5b7..3db23007cdf469c8ee9271d23b25a4bbd078d2e6 100644 (file)
@@ -103,15 +103,14 @@ static const struct kgd2kfd_calls *kgd2kfd;
 bool radeon_kfd_init(void)
 {
 #if defined(CONFIG_HSA_AMD_MODULE)
-       bool (*kgd2kfd_init_p)(unsigned, const struct kfd2kgd_calls*,
-                               const struct kgd2kfd_calls**);
+       bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**);
 
        kgd2kfd_init_p = symbol_request(kgd2kfd_init);
 
        if (kgd2kfd_init_p == NULL)
                return false;
 
-       if (!kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kfd2kgd, &kgd2kfd)) {
+       if (!kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kgd2kfd)) {
                symbol_put(kgd2kfd_init);
                kgd2kfd = NULL;
 
@@ -120,7 +119,7 @@ bool radeon_kfd_init(void)
 
        return true;
 #elif defined(CONFIG_HSA_AMD)
-       if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kfd2kgd, &kgd2kfd)) {
+       if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd)) {
                kgd2kfd = NULL;
 
                return false;
@@ -143,7 +142,8 @@ void radeon_kfd_fini(void)
 void radeon_kfd_device_probe(struct radeon_device *rdev)
 {
        if (kgd2kfd)
-               rdev->kfd = kgd2kfd->probe((struct kgd_dev *)rdev, rdev->pdev);
+               rdev->kfd = kgd2kfd->probe((struct kgd_dev *)rdev,
+                       rdev->pdev, &kfd2kgd);
 }
 
 void radeon_kfd_device_init(struct radeon_device *rdev)
@@ -153,7 +153,7 @@ void radeon_kfd_device_init(struct radeon_device *rdev)
                        .compute_vmid_bitmap = 0xFF00,
 
                        .first_compute_pipe = 1,
-                       .compute_pipe_count = 8 - 1,
+                       .compute_pipe_count = 4 - 1,
                };
 
                radeon_doorbell_get_kfd_info(rdev,
index 686411e4e4f6a3620289be34106ae5d38c9f6b93..7b2a7335cc5d557eafa6864d50cb6ebc9cdfb5ff 100644 (file)
@@ -547,6 +547,35 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                else
                        *value = 1;
                break;
+       case RADEON_INFO_CURRENT_GPU_TEMP:
+               /* get temperature in millidegrees C */
+               if (rdev->asic->pm.get_temperature)
+                       *value = radeon_get_temperature(rdev);
+               else
+                       *value = 0;
+               break;
+       case RADEON_INFO_CURRENT_GPU_SCLK:
+               /* get sclk in Mhz */
+               if (rdev->pm.dpm_enabled)
+                       *value = radeon_dpm_get_current_sclk(rdev) / 100;
+               else
+                       *value = rdev->pm.current_sclk / 100;
+               break;
+       case RADEON_INFO_CURRENT_GPU_MCLK:
+               /* get mclk in Mhz */
+               if (rdev->pm.dpm_enabled)
+                       *value = radeon_dpm_get_current_mclk(rdev) / 100;
+               else
+                       *value = rdev->pm.current_mclk / 100;
+               break;
+       case RADEON_INFO_READ_REG:
+               if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {
+                       DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
+                       return -EFAULT;
+               }
+               if (radeon_get_allowed_info_register(rdev, *value, value))
+                       return -EINVAL;
+               break;
        default:
                DRM_DEBUG_KMS("Invalid request %d\n", info->request);
                return -EINVAL;
index 920a8be8abada71c8b1473f844e39ca3535807a8..fa91a17b81b69c715d162b8c92dd66a4a6add914 100644 (file)
@@ -33,6 +33,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_dp_helper.h>
+#include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_fixed.h>
 #include <drm/drm_crtc_helper.h>
 #include <linux/i2c.h>
@@ -85,6 +86,13 @@ enum radeon_hpd_id {
        RADEON_HPD_NONE = 0xff,
 };
 
+enum radeon_output_csc {
+       RADEON_OUTPUT_CSC_BYPASS = 0,
+       RADEON_OUTPUT_CSC_TVRGB = 1,
+       RADEON_OUTPUT_CSC_YCBCR601 = 2,
+       RADEON_OUTPUT_CSC_YCBCR709 = 3,
+};
+
 #define RADEON_MAX_I2C_BUS 16
 
 /* radeon gpio-based i2c
@@ -255,6 +263,8 @@ struct radeon_mode_info {
        struct drm_property *audio_property;
        /* FMT dithering */
        struct drm_property *dither_property;
+       /* Output CSC */
+       struct drm_property *output_csc_property;
        /* hardcoded DFP edid from BIOS */
        struct edid *bios_hardcoded_edid;
        int bios_hardcoded_edid_size;
@@ -265,6 +275,9 @@ struct radeon_mode_info {
        u16 firmware_flags;
        /* pointer to backlight encoder */
        struct radeon_encoder *bl_encoder;
+
+       /* bitmask for active encoder frontends */
+       uint32_t active_encoders;
 };
 
 #define RADEON_MAX_BL_LEVEL 0xFF
@@ -357,6 +370,7 @@ struct radeon_crtc {
        u32 wm_low;
        u32 wm_high;
        struct drm_display_mode hw_mode;
+       enum radeon_output_csc output_csc;
 };
 
 struct radeon_encoder_primary_dac {
@@ -426,12 +440,24 @@ struct radeon_encoder_atom_dig {
        uint8_t backlight_level;
        int panel_mode;
        struct radeon_afmt *afmt;
+       int active_mst_links;
 };
 
 struct radeon_encoder_atom_dac {
        enum radeon_tv_std tv_std;
 };
 
+struct radeon_encoder_mst {
+       int crtc;
+       struct radeon_encoder *primary;
+       struct radeon_connector *connector;
+       struct drm_dp_mst_port *port;
+       int pbn;
+       int fe;
+       bool fe_from_be;
+       bool enc_active;
+};
+
 struct radeon_encoder {
        struct drm_encoder base;
        uint32_t encoder_enum;
@@ -450,6 +476,11 @@ struct radeon_encoder {
        bool is_ext_encoder;
        u16 caps;
        struct radeon_audio_funcs *audio;
+       enum radeon_output_csc output_csc;
+       bool can_mst;
+       uint32_t offset;
+       bool is_mst_encoder;
+       /* front end for this mst encoder */
 };
 
 struct radeon_connector_atom_dig {
@@ -460,6 +491,7 @@ struct radeon_connector_atom_dig {
        int dp_clock;
        int dp_lane_count;
        bool edp_on;
+       bool is_mst;
 };
 
 struct radeon_gpio_rec {
@@ -503,6 +535,11 @@ enum radeon_connector_dither {
        RADEON_FMT_DITHER_ENABLE = 1,
 };
 
+struct stream_attribs {
+       uint16_t fe;
+       uint16_t slots;
+};
+
 struct radeon_connector {
        struct drm_connector base;
        uint32_t connector_id;
@@ -524,6 +561,14 @@ struct radeon_connector {
        enum radeon_connector_audio audio;
        enum radeon_connector_dither dither;
        int pixelclock_for_modeset;
+       bool is_mst_connector;
+       struct radeon_connector *mst_port;
+       struct drm_dp_mst_port *port;
+       struct drm_dp_mst_topology_mgr mst_mgr;
+
+       struct radeon_encoder *mst_encoder;
+       struct stream_attribs cur_stream_attribs[6];
+       int enabled_attribs;
 };
 
 struct radeon_framebuffer {
@@ -708,15 +753,26 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
                                    struct drm_connector *connector);
+int radeon_dp_get_max_link_rate(struct drm_connector *connector,
+                               u8 *dpcd);
 extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
                                         u8 power_state);
 extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
+extern ssize_t
+radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg);
+
 extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
+extern void atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override);
 extern void radeon_atom_encoder_init(struct radeon_device *rdev);
 extern void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev);
 extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
                                           int action, uint8_t lane_num,
                                           uint8_t lane_set);
+extern void atombios_dig_transmitter_setup2(struct drm_encoder *encoder,
+                                           int action, uint8_t lane_num,
+                                           uint8_t lane_set, int fe);
+extern void atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder,
+                                                int fe);
 extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder);
 extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder);
 void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);
@@ -929,7 +985,23 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
 void radeon_fb_output_poll_changed(struct radeon_device *rdev);
 
 void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id);
+
+void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector);
+void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector);
+
 void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);
 
 int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled);
+
+/* mst */
+int radeon_dp_mst_init(struct radeon_connector *radeon_connector);
+int radeon_dp_mst_probe(struct radeon_connector *radeon_connector);
+int radeon_dp_mst_check_status(struct radeon_connector *radeon_connector);
+int radeon_mst_debugfs_init(struct radeon_device *rdev);
+void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode);
+
+void radeon_setup_mst_connector(struct drm_device *dev);
+
+int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx);
+void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx);
 #endif
index 43e09942823ec0fbd554800d36585eea91531989..318165d4855c4bf3aa9e4a23bddc38cc25481968 100644 (file)
@@ -173,17 +173,6 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
                else
                        rbo->placements[i].lpfn = 0;
        }
-
-       /*
-        * Use two-ended allocation depending on the buffer size to
-        * improve fragmentation quality.
-        * 512kb was measured as the most optimal number.
-        */
-       if (rbo->tbo.mem.size > 512 * 1024) {
-               for (i = 0; i < c; i++) {
-                       rbo->placements[i].flags |= TTM_PL_FLAG_TOPDOWN;
-               }
-       }
 }
 
 int radeon_bo_create(struct radeon_device *rdev,
index 9f758d39420dd4affddb42116a09e695a17b6abe..33cf4108386dbba4ef70a0e372eb992d1ff7e4d3 100644 (file)
@@ -852,6 +852,12 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
                        single_display = false;
        }
 
+       /* 120hz tends to be problematic even if they are under the
+        * vblank limit.
+        */
+       if (single_display && (r600_dpm_get_vrefresh(rdev) >= 120))
+               single_display = false;
+
        /* certain older asics have a separare 3D performance state,
         * so try that first if the user selected performance
         */
index d81182ad53ec6920b4f7027595882cebf26cdcfc..97a904835759f7876b2b69be104493cf302554a7 100644 (file)
@@ -694,6 +694,10 @@ int rs600_irq_set(struct radeon_device *rdev)
        WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
        if (ASIC_IS_DCE2(rdev))
                WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
+
+       /* posting read */
+       RREG32(R_000040_GEN_INT_CNTL);
+
        return 0;
 }
 
index 9031f4b6982417462458b026f8c1503cde82397c..cb0afe78abed4562fe1df4e64769216f151285d8 100644 (file)
@@ -1001,6 +1001,28 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                           ps->sclk_high, ps->max_voltage);
 }
 
+/* get the current sclk in 10 khz units */
+u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK;
+       u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
+       u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1;
+       u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 +
+               ((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1;
+       u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) /
+               (post_div * ref_div);
+
+       return sclk;
+}
+
+/* get the current mclk in 10 khz units */
+u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct igp_power_info *pi = rs780_get_pi(rdev);
+
+       return pi->bootup_uma_clk;
+}
+
 int rs780_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level)
 {
index 6a5c233361e9dbadbcb629c9583baf946e8abc7b..97e5a6f1ce5837fbaaba787991f83a0b4ab7f950 100644 (file)
@@ -2050,6 +2050,52 @@ void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
        }
 }
 
+/* get the current sclk in 10 khz units */
+u32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+       struct rv6xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->sclk;
+       }
+}
+
+/* get the current mclk in 10 khz units */
+u32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+       struct rv6xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->mclk;
+       }
+}
+
 void rv6xx_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index 306732641b231aefb16ddc3186359ae872af5801..b9c770745a7a1f717cb9c894a6882c090fd8153c 100644 (file)
@@ -2492,6 +2492,50 @@ void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
        }
 }
 
+u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return  pl->sclk;
+       }
+}
+
+u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return  pl->mclk;
+       }
+}
+
 void rv770_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index 73107fe9e46f7de25d1d22b3ad3ba0b28f40c8f0..b1d74bc375d82f665dbb4455db5aa84db0c8d8dc 100644 (file)
@@ -1264,6 +1264,36 @@ static void si_init_golden_registers(struct radeon_device *rdev)
        }
 }
 
+/**
+ * si_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int si_get_allowed_info_register(struct radeon_device *rdev,
+                                u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS2:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case (DMA_STATUS_REG + DMA0_REGISTER_OFFSET):
+       case (DMA_STATUS_REG + DMA1_REGISTER_OFFSET):
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 #define PCIE_BUS_CLK                10000
 #define TCLK                        (PCIE_BUS_CLK / 10)
 
@@ -3162,6 +3192,8 @@ static void si_gpu_init(struct radeon_device *rdev)
        }
 
        WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+       WREG32(SRBM_INT_CNTL, 1);
+       WREG32(SRBM_INT_ACK, 1);
 
        evergreen_fix_pci_max_read_req_size(rdev);
 
@@ -4699,12 +4731,6 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
                switch (pkt.type) {
                case RADEON_PACKET_TYPE0:
                        dev_err(rdev->dev, "Packet0 not allowed!\n");
-                       for (i = 0; i < ib->length_dw; i++) {
-                               if (i == idx)
-                                       printk("\t0x%08x <---\n", ib->ptr[i]);
-                               else
-                                       printk("\t0x%08x\n", ib->ptr[i]);
-                       }
                        ret = -EINVAL;
                        break;
                case RADEON_PACKET_TYPE2:
@@ -4736,8 +4762,15 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
                        ret = -EINVAL;
                        break;
                }
-               if (ret)
+               if (ret) {
+                       for (i = 0; i < ib->length_dw; i++) {
+                               if (i == idx)
+                                       printk("\t0x%08x <---\n", ib->ptr[i]);
+                               else
+                                       printk("\t0x%08x\n", ib->ptr[i]);
+                       }
                        break;
+               }
        } while (idx < ib->length_dw);
 
        return ret;
@@ -5910,6 +5943,7 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
        tmp = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
        WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, tmp);
        WREG32(GRBM_INT_CNTL, 0);
+       WREG32(SRBM_INT_CNTL, 0);
        if (rdev->num_crtc >= 2) {
                WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
                WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
@@ -6051,12 +6085,12 @@ int si_irq_set(struct radeon_device *rdev)
                (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
 
        if (!ASIC_IS_NODCE(rdev)) {
-               hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+               hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
        }
 
        dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
@@ -6119,27 +6153,27 @@ int si_irq_set(struct radeon_device *rdev)
        }
        if (rdev->irq.hpd[0]) {
                DRM_DEBUG("si_irq_set: hpd 1\n");
-               hpd1 |= DC_HPDx_INT_EN;
+               hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[1]) {
                DRM_DEBUG("si_irq_set: hpd 2\n");
-               hpd2 |= DC_HPDx_INT_EN;
+               hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[2]) {
                DRM_DEBUG("si_irq_set: hpd 3\n");
-               hpd3 |= DC_HPDx_INT_EN;
+               hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[3]) {
                DRM_DEBUG("si_irq_set: hpd 4\n");
-               hpd4 |= DC_HPDx_INT_EN;
+               hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[4]) {
                DRM_DEBUG("si_irq_set: hpd 5\n");
-               hpd5 |= DC_HPDx_INT_EN;
+               hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[5]) {
                DRM_DEBUG("si_irq_set: hpd 6\n");
-               hpd6 |= DC_HPDx_INT_EN;
+               hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
 
        WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
@@ -6199,6 +6233,9 @@ int si_irq_set(struct radeon_device *rdev)
 
        WREG32(CG_THERMAL_INT, thermal_int);
 
+       /* posting read */
+       RREG32(SRBM_STATUS);
+
        return 0;
 }
 
@@ -6299,6 +6336,37 @@ static inline void si_irq_ack(struct radeon_device *rdev)
                tmp |= DC_HPDx_INT_ACK;
                WREG32(DC_HPD6_INT_CONTROL, tmp);
        }
+
+       if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD1_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD1_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD2_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD2_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD3_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD3_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD4_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD4_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD5_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD6_INT_CONTROL, tmp);
+       }
 }
 
 static void si_irq_disable(struct radeon_device *rdev)
@@ -6364,6 +6432,7 @@ int si_irq_process(struct radeon_device *rdev)
        u32 src_id, src_data, ring_id;
        u32 ring_index;
        bool queue_hotplug = false;
+       bool queue_dp = false;
        bool queue_thermal = false;
        u32 status, addr;
 
@@ -6604,11 +6673,57 @@ restart_ih:
                                        DRM_DEBUG("IH: HPD6\n");
                                }
                                break;
+                       case 6:
+                               if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 1\n");
+                               }
+                               break;
+                       case 7:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 2\n");
+                               }
+                               break;
+                       case 8:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 3\n");
+                               }
+                               break;
+                       case 9:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 4\n");
+                               }
+                               break;
+                       case 10:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 5\n");
+                               }
+                               break;
+                       case 11:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 6\n");
+                               }
+                               break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
                        }
                        break;
+               case 96:
+                       DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
+                       WREG32(SRBM_INT_ACK, 0x1);
+                       break;
                case 124: /* UVD */
                        DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
                        radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
@@ -6682,6 +6797,8 @@ restart_ih:
                rptr &= rdev->ih.ptr_mask;
                WREG32(IH_RB_RPTR, rptr);
        }
+       if (queue_dp)
+               schedule_work(&rdev->dp_work);
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_thermal && rdev->pm.dpm_enabled)
@@ -7119,8 +7236,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
        WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK);
 
        if (!vclk || !dclk) {
-               /* keep the Bypass mode, put PLL to sleep */
-               WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK);
+               /* keep the Bypass mode */
                return 0;
        }
 
@@ -7136,8 +7252,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
        /* set VCO_MODE to 1 */
        WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_VCO_MODE_MASK, ~UPLL_VCO_MODE_MASK);
 
-       /* toggle UPLL_SLEEP to 1 then back to 0 */
-       WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK);
+       /* disable sleep mode */
        WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_SLEEP_MASK);
 
        /* deassert UPLL_RESET */
index 7be11651b7e6c8e5fded976e33ea1ba65ace4775..b35bccfeef79c402c33b6406e0e70755fd4098ad 100644 (file)
@@ -6993,3 +6993,39 @@ void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                           current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
        }
 }
+
+u32 si_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 si_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->mclk;
+       }
+}
index cbd91d226f3ce232b5933686ad41cae3ace64ebe..3afac301398388315f78d6cb7cb62e84e7314581 100644 (file)
 #define        CC_SYS_RB_BACKEND_DISABLE                       0xe80
 #define        GC_USER_SYS_RB_BACKEND_DISABLE                  0xe84
 
+#define SRBM_READ_ERROR                                        0xE98
+#define SRBM_INT_CNTL                                  0xEA0
+#define SRBM_INT_ACK                                   0xEA8
+
 #define        SRBM_STATUS2                                    0x0EC4
 #define                DMA_BUSY                                (1 << 5)
 #define                DMA1_BUSY                               (1 << 6)
 
 #define DCCG_AUDIO_DTO0_PHASE                           0x05b0
 #define DCCG_AUDIO_DTO0_MODULE                          0x05b4
-#define DCCG_AUDIO_DTO1_PHASE                           0x05b8
-#define DCCG_AUDIO_DTO1_MODULE                          0x05bc
+#define DCCG_AUDIO_DTO1_PHASE                           0x05c0
+#define DCCG_AUDIO_DTO1_MODULE                          0x05c4
 
 #define AFMT_AUDIO_SRC_CONTROL                          0x713c
 #define                AFMT_AUDIO_SRC_SELECT(x)                (((x) & 7) << 0)
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xEF54
 #define UVD_RBC_RB_RPTR                                        0xF690
 #define UVD_RBC_RB_WPTR                                        0xF694
+#define UVD_STATUS                                     0xf6bc
 
 #define        UVD_CGC_CTRL                                    0xF4B0
 #      define DCM                                      (1 << 0)
index 25fd4ced36c83491b4cbfb841a57f30c3ae65130..cd0862809adff2f2749f90eff0b85007cc5e1d4f 100644 (file)
@@ -1837,6 +1837,34 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev
        }
 }
 
+u32 sumo_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct sumo_power_info *pi = sumo_get_pi(rdev);
+       struct radeon_ps *rps = &pi->current_rps;
+       struct sumo_ps *ps = sumo_get_ps(rps);
+       struct sumo_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >>
+               CURR_INDEX_SHIFT;
+
+       if (current_index == BOOST_DPM_LEVEL) {
+               pl = &pi->boost_pl;
+               return pl->sclk;
+       } else if (current_index >= ps->num_levels) {
+               return 0;
+       } else {
+               pl = &ps->levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 sumo_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+       return pi->sys_info.bootup_uma_clk;
+}
+
 void sumo_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index 38dacb7a3689e80c3ae41eb4c1826442e792ea79..a5b02c575d775b7b1a4409142507470e7f3fc415 100644 (file)
@@ -1964,6 +1964,31 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r
        }
 }
 
+u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct trinity_power_info *pi = trinity_get_pi(rdev);
+       struct radeon_ps *rps = &pi->current_rps;
+       struct trinity_ps *ps = trinity_get_ps(rps);
+       struct trinity_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
+               CURRENT_STATE_SHIFT;
+
+       if (current_index >= ps->num_levels) {
+               return 0;
+       } else {
+               pl = &ps->levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+       return pi->sys_info.bootup_uma_clk;
+}
+
 void trinity_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index 25c7a998fc2cf075fe1ecb6c8fe603f439abab7f..7d0b8ef9bea21ca04a7fc678f3913dc1768615fd 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/mutex.h>
 
 #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_fb_cma_helper.h>
@@ -99,9 +101,13 @@ static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
        clk_disable_unprepare(rcrtc->clock);
 }
 
+/* -----------------------------------------------------------------------------
+ * Hardware Setup
+ */
+
 static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 {
-       const struct drm_display_mode *mode = &rcrtc->crtc.mode;
+       const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
        unsigned long mode_clock = mode->clock * 1000;
        unsigned long clk;
        u32 value;
@@ -187,9 +193,19 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
                rcdu->dpad0_source = rcrtc->index;
 }
 
-void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
+static unsigned int plane_zpos(struct rcar_du_plane *plane)
+{
+       return to_rcar_du_plane_state(plane->plane.state)->zpos;
+}
+
+static const struct rcar_du_format_info *
+plane_format(struct rcar_du_plane *plane)
+{
+       return to_rcar_du_plane_state(plane->plane.state)->format;
+}
+
+static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
 {
-       struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
        struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES];
        unsigned int num_planes = 0;
        unsigned int prio = 0;
@@ -201,29 +217,30 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
                struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i];
                unsigned int j;
 
-               if (plane->crtc != &rcrtc->crtc || !plane->enabled)
+               if (plane->plane.state->crtc != &rcrtc->crtc)
                        continue;
 
                /* Insert the plane in the sorted planes array. */
                for (j = num_planes++; j > 0; --j) {
-                       if (planes[j-1]->zpos <= plane->zpos)
+                       if (plane_zpos(planes[j-1]) <= plane_zpos(plane))
                                break;
                        planes[j] = planes[j-1];
                }
 
                planes[j] = plane;
-               prio += plane->format->planes * 4;
+               prio += plane_format(plane)->planes * 4;
        }
 
        for (i = 0; i < num_planes; ++i) {
                struct rcar_du_plane *plane = planes[i];
-               unsigned int index = plane->hwindex;
+               struct drm_plane_state *state = plane->plane.state;
+               unsigned int index = to_rcar_du_plane_state(state)->hwindex;
 
                prio -= 4;
                dspr |= (index + 1) << prio;
                dptsr |= DPTSR_PnDK(index) |  DPTSR_PnTS(index);
 
-               if (plane->format->planes == 2) {
+               if (plane_format(plane)->planes == 2) {
                        index = (index + 1) % 8;
 
                        prio -= 4;
@@ -236,8 +253,6 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
         * with superposition controller 2.
         */
        if (rcrtc->index % 2) {
-               u32 value = rcar_du_group_read(rcrtc->group, DPTSR);
-
                /* The DPTSR register is updated when the display controller is
                 * stopped. We thus need to restart the DU. Once again, sorry
                 * for the flicker. One way to mitigate the issue would be to
@@ -245,29 +260,104 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
                 * split, or through a module parameter). Flicker would then
                 * occur only if we need to break the pre-association.
                 */
-               if (value != dptsr) {
+               mutex_lock(&rcrtc->group->lock);
+               if (rcar_du_group_read(rcrtc->group, DPTSR) != dptsr) {
                        rcar_du_group_write(rcrtc->group, DPTSR, dptsr);
                        if (rcrtc->group->used_crtcs)
                                rcar_du_group_restart(rcrtc->group);
                }
+               mutex_unlock(&rcrtc->group->lock);
        }
 
        rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR,
                            dspr);
 }
 
+/* -----------------------------------------------------------------------------
+ * Page Flip
+ */
+
+void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
+                                  struct drm_file *file)
+{
+       struct drm_pending_vblank_event *event;
+       struct drm_device *dev = rcrtc->crtc.dev;
+       unsigned long flags;
+
+       /* Destroy the pending vertical blanking event associated with the
+        * pending page flip, if any, and disable vertical blanking interrupts.
+        */
+       spin_lock_irqsave(&dev->event_lock, flags);
+       event = rcrtc->event;
+       if (event && event->base.file_priv == file) {
+               rcrtc->event = NULL;
+               event->base.destroy(&event->base);
+               drm_crtc_vblank_put(&rcrtc->crtc);
+       }
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
+{
+       struct drm_pending_vblank_event *event;
+       struct drm_device *dev = rcrtc->crtc.dev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       event = rcrtc->event;
+       rcrtc->event = NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       if (event == NULL)
+               return;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       drm_send_vblank_event(dev, rcrtc->index, event);
+       wake_up(&rcrtc->flip_wait);
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       drm_crtc_vblank_put(&rcrtc->crtc);
+}
+
+static bool rcar_du_crtc_page_flip_pending(struct rcar_du_crtc *rcrtc)
+{
+       struct drm_device *dev = rcrtc->crtc.dev;
+       unsigned long flags;
+       bool pending;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       pending = rcrtc->event != NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       return pending;
+}
+
+static void rcar_du_crtc_wait_page_flip(struct rcar_du_crtc *rcrtc)
+{
+       struct rcar_du_device *rcdu = rcrtc->group->dev;
+
+       if (wait_event_timeout(rcrtc->flip_wait,
+                              !rcar_du_crtc_page_flip_pending(rcrtc),
+                              msecs_to_jiffies(50)))
+               return;
+
+       dev_warn(rcdu->dev, "page flip timeout\n");
+
+       rcar_du_crtc_finish_page_flip(rcrtc);
+}
+
+/* -----------------------------------------------------------------------------
+ * Start/Stop and Suspend/Resume
+ */
+
 static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
 {
        struct drm_crtc *crtc = &rcrtc->crtc;
        bool interlaced;
-       unsigned int i;
 
        if (rcrtc->started)
                return;
 
-       if (WARN_ON(rcrtc->plane->format == NULL))
-               return;
-
        /* Set display off and background to black */
        rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
        rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
@@ -276,20 +366,8 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
        rcar_du_crtc_set_display_timing(rcrtc);
        rcar_du_group_set_routing(rcrtc->group);
 
-       mutex_lock(&rcrtc->group->planes.lock);
-       rcrtc->plane->enabled = true;
-       rcar_du_crtc_update_planes(crtc);
-       mutex_unlock(&rcrtc->group->planes.lock);
-
-       /* Setup planes. */
-       for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) {
-               struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i];
-
-               if (plane->crtc != crtc || !plane->enabled)
-                       continue;
-
-               rcar_du_plane_setup(plane);
-       }
+       /* Start with all planes disabled. */
+       rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
 
        /* Select master sync mode. This enables display operation in master
         * sync mode (with the HSYNC and VSYNC signals configured as outputs and
@@ -302,6 +380,9 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
 
        rcar_du_group_start_stop(rcrtc->group, true);
 
+       /* Turn vertical blanking interrupt reporting back on. */
+       drm_crtc_vblank_on(crtc);
+
        rcrtc->started = true;
 }
 
@@ -312,10 +393,12 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
        if (!rcrtc->started)
                return;
 
-       mutex_lock(&rcrtc->group->planes.lock);
-       rcrtc->plane->enabled = false;
-       rcar_du_crtc_update_planes(crtc);
-       mutex_unlock(&rcrtc->group->planes.lock);
+       /* Disable vertical blanking interrupt reporting. We first need to wait
+        * for page flip completion before stopping the CRTC as userspace
+        * expects page flips to eventually complete.
+        */
+       rcar_du_crtc_wait_page_flip(rcrtc);
+       drm_crtc_vblank_off(crtc);
 
        /* Select switch sync mode. This stops display operation and configures
         * the HSYNC and VSYNC signals as inputs.
@@ -335,196 +418,109 @@ void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc)
 
 void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
 {
-       if (rcrtc->dpms != DRM_MODE_DPMS_ON)
+       unsigned int i;
+
+       if (!rcrtc->enabled)
                return;
 
        rcar_du_crtc_get(rcrtc);
        rcar_du_crtc_start(rcrtc);
-}
-
-static void rcar_du_crtc_update_base(struct rcar_du_crtc *rcrtc)
-{
-       struct drm_crtc *crtc = &rcrtc->crtc;
-
-       rcar_du_plane_compute_base(rcrtc->plane, crtc->primary->fb);
-       rcar_du_plane_update_base(rcrtc->plane);
-}
-
-static void rcar_du_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
-       struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
 
-       if (mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
+       /* Commit the planes state. */
+       for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) {
+               struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i];
 
-       if (rcrtc->dpms == mode)
-               return;
+               if (plane->plane.state->crtc != &rcrtc->crtc)
+                       continue;
 
-       if (mode == DRM_MODE_DPMS_ON) {
-               rcar_du_crtc_get(rcrtc);
-               rcar_du_crtc_start(rcrtc);
-       } else {
-               rcar_du_crtc_stop(rcrtc);
-               rcar_du_crtc_put(rcrtc);
+               rcar_du_plane_setup(plane);
        }
 
-       rcrtc->dpms = mode;
+       rcar_du_crtc_update_planes(rcrtc);
 }
 
-static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc,
-                                   const struct drm_display_mode *mode,
-                                   struct drm_display_mode *adjusted_mode)
-{
-       /* TODO Fixup modes */
-       return true;
-}
+/* -----------------------------------------------------------------------------
+ * CRTC Functions
+ */
 
-static void rcar_du_crtc_mode_prepare(struct drm_crtc *crtc)
+static void rcar_du_crtc_enable(struct drm_crtc *crtc)
 {
        struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
 
-       /* We need to access the hardware during mode set, acquire a reference
-        * to the CRTC.
-        */
-       rcar_du_crtc_get(rcrtc);
+       if (rcrtc->enabled)
+               return;
 
-       /* Stop the CRTC and release the plane. Force the DPMS mode to off as a
-        * result.
-        */
-       rcar_du_crtc_stop(rcrtc);
-       rcar_du_plane_release(rcrtc->plane);
+       rcar_du_crtc_get(rcrtc);
+       rcar_du_crtc_start(rcrtc);
 
-       rcrtc->dpms = DRM_MODE_DPMS_OFF;
+       rcrtc->enabled = true;
 }
 
-static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
-                                struct drm_display_mode *mode,
-                                struct drm_display_mode *adjusted_mode,
-                                int x, int y,
-                                struct drm_framebuffer *old_fb)
+static void rcar_du_crtc_disable(struct drm_crtc *crtc)
 {
        struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
-       struct rcar_du_device *rcdu = rcrtc->group->dev;
-       const struct rcar_du_format_info *format;
-       int ret;
-
-       format = rcar_du_format_info(crtc->primary->fb->pixel_format);
-       if (format == NULL) {
-               dev_dbg(rcdu->dev, "mode_set: unsupported format %08x\n",
-                       crtc->primary->fb->pixel_format);
-               ret = -EINVAL;
-               goto error;
-       }
 
-       ret = rcar_du_plane_reserve(rcrtc->plane, format);
-       if (ret < 0)
-               goto error;
-
-       rcrtc->plane->format = format;
-
-       rcrtc->plane->src_x = x;
-       rcrtc->plane->src_y = y;
-       rcrtc->plane->width = mode->hdisplay;
-       rcrtc->plane->height = mode->vdisplay;
+       if (!rcrtc->enabled)
+               return;
 
-       rcar_du_plane_compute_base(rcrtc->plane, crtc->primary->fb);
+       rcar_du_crtc_stop(rcrtc);
+       rcar_du_crtc_put(rcrtc);
 
+       rcrtc->enabled = false;
        rcrtc->outputs = 0;
-
-       return 0;
-
-error:
-       /* There's no rollback/abort operation to clean up in case of error. We
-        * thus need to release the reference to the CRTC acquired in prepare()
-        * here.
-        */
-       rcar_du_crtc_put(rcrtc);
-       return ret;
 }
 
-static void rcar_du_crtc_mode_commit(struct drm_crtc *crtc)
+static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc,
+                                   const struct drm_display_mode *mode,
+                                   struct drm_display_mode *adjusted_mode)
 {
-       struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
-
-       /* We're done, restart the CRTC and set the DPMS mode to on. The
-        * reference to the DU acquired at prepare() time will thus be released
-        * by the DPMS handler (possibly called by the disable() handler).
-        */
-       rcar_du_crtc_start(rcrtc);
-       rcrtc->dpms = DRM_MODE_DPMS_ON;
+       /* TODO Fixup modes */
+       return true;
 }
 
-static int rcar_du_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-                                     struct drm_framebuffer *old_fb)
+static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc)
 {
+       struct drm_pending_vblank_event *event = crtc->state->event;
        struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+       struct drm_device *dev = rcrtc->crtc.dev;
+       unsigned long flags;
 
-       rcrtc->plane->src_x = x;
-       rcrtc->plane->src_y = y;
-
-       rcar_du_crtc_update_base(rcrtc);
+       if (event) {
+               WARN_ON(drm_crtc_vblank_get(crtc) != 0);
 
-       return 0;
+               spin_lock_irqsave(&dev->event_lock, flags);
+               rcrtc->event = event;
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+       }
 }
 
-static void rcar_du_crtc_disable(struct drm_crtc *crtc)
+static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc)
 {
        struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
 
-       rcar_du_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-       rcar_du_plane_release(rcrtc->plane);
+       rcar_du_crtc_update_planes(rcrtc);
 }
 
 static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
-       .dpms = rcar_du_crtc_dpms,
        .mode_fixup = rcar_du_crtc_mode_fixup,
-       .prepare = rcar_du_crtc_mode_prepare,
-       .commit = rcar_du_crtc_mode_commit,
-       .mode_set = rcar_du_crtc_mode_set,
-       .mode_set_base = rcar_du_crtc_mode_set_base,
        .disable = rcar_du_crtc_disable,
+       .enable = rcar_du_crtc_enable,
+       .atomic_begin = rcar_du_crtc_atomic_begin,
+       .atomic_flush = rcar_du_crtc_atomic_flush,
 };
 
-void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
-                                  struct drm_file *file)
-{
-       struct drm_pending_vblank_event *event;
-       struct drm_device *dev = rcrtc->crtc.dev;
-       unsigned long flags;
-
-       /* Destroy the pending vertical blanking event associated with the
-        * pending page flip, if any, and disable vertical blanking interrupts.
-        */
-       spin_lock_irqsave(&dev->event_lock, flags);
-       event = rcrtc->event;
-       if (event && event->base.file_priv == file) {
-               rcrtc->event = NULL;
-               event->base.destroy(&event->base);
-               drm_vblank_put(dev, rcrtc->index);
-       }
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-}
-
-static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
-{
-       struct drm_pending_vblank_event *event;
-       struct drm_device *dev = rcrtc->crtc.dev;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->event_lock, flags);
-       event = rcrtc->event;
-       rcrtc->event = NULL;
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-
-       if (event == NULL)
-               return;
-
-       spin_lock_irqsave(&dev->event_lock, flags);
-       drm_send_vblank_event(dev, rcrtc->index, event);
-       spin_unlock_irqrestore(&dev->event_lock, flags);
+static const struct drm_crtc_funcs crtc_funcs = {
+       .reset = drm_atomic_helper_crtc_reset,
+       .destroy = drm_crtc_cleanup,
+       .set_config = drm_atomic_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
+       .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
 
-       drm_vblank_put(dev, rcrtc->index);
-}
+/* -----------------------------------------------------------------------------
+ * Interrupt Handling
+ */
 
 static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
 {
@@ -544,41 +540,9 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
        return ret;
 }
 
-static int rcar_du_crtc_page_flip(struct drm_crtc *crtc,
-                                 struct drm_framebuffer *fb,
-                                 struct drm_pending_vblank_event *event,
-                                 uint32_t page_flip_flags)
-{
-       struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
-       struct drm_device *dev = rcrtc->crtc.dev;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->event_lock, flags);
-       if (rcrtc->event != NULL) {
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-               return -EBUSY;
-       }
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-
-       crtc->primary->fb = fb;
-       rcar_du_crtc_update_base(rcrtc);
-
-       if (event) {
-               event->pipe = rcrtc->index;
-               drm_vblank_get(dev, rcrtc->index);
-               spin_lock_irqsave(&dev->event_lock, flags);
-               rcrtc->event = event;
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-       }
-
-       return 0;
-}
-
-static const struct drm_crtc_funcs crtc_funcs = {
-       .destroy = drm_crtc_cleanup,
-       .set_config = drm_crtc_helper_set_config,
-       .page_flip = rcar_du_crtc_page_flip,
-};
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
 
 int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
 {
@@ -620,20 +584,24 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
                return -EPROBE_DEFER;
        }
 
+       init_waitqueue_head(&rcrtc->flip_wait);
+
        rcrtc->group = rgrp;
        rcrtc->mmio_offset = mmio_offsets[index];
        rcrtc->index = index;
-       rcrtc->dpms = DRM_MODE_DPMS_OFF;
-       rcrtc->plane = &rgrp->planes.planes[index % 2];
-
-       rcrtc->plane->crtc = crtc;
+       rcrtc->enabled = false;
 
-       ret = drm_crtc_init(rcdu->ddev, crtc, &crtc_funcs);
+       ret = drm_crtc_init_with_planes(rcdu->ddev, crtc,
+                                       &rgrp->planes.planes[index % 2].plane,
+                                       NULL, &crtc_funcs);
        if (ret < 0)
                return ret;
 
        drm_crtc_helper_add(crtc, &crtc_helper_funcs);
 
+       /* Start with vertical blanking interrupt reporting disabled. */
+       drm_crtc_vblank_off(crtc);
+
        /* Register the interrupt handler. */
        if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ_CLOCK)) {
                irq = platform_get_irq(pdev, index);
index d2f89f7d2e5e3e6c6001c63a49ff032ece9aeded..5d9aa9b33769eb225ea3919d2fc7f06842988f6f 100644 (file)
 #define __RCAR_DU_CRTC_H__
 
 #include <linux/mutex.h>
+#include <linux/wait.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 
 struct rcar_du_group;
-struct rcar_du_plane;
 
 struct rcar_du_crtc {
        struct drm_crtc crtc;
@@ -32,11 +32,12 @@ struct rcar_du_crtc {
        bool started;
 
        struct drm_pending_vblank_event *event;
+       wait_queue_head_t flip_wait;
+
        unsigned int outputs;
-       int dpms;
+       bool enabled;
 
        struct rcar_du_group *group;
-       struct rcar_du_plane *plane;
 };
 
 #define to_rcar_crtc(c)        container_of(c, struct rcar_du_crtc, crtc)
@@ -59,6 +60,5 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc);
 
 void rcar_du_crtc_route_output(struct drm_crtc *crtc,
                               enum rcar_du_output output);
-void rcar_du_crtc_update_planes(struct drm_crtc *crtc);
 
 #endif /* __RCAR_DU_CRTC_H__ */
index e0d74f821416cdf31ed7e738b8726395276891b6..da1216a73969ef62f062486734d5946082ee093f 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
+#include <linux/wait.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
@@ -163,6 +164,8 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
                return -ENOMEM;
        }
 
+       init_waitqueue_head(&rcdu->commit.wait);
+
        rcdu->dev = &pdev->dev;
        rcdu->info = np ? of_match_device(rcar_du_of_table, rcdu->dev)->data
                   : (void *)platform_get_device_id(pdev)->driver_data;
@@ -175,17 +178,19 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
        if (IS_ERR(rcdu->mmio))
                return PTR_ERR(rcdu->mmio);
 
-       /* DRM/KMS objects */
-       ret = rcar_du_modeset_init(rcdu);
+       /* Initialize vertical blanking interrupts handling. Start with vblank
+        * disabled for all CRTCs.
+        */
+       ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1);
        if (ret < 0) {
-               dev_err(&pdev->dev, "failed to initialize DRM/KMS\n");
+               dev_err(&pdev->dev, "failed to initialize vblank\n");
                goto done;
        }
 
-       /* vblank handling */
-       ret = drm_vblank_init(dev, (1 << rcdu->num_crtcs) - 1);
+       /* DRM/KMS objects */
+       ret = rcar_du_modeset_init(rcdu);
        if (ret < 0) {
-               dev_err(&pdev->dev, "failed to initialize vblank\n");
+               dev_err(&pdev->dev, "failed to initialize DRM/KMS\n");
                goto done;
        }
 
@@ -247,7 +252,8 @@ static const struct file_operations rcar_du_fops = {
 };
 
 static struct drm_driver rcar_du_driver = {
-       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME,
+       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
+                               | DRIVER_ATOMIC,
        .load                   = rcar_du_load,
        .unload                 = rcar_du_unload,
        .preclose               = rcar_du_preclose,
index c5b9ea6a7eaab38d370014b643298064ba9a32ab..c7c538dd2e683045e7bfefcfc4e198f9352f35bb 100644 (file)
@@ -15,6 +15,7 @@
 #define __RCAR_DU_DRV_H__
 
 #include <linux/kernel.h>
+#include <linux/wait.h>
 
 #include "rcar_du_crtc.h"
 #include "rcar_du_group.h"
@@ -64,6 +65,10 @@ struct rcar_du_device_info {
        unsigned int num_lvds;
 };
 
+#define RCAR_DU_MAX_CRTCS              3
+#define RCAR_DU_MAX_GROUPS             DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2)
+#define RCAR_DU_MAX_LVDS               2
+
 struct rcar_du_device {
        struct device *dev;
        const struct rcar_du_device_info *info;
@@ -73,13 +78,18 @@ struct rcar_du_device {
        struct drm_device *ddev;
        struct drm_fbdev_cma *fbdev;
 
-       struct rcar_du_crtc crtcs[3];
+       struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS];
        unsigned int num_crtcs;
 
-       struct rcar_du_group groups[2];
+       struct rcar_du_group groups[RCAR_DU_MAX_GROUPS];
 
        unsigned int dpad0_source;
-       struct rcar_du_lvdsenc *lvds[2];
+       struct rcar_du_lvdsenc *lvds[RCAR_DU_MAX_LVDS];
+
+       struct {
+               wait_queue_head_t wait;
+               u32 pending;
+       } commit;
 };
 
 static inline bool rcar_du_has(struct rcar_du_device *rcdu,
index 279167f783f67857ee3b37cd491419626933399d..d0ae1e8009c6b8982ddaf8746893770a21634ce8 100644 (file)
@@ -42,46 +42,40 @@ rcar_du_connector_best_encoder(struct drm_connector *connector)
  * Encoder
  */
 
-static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void rcar_du_encoder_disable(struct drm_encoder *encoder)
 {
        struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
 
-       if (mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
+       if (renc->lvds)
+               rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, false);
+}
+
+static void rcar_du_encoder_enable(struct drm_encoder *encoder)
+{
+       struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
 
        if (renc->lvds)
-               rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode);
+               rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, true);
 }
 
-static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder,
-                                      const struct drm_display_mode *mode,
-                                      struct drm_display_mode *adjusted_mode)
+static int rcar_du_encoder_atomic_check(struct drm_encoder *encoder,
+                                       struct drm_crtc_state *crtc_state,
+                                       struct drm_connector_state *conn_state)
 {
        struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
+       struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+       const struct drm_display_mode *mode = &crtc_state->mode;
        const struct drm_display_mode *panel_mode;
+       struct drm_connector *connector = conn_state->connector;
        struct drm_device *dev = encoder->dev;
-       struct drm_connector *connector;
-       bool found = false;
 
        /* DAC encoders have currently no restriction on the mode. */
        if (encoder->encoder_type == DRM_MODE_ENCODER_DAC)
-               return true;
-
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       found = true;
-                       break;
-               }
-       }
-
-       if (!found) {
-               dev_dbg(dev->dev, "mode_fixup: no connector found\n");
-               return false;
-       }
+               return 0;
 
        if (list_empty(&connector->modes)) {
-               dev_dbg(dev->dev, "mode_fixup: empty modes list\n");
-               return false;
+               dev_dbg(dev->dev, "encoder: empty modes list\n");
+               return -EINVAL;
        }
 
        panel_mode = list_first_entry(&connector->modes,
@@ -90,7 +84,7 @@ static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder,
        /* We're not allowed to modify the resolution. */
        if (mode->hdisplay != panel_mode->hdisplay ||
            mode->vdisplay != panel_mode->vdisplay)
-               return false;
+               return -EINVAL;
 
        /* The flat panel mode is fixed, just copy it to the adjusted mode. */
        drm_mode_copy(adjusted_mode, panel_mode);
@@ -102,25 +96,7 @@ static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder,
                adjusted_mode->clock = clamp(adjusted_mode->clock,
                                             30000, 150000);
 
-       return true;
-}
-
-static void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder)
-{
-       struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
-
-       if (renc->lvds)
-               rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc,
-                                    DRM_MODE_DPMS_OFF);
-}
-
-static void rcar_du_encoder_mode_commit(struct drm_encoder *encoder)
-{
-       struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
-
-       if (renc->lvds)
-               rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc,
-                                    DRM_MODE_DPMS_ON);
+       return 0;
 }
 
 static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
@@ -133,11 +109,10 @@ static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
 }
 
 static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
-       .dpms = rcar_du_encoder_dpms,
-       .mode_fixup = rcar_du_encoder_mode_fixup,
-       .prepare = rcar_du_encoder_mode_prepare,
-       .commit = rcar_du_encoder_mode_commit,
        .mode_set = rcar_du_encoder_mode_set,
+       .disable = rcar_du_encoder_disable,
+       .enable = rcar_du_encoder_enable,
+       .atomic_check = rcar_du_encoder_atomic_check,
 };
 
 static const struct drm_encoder_funcs encoder_funcs = {
index 0c38cdcda4cae9a0880bf354b7ffd167c16be870..ed36433fbe84a55d2fbd3e822d9681251f596d3b 100644 (file)
@@ -14,6 +14,8 @@
 #ifndef __RCAR_DU_GROUP_H__
 #define __RCAR_DU_GROUP_H__
 
+#include <linux/mutex.h>
+
 #include "rcar_du_plane.h"
 
 struct rcar_du_device;
@@ -25,6 +27,7 @@ struct rcar_du_device;
  * @index: group index
  * @use_count: number of users of the group (rcar_du_group_(get|put))
  * @used_crtcs: number of CRTCs currently in use
+ * @lock: protects the DPTSR register
  * @planes: planes handled by the group
  */
 struct rcar_du_group {
@@ -35,6 +38,8 @@ struct rcar_du_group {
        unsigned int use_count;
        unsigned int used_crtcs;
 
+       struct mutex lock;
+
        struct rcar_du_planes planes;
 };
 
index ca94b029ac80ca664c0a53631328eaf90e971754..96f2eb43713c55e99f662fb76f8b7dcd727c0724 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_encoder_slave.h>
@@ -74,10 +75,13 @@ rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force)
 }
 
 static const struct drm_connector_funcs connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
+       .reset = drm_atomic_helper_connector_reset,
        .detect = rcar_du_hdmi_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = rcar_du_hdmi_connector_destroy,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
@@ -108,7 +112,7 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
        if (ret < 0)
                return ret;
 
-       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+       connector->dpms = DRM_MODE_DPMS_OFF;
        drm_object_property_set_value(&connector->base,
                rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
 
@@ -116,7 +120,6 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
        if (ret < 0)
                return ret;
 
-       connector->encoder = encoder;
        rcon->encoder = renc;
 
        return 0;
index 221f0a17fd6a62bbde33950e8529ce371aff9323..81da8419282ba047ce4c0afacb6ad82a4d9fe304 100644 (file)
 struct rcar_du_hdmienc {
        struct rcar_du_encoder *renc;
        struct device *dev;
-       int dpms;
+       bool enabled;
 };
 
 #define to_rcar_hdmienc(e)     (to_rcar_encoder(e)->hdmi)
 #define to_slave_funcs(e)      (to_rcar_encoder(e)->slave.slave_funcs)
 
-static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode)
+static void rcar_du_hdmienc_disable(struct drm_encoder *encoder)
 {
        struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
        struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
 
-       if (mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
+       if (sfuncs->dpms)
+               sfuncs->dpms(encoder, DRM_MODE_DPMS_OFF);
 
-       if (hdmienc->dpms == mode)
-               return;
+       if (hdmienc->renc->lvds)
+               rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc,
+                                      false);
 
-       if (mode == DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
-               rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
+       hdmienc->enabled = false;
+}
 
-       if (sfuncs->dpms)
-               sfuncs->dpms(encoder, mode);
+static void rcar_du_hdmienc_enable(struct drm_encoder *encoder)
+{
+       struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
+       struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+
+       if (hdmienc->renc->lvds)
+               rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc,
+                                      true);
 
-       if (mode != DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
-               rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
+       if (sfuncs->dpms)
+               sfuncs->dpms(encoder, DRM_MODE_DPMS_ON);
 
-       hdmienc->dpms = mode;
+       hdmienc->enabled = true;
 }
 
-static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder,
-                                      const struct drm_display_mode *mode,
-                                      struct drm_display_mode *adjusted_mode)
+static int rcar_du_hdmienc_atomic_check(struct drm_encoder *encoder,
+                                       struct drm_crtc_state *crtc_state,
+                                       struct drm_connector_state *conn_state)
 {
        struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
        struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+       struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+       const struct drm_display_mode *mode = &crtc_state->mode;
 
        /* The internal LVDS encoder has a clock frequency operating range of
         * 30MHz to 150MHz. Clamp the clock accordingly.
@@ -70,19 +79,9 @@ static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder,
                                             30000, 150000);
 
        if (sfuncs->mode_fixup == NULL)
-               return true;
-
-       return sfuncs->mode_fixup(encoder, mode, adjusted_mode);
-}
+               return 0;
 
-static void rcar_du_hdmienc_mode_prepare(struct drm_encoder *encoder)
-{
-       rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-static void rcar_du_hdmienc_mode_commit(struct drm_encoder *encoder)
-{
-       rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_ON);
+       return sfuncs->mode_fixup(encoder, mode, adjusted_mode) ? 0 : -EINVAL;
 }
 
 static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder,
@@ -99,18 +98,18 @@ static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder,
 }
 
 static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
-       .dpms = rcar_du_hdmienc_dpms,
-       .mode_fixup = rcar_du_hdmienc_mode_fixup,
-       .prepare = rcar_du_hdmienc_mode_prepare,
-       .commit = rcar_du_hdmienc_mode_commit,
        .mode_set = rcar_du_hdmienc_mode_set,
+       .disable = rcar_du_hdmienc_disable,
+       .enable = rcar_du_hdmienc_enable,
+       .atomic_check = rcar_du_hdmienc_atomic_check,
 };
 
 static void rcar_du_hdmienc_cleanup(struct drm_encoder *encoder)
 {
        struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 
-       rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF);
+       if (hdmienc->enabled)
+               rcar_du_hdmienc_disable(encoder);
 
        drm_encoder_cleanup(encoder);
        put_device(hdmienc->dev);
index cc9136e8ee9cd2f73c65850215fad60a584358ee..fb052bca574fdd0a71814db3e683c6fa396d038d 100644 (file)
  */
 
 #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_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
 #include <linux/of_graph.h>
+#include <linux/wait.h>
 
 #include "rcar_du_crtc.h"
 #include "rcar_du_drv.h"
@@ -185,9 +188,309 @@ static void rcar_du_output_poll_changed(struct drm_device *dev)
        drm_fbdev_cma_hotplug_event(rcdu->fbdev);
 }
 
+/* -----------------------------------------------------------------------------
+ * Atomic Check and Update
+ */
+
+/*
+ * Atomic hardware plane allocator
+ *
+ * The hardware plane allocator is solely based on the atomic plane states
+ * without keeping any external state to avoid races between .atomic_check()
+ * and .atomic_commit().
+ *
+ * The core idea is to avoid using a free planes bitmask that would need to be
+ * shared between check and commit handlers with a collective knowledge based on
+ * the allocated hardware plane(s) for each KMS plane. The allocator then loops
+ * over all plane states to compute the free planes bitmask, allocates hardware
+ * planes based on that bitmask, and stores the result back in the plane states.
+ *
+ * For this to work we need to access the current state of planes not touched by
+ * the atomic update. To ensure that it won't be modified, we need to lock all
+ * planes using drm_atomic_get_plane_state(). This effectively serializes atomic
+ * updates from .atomic_check() up to completion (when swapping the states if
+ * the check step has succeeded) or rollback (when freeing the states if the
+ * check step has failed).
+ *
+ * Allocation is performed in the .atomic_check() handler and applied
+ * automatically when the core swaps the old and new states.
+ */
+
+static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane,
+                                       struct rcar_du_plane_state *state)
+{
+       const struct rcar_du_format_info *cur_format;
+
+       cur_format = to_rcar_du_plane_state(plane->plane.state)->format;
+
+       /* Lowering the number of planes doesn't strictly require reallocation
+        * as the extra hardware plane will be freed when committing, but doing
+        * so could lead to more fragmentation.
+        */
+       return !cur_format || cur_format->planes != state->format->planes;
+}
+
+static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state)
+{
+       unsigned int mask;
+
+       if (state->hwindex == -1)
+               return 0;
+
+       mask = 1 << state->hwindex;
+       if (state->format->planes == 2)
+               mask |= 1 << ((state->hwindex + 1) % 8);
+
+       return mask;
+}
+
+static int rcar_du_plane_hwalloc(unsigned int num_planes, unsigned int free)
+{
+       unsigned int i;
+
+       for (i = 0; i < RCAR_DU_NUM_HW_PLANES; ++i) {
+               if (!(free & (1 << i)))
+                       continue;
+
+               if (num_planes == 1 || free & (1 << ((i + 1) % 8)))
+                       break;
+       }
+
+       return i == RCAR_DU_NUM_HW_PLANES ? -EBUSY : i;
+}
+
+static int rcar_du_atomic_check(struct drm_device *dev,
+                               struct drm_atomic_state *state)
+{
+       struct rcar_du_device *rcdu = dev->dev_private;
+       unsigned int group_freed_planes[RCAR_DU_MAX_GROUPS] = { 0, };
+       unsigned int group_free_planes[RCAR_DU_MAX_GROUPS] = { 0, };
+       bool needs_realloc = false;
+       unsigned int groups = 0;
+       unsigned int i;
+       int ret;
+
+       ret = drm_atomic_helper_check(dev, state);
+       if (ret < 0)
+               return ret;
+
+       /* Check if hardware planes need to be reallocated. */
+       for (i = 0; i < dev->mode_config.num_total_plane; ++i) {
+               struct rcar_du_plane_state *plane_state;
+               struct rcar_du_plane *plane;
+               unsigned int index;
+
+               if (!state->planes[i])
+                       continue;
+
+               plane = to_rcar_plane(state->planes[i]);
+               plane_state = to_rcar_du_plane_state(state->plane_states[i]);
+
+               /* If the plane is being disabled we don't need to go through
+                * the full reallocation procedure. Just mark the hardware
+                * plane(s) as freed.
+                */
+               if (!plane_state->format) {
+                       index = plane - plane->group->planes.planes;
+                       group_freed_planes[plane->group->index] |= 1 << index;
+                       plane_state->hwindex = -1;
+                       continue;
+               }
+
+               /* If the plane needs to be reallocated mark it as such, and
+                * mark the hardware plane(s) as free.
+                */
+               if (rcar_du_plane_needs_realloc(plane, plane_state)) {
+                       groups |= 1 << plane->group->index;
+                       needs_realloc = true;
+
+                       index = plane - plane->group->planes.planes;
+                       group_freed_planes[plane->group->index] |= 1 << index;
+                       plane_state->hwindex = -1;
+               }
+       }
+
+       if (!needs_realloc)
+               return 0;
+
+       /* Grab all plane states for the groups that need reallocation to ensure
+        * locking and avoid racy updates. This serializes the update operation,
+        * but there's not much we can do about it as that's the hardware
+        * design.
+        *
+        * Compute the used planes mask for each group at the same time to avoid
+        * looping over the planes separately later.
+        */
+       while (groups) {
+               unsigned int index = ffs(groups) - 1;
+               struct rcar_du_group *group = &rcdu->groups[index];
+               unsigned int used_planes = 0;
+
+               for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
+                       struct rcar_du_plane *plane = &group->planes.planes[i];
+                       struct rcar_du_plane_state *plane_state;
+                       struct drm_plane_state *s;
+
+                       s = drm_atomic_get_plane_state(state, &plane->plane);
+                       if (IS_ERR(s))
+                               return PTR_ERR(s);
+
+                       /* If the plane has been freed in the above loop its
+                        * hardware planes must not be added to the used planes
+                        * bitmask. However, the current state doesn't reflect
+                        * the free state yet, as we've modified the new state
+                        * above. Use the local freed planes list to check for
+                        * that condition instead.
+                        */
+                       if (group_freed_planes[index] & (1 << i))
+                               continue;
+
+                       plane_state = to_rcar_du_plane_state(plane->plane.state);
+                       used_planes |= rcar_du_plane_hwmask(plane_state);
+               }
+
+               group_free_planes[index] = 0xff & ~used_planes;
+               groups &= ~(1 << index);
+       }
+
+       /* Reallocate hardware planes for each plane that needs it. */
+       for (i = 0; i < dev->mode_config.num_total_plane; ++i) {
+               struct rcar_du_plane_state *plane_state;
+               struct rcar_du_plane *plane;
+               int idx;
+
+               if (!state->planes[i])
+                       continue;
+
+               plane = to_rcar_plane(state->planes[i]);
+               plane_state = to_rcar_du_plane_state(state->plane_states[i]);
+
+               /* Skip planes that are being disabled or don't need to be
+                * reallocated.
+                */
+               if (!plane_state->format ||
+                   !rcar_du_plane_needs_realloc(plane, plane_state))
+                       continue;
+
+               idx = rcar_du_plane_hwalloc(plane_state->format->planes,
+                                       group_free_planes[plane->group->index]);
+               if (idx < 0) {
+                       dev_dbg(rcdu->dev, "%s: no available hardware plane\n",
+                               __func__);
+                       return idx;
+               }
+
+               plane_state->hwindex = idx;
+
+               group_free_planes[plane->group->index] &=
+                       ~rcar_du_plane_hwmask(plane_state);
+       }
+
+       return 0;
+}
+
+struct rcar_du_commit {
+       struct work_struct work;
+       struct drm_device *dev;
+       struct drm_atomic_state *state;
+       u32 crtcs;
+};
+
+static void rcar_du_atomic_complete(struct rcar_du_commit *commit)
+{
+       struct drm_device *dev = commit->dev;
+       struct rcar_du_device *rcdu = dev->dev_private;
+       struct drm_atomic_state *old_state = commit->state;
+
+       /* Apply the atomic update. */
+       drm_atomic_helper_commit_modeset_disables(dev, old_state);
+       drm_atomic_helper_commit_modeset_enables(dev, old_state);
+       drm_atomic_helper_commit_planes(dev, old_state);
+
+       drm_atomic_helper_wait_for_vblanks(dev, old_state);
+
+       drm_atomic_helper_cleanup_planes(dev, old_state);
+
+       drm_atomic_state_free(old_state);
+
+       /* Complete the commit, wake up any waiter. */
+       spin_lock(&rcdu->commit.wait.lock);
+       rcdu->commit.pending &= ~commit->crtcs;
+       wake_up_all_locked(&rcdu->commit.wait);
+       spin_unlock(&rcdu->commit.wait.lock);
+
+       kfree(commit);
+}
+
+static void rcar_du_atomic_work(struct work_struct *work)
+{
+       struct rcar_du_commit *commit =
+               container_of(work, struct rcar_du_commit, work);
+
+       rcar_du_atomic_complete(commit);
+}
+
+static int rcar_du_atomic_commit(struct drm_device *dev,
+                                struct drm_atomic_state *state, bool async)
+{
+       struct rcar_du_device *rcdu = dev->dev_private;
+       struct rcar_du_commit *commit;
+       unsigned int i;
+       int ret;
+
+       ret = drm_atomic_helper_prepare_planes(dev, state);
+       if (ret)
+               return ret;
+
+       /* Allocate the commit object. */
+       commit = kzalloc(sizeof(*commit), GFP_KERNEL);
+       if (commit == NULL)
+               return -ENOMEM;
+
+       INIT_WORK(&commit->work, rcar_du_atomic_work);
+       commit->dev = dev;
+       commit->state = state;
+
+       /* Wait until all affected CRTCs have completed previous commits and
+        * mark them as pending.
+        */
+       for (i = 0; i < dev->mode_config.num_crtc; ++i) {
+               if (state->crtcs[i])
+                       commit->crtcs |= 1 << drm_crtc_index(state->crtcs[i]);
+       }
+
+       spin_lock(&rcdu->commit.wait.lock);
+       ret = wait_event_interruptible_locked(rcdu->commit.wait,
+                       !(rcdu->commit.pending & commit->crtcs));
+       if (ret == 0)
+               rcdu->commit.pending |= commit->crtcs;
+       spin_unlock(&rcdu->commit.wait.lock);
+
+       if (ret) {
+               kfree(commit);
+               return ret;
+       }
+
+       /* Swap the state, this is the point of no return. */
+       drm_atomic_helper_swap_state(dev, state);
+
+       if (async)
+               schedule_work(&commit->work);
+       else
+               rcar_du_atomic_complete(commit);
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
 static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
        .fb_create = rcar_du_fb_create,
        .output_poll_changed = rcar_du_output_poll_changed,
+       .atomic_check = rcar_du_atomic_check,
+       .atomic_commit = rcar_du_atomic_commit,
 };
 
 static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
@@ -392,6 +695,8 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
        for (i = 0; i < num_groups; ++i) {
                struct rcar_du_group *rgrp = &rcdu->groups[i];
 
+               mutex_init(&rgrp->lock);
+
                rgrp->dev = rcdu;
                rgrp->mmio_offset = mmio_offsets[i];
                rgrp->index = i;
@@ -439,27 +744,21 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
                encoder->possible_clones = (1 << num_encoders) - 1;
        }
 
-       /* Now that the CRTCs have been initialized register the planes. */
-       for (i = 0; i < num_groups; ++i) {
-               ret = rcar_du_planes_register(&rcdu->groups[i]);
-               if (ret < 0)
-                       return ret;
-       }
+       drm_mode_config_reset(dev);
 
        drm_kms_helper_poll_init(dev);
 
-       drm_helper_disable_unused_functions(dev);
-
-       fbdev = drm_fbdev_cma_init(dev, 32, dev->mode_config.num_crtc,
-                                  dev->mode_config.num_connector);
-       if (IS_ERR(fbdev))
-               return PTR_ERR(fbdev);
+       if (dev->mode_config.num_connector) {
+               fbdev = drm_fbdev_cma_init(dev, 32, dev->mode_config.num_crtc,
+                                          dev->mode_config.num_connector);
+               if (IS_ERR(fbdev))
+                       return PTR_ERR(fbdev);
 
-#ifndef CONFIG_FRAMEBUFFER_CONSOLE
-       drm_fbdev_cma_restore_mode(fbdev);
-#endif
-
-       rcdu->fbdev = fbdev;
+               rcdu->fbdev = fbdev;
+       } else {
+               dev_info(rcdu->dev,
+                        "no connector found, disabling fbdev emulation\n");
+       }
 
        return 0;
 }
index 6d9811c052c4bce4d41ea61232fd99aaa71d6aa9..0c43032fc69318b294d3cf2baa29862bedb77d14 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 
@@ -74,10 +75,13 @@ rcar_du_lvds_connector_detect(struct drm_connector *connector, bool force)
 }
 
 static const struct drm_connector_funcs connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
+       .reset = drm_atomic_helper_connector_reset,
        .detect = rcar_du_lvds_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = rcar_du_lvds_connector_destroy,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
@@ -117,7 +121,7 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
        if (ret < 0)
                return ret;
 
-       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+       connector->dpms = DRM_MODE_DPMS_OFF;
        drm_object_property_set_value(&connector->base,
                rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
 
@@ -125,7 +129,6 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
        if (ret < 0)
                return ret;
 
-       connector->encoder = encoder;
        lvdscon->connector.encoder = renc;
 
        return 0;
index 7cfb48ce1791a2526c4c8afc33d7c864cabc3094..85043c5bad032d8c746726e490d25eb65dcafb9c 100644 (file)
@@ -28,7 +28,7 @@ struct rcar_du_lvdsenc {
        unsigned int index;
        void __iomem *mmio;
        struct clk *clock;
-       int dpms;
+       bool enabled;
 
        enum rcar_lvds_input input;
 };
@@ -48,7 +48,7 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
        u32 pllcr;
        int ret;
 
-       if (lvds->dpms == DRM_MODE_DPMS_ON)
+       if (lvds->enabled)
                return 0;
 
        ret = clk_prepare_enable(lvds->clock);
@@ -110,13 +110,13 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
        lvdcr0 |= LVDCR0_LVRES;
        rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 
-       lvds->dpms = DRM_MODE_DPMS_ON;
+       lvds->enabled = true;
        return 0;
 }
 
 static void rcar_du_lvdsenc_stop(struct rcar_du_lvdsenc *lvds)
 {
-       if (lvds->dpms == DRM_MODE_DPMS_OFF)
+       if (!lvds->enabled)
                return;
 
        rcar_lvds_write(lvds, LVDCR0, 0);
@@ -124,13 +124,13 @@ static void rcar_du_lvdsenc_stop(struct rcar_du_lvdsenc *lvds)
 
        clk_disable_unprepare(lvds->clock);
 
-       lvds->dpms = DRM_MODE_DPMS_OFF;
+       lvds->enabled = false;
 }
 
-int rcar_du_lvdsenc_dpms(struct rcar_du_lvdsenc *lvds,
-                        struct drm_crtc *crtc, int mode)
+int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, struct drm_crtc *crtc,
+                          bool enable)
 {
-       if (mode == DRM_MODE_DPMS_OFF) {
+       if (!enable) {
                rcar_du_lvdsenc_stop(lvds);
                return 0;
        } else if (crtc) {
@@ -179,7 +179,7 @@ int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
                lvds->dev = rcdu;
                lvds->index = i;
                lvds->input = i ? RCAR_LVDS_INPUT_DU1 : RCAR_LVDS_INPUT_DU0;
-               lvds->dpms = DRM_MODE_DPMS_OFF;
+               lvds->enabled = false;
 
                ret = rcar_du_lvdsenc_get_resources(lvds, pdev);
                if (ret < 0)
index f65aabda0796bbc62aa9af0326d2dccafd187067..9a6001c0730354b40d118650a27004ab470f6068 100644 (file)
@@ -28,15 +28,15 @@ enum rcar_lvds_input {
 
 #if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
 int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu);
-int rcar_du_lvdsenc_dpms(struct rcar_du_lvdsenc *lvds,
-                        struct drm_crtc *crtc, int mode);
+int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds,
+                          struct drm_crtc *crtc, bool enable);
 #else
 static inline int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
 {
        return 0;
 }
-static inline int rcar_du_lvdsenc_dpms(struct rcar_du_lvdsenc *lvds,
-                                      struct drm_crtc *crtc, int mode)
+static inline int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds,
+                                        struct drm_crtc *crtc, bool enable)
 {
        return 0;
 }
index 50f2f2b20d39fce3d8465611196a6ee6f36e803d..210e5c3fd9820d30f3347ce01fb4ecbb8b9f5fe5 100644 (file)
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
 
 #include "rcar_du_drv.h"
 #include "rcar_du_kms.h"
 #define RCAR_DU_COLORKEY_SOURCE                (1 << 24)
 #define RCAR_DU_COLORKEY_MASK          (1 << 24)
 
-struct rcar_du_kms_plane {
-       struct drm_plane plane;
-       struct rcar_du_plane *hwplane;
-};
-
-static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane)
-{
-       return container_of(plane, struct rcar_du_kms_plane, plane)->hwplane;
-}
-
 static u32 rcar_du_plane_read(struct rcar_du_group *rgrp,
                              unsigned int index, u32 reg)
 {
@@ -50,74 +42,31 @@ static void rcar_du_plane_write(struct rcar_du_group *rgrp,
                      data);
 }
 
-int rcar_du_plane_reserve(struct rcar_du_plane *plane,
-                         const struct rcar_du_format_info *format)
-{
-       struct rcar_du_group *rgrp = plane->group;
-       unsigned int i;
-       int ret = -EBUSY;
-
-       mutex_lock(&rgrp->planes.lock);
-
-       for (i = 0; i < ARRAY_SIZE(rgrp->planes.planes); ++i) {
-               if (!(rgrp->planes.free & (1 << i)))
-                       continue;
-
-               if (format->planes == 1 ||
-                   rgrp->planes.free & (1 << ((i + 1) % 8)))
-                       break;
-       }
-
-       if (i == ARRAY_SIZE(rgrp->planes.planes))
-               goto done;
-
-       rgrp->planes.free &= ~(1 << i);
-       if (format->planes == 2)
-               rgrp->planes.free &= ~(1 << ((i + 1) % 8));
-
-       plane->hwindex = i;
-
-       ret = 0;
-
-done:
-       mutex_unlock(&rgrp->planes.lock);
-       return ret;
-}
-
-void rcar_du_plane_release(struct rcar_du_plane *plane)
-{
-       struct rcar_du_group *rgrp = plane->group;
-
-       if (plane->hwindex == -1)
-               return;
-
-       mutex_lock(&rgrp->planes.lock);
-       rgrp->planes.free |= 1 << plane->hwindex;
-       if (plane->format->planes == 2)
-               rgrp->planes.free |= 1 << ((plane->hwindex + 1) % 8);
-       mutex_unlock(&rgrp->planes.lock);
-
-       plane->hwindex = -1;
-}
-
-void rcar_du_plane_update_base(struct rcar_du_plane *plane)
+static void rcar_du_plane_setup_fb(struct rcar_du_plane *plane)
 {
+       struct rcar_du_plane_state *state =
+               to_rcar_du_plane_state(plane->plane.state);
+       struct drm_framebuffer *fb = plane->plane.state->fb;
        struct rcar_du_group *rgrp = plane->group;
-       unsigned int index = plane->hwindex;
+       unsigned int src_x = state->state.src_x >> 16;
+       unsigned int src_y = state->state.src_y >> 16;
+       unsigned int index = state->hwindex;
+       struct drm_gem_cma_object *gem;
        bool interlaced;
        u32 mwr;
 
-       interlaced = plane->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
+       interlaced = state->state.crtc->state->adjusted_mode.flags
+                  & DRM_MODE_FLAG_INTERLACE;
 
        /* Memory pitch (expressed in pixels). Must be doubled for interlaced
         * operation with 32bpp formats.
         */
-       if (plane->format->planes == 2)
-               mwr = plane->pitch;
+       if (state->format->planes == 2)
+               mwr = fb->pitches[0];
        else
-               mwr = plane->pitch * 8 / plane->format->bpp;
+               mwr = fb->pitches[0] * 8 / state->format->bpp;
 
-       if (interlaced && plane->format->bpp == 32)
+       if (interlaced && state->format->bpp == 32)
                mwr *= 2;
 
        rcar_du_plane_write(rgrp, index, PnMWR, mwr);
@@ -134,42 +83,33 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
         * require a halved Y position value, in both progressive and interlaced
         * modes.
         */
-       rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
-       rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
-                           (!interlaced && plane->format->bpp == 32 ? 2 : 1));
-       rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]);
+       rcar_du_plane_write(rgrp, index, PnSPXR, src_x);
+       rcar_du_plane_write(rgrp, index, PnSPYR, src_y *
+                           (!interlaced && state->format->bpp == 32 ? 2 : 1));
 
-       if (plane->format->planes == 2) {
-               index = (index + 1) % 8;
-
-               rcar_du_plane_write(rgrp, index, PnMWR, plane->pitch);
+       gem = drm_fb_cma_get_gem_obj(fb, 0);
+       rcar_du_plane_write(rgrp, index, PnDSA0R, gem->paddr + fb->offsets[0]);
 
-               rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
-               rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
-                                   (plane->format->bpp == 16 ? 2 : 1) / 2);
-               rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[1]);
-       }
-}
+       if (state->format->planes == 2) {
+               index = (index + 1) % 8;
 
-void rcar_du_plane_compute_base(struct rcar_du_plane *plane,
-                               struct drm_framebuffer *fb)
-{
-       struct drm_gem_cma_object *gem;
+               rcar_du_plane_write(rgrp, index, PnMWR, fb->pitches[0]);
 
-       plane->pitch = fb->pitches[0];
+               rcar_du_plane_write(rgrp, index, PnSPXR, src_x);
+               rcar_du_plane_write(rgrp, index, PnSPYR, src_y *
+                                   (state->format->bpp == 16 ? 2 : 1) / 2);
 
-       gem = drm_fb_cma_get_gem_obj(fb, 0);
-       plane->dma[0] = gem->paddr + fb->offsets[0];
-
-       if (plane->format->planes == 2) {
                gem = drm_fb_cma_get_gem_obj(fb, 1);
-               plane->dma[1] = gem->paddr + fb->offsets[1];
+               rcar_du_plane_write(rgrp, index, PnDSA0R,
+                                   gem->paddr + fb->offsets[1]);
        }
 }
 
 static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
                                     unsigned int index)
 {
+       struct rcar_du_plane_state *state =
+               to_rcar_du_plane_state(plane->plane.state);
        struct rcar_du_group *rgrp = plane->group;
        u32 colorkey;
        u32 pnmr;
@@ -183,47 +123,47 @@ static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
         * For XRGB, set the alpha value to the plane-wide alpha value and
         * enable alpha-blending regardless of the X bit value.
         */
-       if (plane->format->fourcc != DRM_FORMAT_XRGB1555)
+       if (state->format->fourcc != DRM_FORMAT_XRGB1555)
                rcar_du_plane_write(rgrp, index, PnALPHAR, PnALPHAR_ABIT_0);
        else
                rcar_du_plane_write(rgrp, index, PnALPHAR,
-                                   PnALPHAR_ABIT_X | plane->alpha);
+                                   PnALPHAR_ABIT_X | state->alpha);
 
-       pnmr = PnMR_BM_MD | plane->format->pnmr;
+       pnmr = PnMR_BM_MD | state->format->pnmr;
 
        /* Disable color keying when requested. YUV formats have the
         * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying
         * automatically.
         */
-       if ((plane->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE)
+       if ((state->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE)
                pnmr |= PnMR_SPIM_TP_OFF;
 
        /* For packed YUV formats we need to select the U/V order. */
-       if (plane->format->fourcc == DRM_FORMAT_YUYV)
+       if (state->format->fourcc == DRM_FORMAT_YUYV)
                pnmr |= PnMR_YCDF_YUYV;
 
        rcar_du_plane_write(rgrp, index, PnMR, pnmr);
 
-       switch (plane->format->fourcc) {
+       switch (state->format->fourcc) {
        case DRM_FORMAT_RGB565:
-               colorkey = ((plane->colorkey & 0xf80000) >> 8)
-                        | ((plane->colorkey & 0x00fc00) >> 5)
-                        | ((plane->colorkey & 0x0000f8) >> 3);
+               colorkey = ((state->colorkey & 0xf80000) >> 8)
+                        | ((state->colorkey & 0x00fc00) >> 5)
+                        | ((state->colorkey & 0x0000f8) >> 3);
                rcar_du_plane_write(rgrp, index, PnTC2R, colorkey);
                break;
 
        case DRM_FORMAT_ARGB1555:
        case DRM_FORMAT_XRGB1555:
-               colorkey = ((plane->colorkey & 0xf80000) >> 9)
-                        | ((plane->colorkey & 0x00f800) >> 6)
-                        | ((plane->colorkey & 0x0000f8) >> 3);
+               colorkey = ((state->colorkey & 0xf80000) >> 9)
+                        | ((state->colorkey & 0x00f800) >> 6)
+                        | ((state->colorkey & 0x0000f8) >> 3);
                rcar_du_plane_write(rgrp, index, PnTC2R, colorkey);
                break;
 
        case DRM_FORMAT_XRGB8888:
        case DRM_FORMAT_ARGB8888:
                rcar_du_plane_write(rgrp, index, PnTC3R,
-                                   PnTC3R_CODE | (plane->colorkey & 0xffffff));
+                                   PnTC3R_CODE | (state->colorkey & 0xffffff));
                break;
        }
 }
@@ -231,6 +171,8 @@ static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
 static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
                                  unsigned int index)
 {
+       struct rcar_du_plane_state *state =
+               to_rcar_du_plane_state(plane->plane.state);
        struct rcar_du_group *rgrp = plane->group;
        u32 ddcr2 = PnDDCR2_CODE;
        u32 ddcr4;
@@ -242,17 +184,17 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
         */
        ddcr4 = rcar_du_plane_read(rgrp, index, PnDDCR4);
        ddcr4 &= ~PnDDCR4_EDF_MASK;
-       ddcr4 |= plane->format->edf | PnDDCR4_CODE;
+       ddcr4 |= state->format->edf | PnDDCR4_CODE;
 
        rcar_du_plane_setup_mode(plane, index);
 
-       if (plane->format->planes == 2) {
-               if (plane->hwindex != index) {
-                       if (plane->format->fourcc == DRM_FORMAT_NV12 ||
-                           plane->format->fourcc == DRM_FORMAT_NV21)
+       if (state->format->planes == 2) {
+               if (state->hwindex != index) {
+                       if (state->format->fourcc == DRM_FORMAT_NV12 ||
+                           state->format->fourcc == DRM_FORMAT_NV21)
                                ddcr2 |= PnDDCR2_Y420;
 
-                       if (plane->format->fourcc == DRM_FORMAT_NV21)
+                       if (state->format->fourcc == DRM_FORMAT_NV21)
                                ddcr2 |= PnDDCR2_NV21;
 
                        ddcr2 |= PnDDCR2_DIVU;
@@ -265,10 +207,10 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
        rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4);
 
        /* Destination position and size */
-       rcar_du_plane_write(rgrp, index, PnDSXR, plane->width);
-       rcar_du_plane_write(rgrp, index, PnDSYR, plane->height);
-       rcar_du_plane_write(rgrp, index, PnDPXR, plane->dst_x);
-       rcar_du_plane_write(rgrp, index, PnDPYR, plane->dst_y);
+       rcar_du_plane_write(rgrp, index, PnDSXR, plane->plane.state->crtc_w);
+       rcar_du_plane_write(rgrp, index, PnDSYR, plane->plane.state->crtc_h);
+       rcar_du_plane_write(rgrp, index, PnDPXR, plane->plane.state->crtc_x);
+       rcar_du_plane_write(rgrp, index, PnDPYR, plane->plane.state->crtc_y);
 
        /* Wrap-around and blinking, disabled */
        rcar_du_plane_write(rgrp, index, PnWASPR, 0);
@@ -279,150 +221,143 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
 
 void rcar_du_plane_setup(struct rcar_du_plane *plane)
 {
-       __rcar_du_plane_setup(plane, plane->hwindex);
-       if (plane->format->planes == 2)
-               __rcar_du_plane_setup(plane, (plane->hwindex + 1) % 8);
+       struct rcar_du_plane_state *state =
+               to_rcar_du_plane_state(plane->plane.state);
+
+       __rcar_du_plane_setup(plane, state->hwindex);
+       if (state->format->planes == 2)
+               __rcar_du_plane_setup(plane, (state->hwindex + 1) % 8);
 
-       rcar_du_plane_update_base(plane);
+       rcar_du_plane_setup_fb(plane);
 }
 
-static int
-rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
-                      struct drm_framebuffer *fb, int crtc_x, int crtc_y,
-                      unsigned int crtc_w, unsigned int crtc_h,
-                      uint32_t src_x, uint32_t src_y,
-                      uint32_t src_w, uint32_t src_h)
+static int rcar_du_plane_atomic_check(struct drm_plane *plane,
+                                     struct drm_plane_state *state)
 {
+       struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state);
        struct rcar_du_plane *rplane = to_rcar_plane(plane);
        struct rcar_du_device *rcdu = rplane->group->dev;
-       const struct rcar_du_format_info *format;
-       unsigned int nplanes;
-       int ret;
 
-       format = rcar_du_format_info(fb->pixel_format);
-       if (format == NULL) {
-               dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__,
-                       fb->pixel_format);
-               return -EINVAL;
+       if (!state->fb || !state->crtc) {
+               rstate->format = NULL;
+               return 0;
        }
 
-       if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) {
+       if (state->src_w >> 16 != state->crtc_w ||
+           state->src_h >> 16 != state->crtc_h) {
                dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__);
                return -EINVAL;
        }
 
-       nplanes = rplane->format ? rplane->format->planes : 0;
-
-       /* Reallocate hardware planes if the number of required planes has
-        * changed.
-        */
-       if (format->planes != nplanes) {
-               rcar_du_plane_release(rplane);
-               ret = rcar_du_plane_reserve(rplane, format);
-               if (ret < 0)
-                       return ret;
+       rstate->format = rcar_du_format_info(state->fb->pixel_format);
+       if (rstate->format == NULL) {
+               dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__,
+                       state->fb->pixel_format);
+               return -EINVAL;
        }
 
-       rplane->crtc = crtc;
-       rplane->format = format;
-
-       rplane->src_x = src_x >> 16;
-       rplane->src_y = src_y >> 16;
-       rplane->dst_x = crtc_x;
-       rplane->dst_y = crtc_y;
-       rplane->width = crtc_w;
-       rplane->height = crtc_h;
-
-       rcar_du_plane_compute_base(rplane, fb);
-       rcar_du_plane_setup(rplane);
-
-       mutex_lock(&rplane->group->planes.lock);
-       rplane->enabled = true;
-       rcar_du_crtc_update_planes(rplane->crtc);
-       mutex_unlock(&rplane->group->planes.lock);
-
        return 0;
 }
 
-static int rcar_du_plane_disable(struct drm_plane *plane)
+static void rcar_du_plane_atomic_update(struct drm_plane *plane,
+                                       struct drm_plane_state *old_state)
 {
        struct rcar_du_plane *rplane = to_rcar_plane(plane);
 
-       if (!rplane->enabled)
-               return 0;
+       if (plane->state->crtc)
+               rcar_du_plane_setup(rplane);
+}
 
-       mutex_lock(&rplane->group->planes.lock);
-       rplane->enabled = false;
-       rcar_du_crtc_update_planes(rplane->crtc);
-       mutex_unlock(&rplane->group->planes.lock);
+static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = {
+       .atomic_check = rcar_du_plane_atomic_check,
+       .atomic_update = rcar_du_plane_atomic_update,
+};
 
-       rcar_du_plane_release(rplane);
+static void rcar_du_plane_reset(struct drm_plane *plane)
+{
+       struct rcar_du_plane_state *state;
 
-       rplane->crtc = NULL;
-       rplane->format = NULL;
+       if (plane->state && plane->state->fb)
+               drm_framebuffer_unreference(plane->state->fb);
 
-       return 0;
-}
+       kfree(plane->state);
+       plane->state = NULL;
 
-/* Both the .set_property and the .update_plane operations are called with the
- * mode_config lock held. There is this no need to explicitly protect access to
- * the alpha and colorkey fields and the mode register.
- */
-static void rcar_du_plane_set_alpha(struct rcar_du_plane *plane, u32 alpha)
-{
-       if (plane->alpha == alpha)
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (state == NULL)
                return;
 
-       plane->alpha = alpha;
-       if (!plane->enabled || plane->format->fourcc != DRM_FORMAT_XRGB1555)
-               return;
+       state->hwindex = -1;
+       state->alpha = 255;
+       state->colorkey = RCAR_DU_COLORKEY_NONE;
+       state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
 
-       rcar_du_plane_setup_mode(plane, plane->hwindex);
+       plane->state = &state->state;
+       plane->state->plane = plane;
 }
 
-static void rcar_du_plane_set_colorkey(struct rcar_du_plane *plane,
-                                      u32 colorkey)
+static struct drm_plane_state *
+rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
 {
-       if (plane->colorkey == colorkey)
-               return;
+       struct rcar_du_plane_state *state;
+       struct rcar_du_plane_state *copy;
 
-       plane->colorkey = colorkey;
-       if (!plane->enabled)
-               return;
+       state = to_rcar_du_plane_state(plane->state);
+       copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+       if (copy == NULL)
+               return NULL;
+
+       if (copy->state.fb)
+               drm_framebuffer_reference(copy->state.fb);
 
-       rcar_du_plane_setup_mode(plane, plane->hwindex);
+       return &copy->state;
 }
 
-static void rcar_du_plane_set_zpos(struct rcar_du_plane *plane,
-                                  unsigned int zpos)
+static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane,
+                                              struct drm_plane_state *state)
 {
-       mutex_lock(&plane->group->planes.lock);
-       if (plane->zpos == zpos)
-               goto done;
+       if (state->fb)
+               drm_framebuffer_unreference(state->fb);
 
-       plane->zpos = zpos;
-       if (!plane->enabled)
-               goto done;
+       kfree(to_rcar_du_plane_state(state));
+}
+
+static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
+                                            struct drm_plane_state *state,
+                                            struct drm_property *property,
+                                            uint64_t val)
+{
+       struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state);
+       struct rcar_du_plane *rplane = to_rcar_plane(plane);
+       struct rcar_du_group *rgrp = rplane->group;
 
-       rcar_du_crtc_update_planes(plane->crtc);
+       if (property == rgrp->planes.alpha)
+               rstate->alpha = val;
+       else if (property == rgrp->planes.colorkey)
+               rstate->colorkey = val;
+       else if (property == rgrp->planes.zpos)
+               rstate->zpos = val;
+       else
+               return -EINVAL;
 
-done:
-       mutex_unlock(&plane->group->planes.lock);
+       return 0;
 }
 
-static int rcar_du_plane_set_property(struct drm_plane *plane,
-                                     struct drm_property *property,
-                                     uint64_t value)
+static int rcar_du_plane_atomic_get_property(struct drm_plane *plane,
+       const struct drm_plane_state *state, struct drm_property *property,
+       uint64_t *val)
 {
+       const struct rcar_du_plane_state *rstate =
+               container_of(state, const struct rcar_du_plane_state, state);
        struct rcar_du_plane *rplane = to_rcar_plane(plane);
        struct rcar_du_group *rgrp = rplane->group;
 
        if (property == rgrp->planes.alpha)
-               rcar_du_plane_set_alpha(rplane, value);
+               *val = rstate->alpha;
        else if (property == rgrp->planes.colorkey)
-               rcar_du_plane_set_colorkey(rplane, value);
+               *val = rstate->colorkey;
        else if (property == rgrp->planes.zpos)
-               rcar_du_plane_set_zpos(rplane, value);
+               *val = rstate->zpos;
        else
                return -EINVAL;
 
@@ -430,10 +365,15 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
 }
 
 static const struct drm_plane_funcs rcar_du_plane_funcs = {
-       .update_plane = rcar_du_plane_update,
-       .disable_plane = rcar_du_plane_disable,
-       .set_property = rcar_du_plane_set_property,
+       .update_plane = drm_atomic_helper_update_plane,
+       .disable_plane = drm_atomic_helper_disable_plane,
+       .reset = rcar_du_plane_reset,
+       .set_property = drm_atomic_helper_plane_set_property,
        .destroy = drm_plane_cleanup,
+       .atomic_duplicate_state = rcar_du_plane_atomic_duplicate_state,
+       .atomic_destroy_state = rcar_du_plane_atomic_destroy_state,
+       .atomic_set_property = rcar_du_plane_atomic_set_property,
+       .atomic_get_property = rcar_du_plane_atomic_get_property,
 };
 
 static const uint32_t formats[] = {
@@ -453,10 +393,11 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
 {
        struct rcar_du_planes *planes = &rgrp->planes;
        struct rcar_du_device *rcdu = rgrp->dev;
+       unsigned int num_planes;
+       unsigned int num_crtcs;
+       unsigned int crtcs;
        unsigned int i;
-
-       mutex_init(&planes->lock);
-       planes->free = 0xff;
+       int ret;
 
        planes->alpha =
                drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255);
@@ -478,45 +419,34 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
        if (planes->zpos == NULL)
                return -ENOMEM;
 
-       for (i = 0; i < ARRAY_SIZE(planes->planes); ++i) {
-               struct rcar_du_plane *plane = &planes->planes[i];
-
-               plane->group = rgrp;
-               plane->hwindex = -1;
-               plane->alpha = 255;
-               plane->colorkey = RCAR_DU_COLORKEY_NONE;
-               plane->zpos = 0;
-       }
-
-       return 0;
-}
-
-int rcar_du_planes_register(struct rcar_du_group *rgrp)
-{
-       struct rcar_du_planes *planes = &rgrp->planes;
-       struct rcar_du_device *rcdu = rgrp->dev;
-       unsigned int crtcs;
-       unsigned int i;
-       int ret;
+        /* Create one primary plane per in this group CRTC and seven overlay
+         * planes.
+         */
+       num_crtcs = min(rcdu->num_crtcs - 2 * rgrp->index, 2U);
+       num_planes = num_crtcs + 7;
 
        crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index));
 
-       for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
-               struct rcar_du_kms_plane *plane;
-
-               plane = devm_kzalloc(rcdu->dev, sizeof(*plane), GFP_KERNEL);
-               if (plane == NULL)
-                       return -ENOMEM;
+       for (i = 0; i < num_planes; ++i) {
+               enum drm_plane_type type = i < num_crtcs
+                                        ? DRM_PLANE_TYPE_PRIMARY
+                                        : DRM_PLANE_TYPE_OVERLAY;
+               struct rcar_du_plane *plane = &planes->planes[i];
 
-               plane->hwplane = &planes->planes[i + 2];
-               plane->hwplane->zpos = 1;
+               plane->group = rgrp;
 
-               ret = drm_plane_init(rcdu->ddev, &plane->plane, crtcs,
-                                    &rcar_du_plane_funcs, formats,
-                                    ARRAY_SIZE(formats), false);
+               ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs,
+                                              &rcar_du_plane_funcs, formats,
+                                              ARRAY_SIZE(formats), type);
                if (ret < 0)
                        return ret;
 
+               drm_plane_helper_add(&plane->plane,
+                                    &rcar_du_plane_helper_funcs);
+
+               if (type == DRM_PLANE_TYPE_PRIMARY)
+                       continue;
+
                drm_object_attach_property(&plane->plane.base,
                                           planes->alpha, 255);
                drm_object_attach_property(&plane->plane.base,
index 3021288b1a892db231024ce8c9adf4d4be939267..abff0ebeb195f4cba972d8e00237cdf496e89108 100644 (file)
 #ifndef __RCAR_DU_PLANE_H__
 #define __RCAR_DU_PLANE_H__
 
-#include <linux/mutex.h>
-
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 
 struct rcar_du_format_info;
 struct rcar_du_group;
 
-/* The RCAR DU has 8 hardware planes, shared between KMS planes and CRTCs. As
- * using KMS planes requires at least one of the CRTCs being enabled, no more
- * than 7 KMS planes can be available. We thus create 7 KMS planes and
- * 9 software planes (one for each KMS planes and one for each CRTC).
+/* The RCAR DU has 8 hardware planes, shared between primary and overlay planes.
+ * As using overlay planes requires at least one of the CRTCs being enabled, no
+ * more than 7 overlay planes can be available. We thus create 1 primary plane
+ * per CRTC and 7 overlay planes, for a total of up to 9 KMS planes.
  */
-
-#define RCAR_DU_NUM_KMS_PLANES         7
+#define RCAR_DU_NUM_KMS_PLANES         9
 #define RCAR_DU_NUM_HW_PLANES          8
-#define RCAR_DU_NUM_SW_PLANES          9
 
 struct rcar_du_plane {
+       struct drm_plane plane;
        struct rcar_du_group *group;
-       struct drm_crtc *crtc;
-
-       bool enabled;
-
-       int hwindex;            /* 0-based, -1 means unused */
-       unsigned int alpha;
-       unsigned int colorkey;
-       unsigned int zpos;
-
-       const struct rcar_du_format_info *format;
-
-       unsigned long dma[2];
-       unsigned int pitch;
-
-       unsigned int width;
-       unsigned int height;
-
-       unsigned int src_x;
-       unsigned int src_y;
-       unsigned int dst_x;
-       unsigned int dst_y;
 };
 
+static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane)
+{
+       return container_of(plane, struct rcar_du_plane, plane);
+}
+
 struct rcar_du_planes {
-       struct rcar_du_plane planes[RCAR_DU_NUM_SW_PLANES];
-       unsigned int free;
-       struct mutex lock;
+       struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
 
        struct drm_property *alpha;
        struct drm_property *colorkey;
        struct drm_property *zpos;
 };
 
+struct rcar_du_plane_state {
+       struct drm_plane_state state;
+
+       const struct rcar_du_format_info *format;
+       int hwindex;            /* 0-based, -1 means unused */
+
+       unsigned int alpha;
+       unsigned int colorkey;
+       unsigned int zpos;
+};
+
+static inline struct rcar_du_plane_state *
+to_rcar_du_plane_state(struct drm_plane_state *state)
+{
+       return container_of(state, struct rcar_du_plane_state, state);
+}
+
 int rcar_du_planes_init(struct rcar_du_group *rgrp);
-int rcar_du_planes_register(struct rcar_du_group *rgrp);
 
 void rcar_du_plane_setup(struct rcar_du_plane *plane);
-void rcar_du_plane_update_base(struct rcar_du_plane *plane);
-void rcar_du_plane_compute_base(struct rcar_du_plane *plane,
-                               struct drm_framebuffer *fb);
-int rcar_du_plane_reserve(struct rcar_du_plane *plane,
-                         const struct rcar_du_format_info *format);
-void rcar_du_plane_release(struct rcar_du_plane *plane);
 
 #endif /* __RCAR_DU_PLANE_H__ */
index 9d4879921cc7a92e574ba15f47c95370e9a469b9..e0a5d8f939630a5d21319671f8a32981c4c09a6a 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 
@@ -43,10 +44,13 @@ rcar_du_vga_connector_detect(struct drm_connector *connector, bool force)
 }
 
 static const struct drm_connector_funcs connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
+       .reset = drm_atomic_helper_connector_reset,
        .detect = rcar_du_vga_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = rcar_du_vga_connector_destroy,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
@@ -76,7 +80,7 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
        if (ret < 0)
                return ret;
 
-       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+       connector->dpms = DRM_MODE_DPMS_OFF;
        drm_object_property_set_value(&connector->base,
                rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
 
@@ -84,7 +88,6 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
        if (ret < 0)
                return ret;
 
-       connector->encoder = encoder;
        rcon->encoder = renc;
 
        return 0;
index 21a481b224ebab6ef896bbbf5e2a9036c5cfb0ed..30da7813d53e03691026e796e580bf348a532009 100644 (file)
@@ -129,6 +129,7 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
        struct rockchip_drm_private *private;
        struct dma_iommu_mapping *mapping;
        struct device *dev = drm_dev->dev;
+       struct drm_connector *connector;
        int ret;
 
        private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL);
@@ -171,6 +172,23 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
        if (ret)
                goto err_detach_device;
 
+       /*
+        * All components are now added, we can publish the connector sysfs
+        * entries to userspace.  This will generate hotplug events and so
+        * userspace will expect to be able to access DRM at this point.
+        */
+       list_for_each_entry(connector, &drm_dev->mode_config.connector_list,
+                       head) {
+               ret = drm_connector_register(connector);
+               if (ret) {
+                       dev_err(drm_dev->dev,
+                               "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n",
+                               connector->base.id,
+                               connector->name, ret);
+                       goto err_unbind;
+               }
+       }
+
        /* init kms poll for handling hpd */
        drm_kms_helper_poll_init(drm_dev);
 
@@ -200,6 +218,7 @@ err_vblank_cleanup:
        drm_vblank_cleanup(drm_dev);
 err_kms_helper_poll_fini:
        drm_kms_helper_poll_fini(drm_dev);
+err_unbind:
        component_unbind_all(dev, drm_dev);
 err_detach_device:
        arm_iommu_detach_device(dev);
index a5d889a8716bd776274462af116d873163ac5f87..5b0dc0f6fd940f7d6689f832e03c0c3cd1048656 100644 (file)
@@ -71,7 +71,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
 
        size = mode_cmd.pitches[0] * mode_cmd.height;
 
-       rk_obj = rockchip_gem_create_object(dev, size);
+       rk_obj = rockchip_gem_create_object(dev, size, true);
        if (IS_ERR(rk_obj))
                return -ENOMEM;
 
@@ -106,7 +106,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
 
        fb = helper->fb;
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
-       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+       drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
        offset = fbi->var.xoffset * bytes_per_pixel;
        offset += fbi->var.yoffset * fb->pitches[0];
@@ -119,6 +119,9 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
        DRM_DEBUG_KMS("FB [%dx%d]-%d kvaddr=%p offset=%ld size=%d\n",
                      fb->width, fb->height, fb->depth, rk_obj->kvaddr,
                      offset, size);
+
+       fbi->skip_vt_switch = true;
+
        return 0;
 
 err_drm_framebuffer_unref:
index 7ca8799ef78498ca84cc3a48f1265d2f1ce2f6c9..eb2282cc4a56507819a5ab638af504499157157a 100644 (file)
@@ -22,7 +22,8 @@
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
 
-static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj)
+static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
+                                 bool alloc_kmap)
 {
        struct drm_gem_object *obj = &rk_obj->base;
        struct drm_device *drm = obj->dev;
@@ -30,7 +31,9 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj)
        init_dma_attrs(&rk_obj->dma_attrs);
        dma_set_attr(DMA_ATTR_WRITE_COMBINE, &rk_obj->dma_attrs);
 
-       /* TODO(djkurtz): Use DMA_ATTR_NO_KERNEL_MAPPING except for fbdev */
+       if (!alloc_kmap)
+               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs);
+
        rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
                                         &rk_obj->dma_addr, GFP_KERNEL,
                                         &rk_obj->dma_attrs);
@@ -103,7 +106,8 @@ int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 }
 
 struct rockchip_gem_object *
-       rockchip_gem_create_object(struct drm_device *drm, unsigned int size)
+       rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
+                                  bool alloc_kmap)
 {
        struct rockchip_gem_object *rk_obj;
        struct drm_gem_object *obj;
@@ -119,7 +123,7 @@ struct rockchip_gem_object *
 
        drm_gem_private_object_init(drm, obj, size);
 
-       ret = rockchip_gem_alloc_buf(rk_obj);
+       ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
        if (ret)
                goto err_free_rk_obj;
 
@@ -163,7 +167,7 @@ rockchip_gem_create_with_handle(struct drm_file *file_priv,
        struct drm_gem_object *obj;
        int ret;
 
-       rk_obj = rockchip_gem_create_object(drm, size);
+       rk_obj = rockchip_gem_create_object(drm, size, false);
        if (IS_ERR(rk_obj))
                return ERR_CAST(rk_obj);
 
@@ -282,6 +286,9 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
 {
        struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
 
+       if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs))
+               return NULL;
+
        return rk_obj->kvaddr;
 }
 
index 67bcebe90003dbf5674e752aadd86f9041d6844a..ad22618473a488b10a10e1155f85bc79e1c8870e 100644 (file)
@@ -41,7 +41,8 @@ int rockchip_gem_mmap_buf(struct drm_gem_object *obj,
                          struct vm_area_struct *vma);
 
 struct rockchip_gem_object *
-       rockchip_gem_create_object(struct drm_device *drm, unsigned int size);
+       rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
+                                  bool alloc_kmap);
 
 void rockchip_gem_free_object(struct drm_gem_object *obj);
 
index 9a5c571b95fceb97dae7bfadf1b9782ede0f686e..ccb0ce073ef2af6f2233fbc88428ea176dbea855 100644 (file)
@@ -81,7 +81,7 @@ struct vop {
        struct drm_crtc crtc;
        struct device *dev;
        struct drm_device *drm_dev;
-       unsigned int dpms;
+       bool is_enabled;
 
        int connector_type;
        int connector_out_mode;
@@ -89,6 +89,7 @@ struct vop {
        /* mutex vsync_ work */
        struct mutex vsync_mutex;
        bool vsync_work_pending;
+       struct completion dsp_hold_completion;
 
        const struct vop_data *data;
 
@@ -382,11 +383,50 @@ static bool is_alpha_support(uint32_t format)
        }
 }
 
+static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
+{
+       unsigned long flags;
+
+       if (WARN_ON(!vop->is_enabled))
+               return;
+
+       spin_lock_irqsave(&vop->irq_lock, flags);
+
+       vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
+                      DSP_HOLD_VALID_INTR_EN(1));
+
+       spin_unlock_irqrestore(&vop->irq_lock, flags);
+}
+
+static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
+{
+       unsigned long flags;
+
+       if (WARN_ON(!vop->is_enabled))
+               return;
+
+       spin_lock_irqsave(&vop->irq_lock, flags);
+
+       vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
+                      DSP_HOLD_VALID_INTR_EN(0));
+
+       spin_unlock_irqrestore(&vop->irq_lock, flags);
+}
+
 static void vop_enable(struct drm_crtc *crtc)
 {
        struct vop *vop = to_vop(crtc);
        int ret;
 
+       if (vop->is_enabled)
+               return;
+
+       ret = pm_runtime_get_sync(vop->dev);
+       if (ret < 0) {
+               dev_err(vop->dev, "failed to get pm runtime: %d\n", ret);
+               return;
+       }
+
        ret = clk_enable(vop->hclk);
        if (ret < 0) {
                dev_err(vop->dev, "failed to enable hclk - %d\n", ret);
@@ -417,6 +457,11 @@ static void vop_enable(struct drm_crtc *crtc)
                goto err_disable_aclk;
        }
 
+       /*
+        * At here, vop clock & iommu is enable, R/W vop regs would be safe.
+        */
+       vop->is_enabled = true;
+
        spin_lock(&vop->reg_lock);
 
        VOP_CTRL_SET(vop, standby, 0);
@@ -441,28 +486,44 @@ static void vop_disable(struct drm_crtc *crtc)
 {
        struct vop *vop = to_vop(crtc);
 
-       drm_vblank_off(crtc->dev, vop->pipe);
+       if (!vop->is_enabled)
+               return;
 
-       disable_irq(vop->irq);
+       drm_vblank_off(crtc->dev, vop->pipe);
 
        /*
-        * TODO: Since standby doesn't take effect until the next vblank,
-        * when we turn off dclk below, the vop is probably still active.
+        * Vop standby will take effect at end of current frame,
+        * if dsp hold valid irq happen, it means standby complete.
+        *
+        * we must wait standby complete when we want to disable aclk,
+        * if not, memory bus maybe dead.
         */
+       reinit_completion(&vop->dsp_hold_completion);
+       vop_dsp_hold_valid_irq_enable(vop);
+
        spin_lock(&vop->reg_lock);
 
        VOP_CTRL_SET(vop, standby, 1);
 
        spin_unlock(&vop->reg_lock);
+
+       wait_for_completion(&vop->dsp_hold_completion);
+
+       vop_dsp_hold_valid_irq_disable(vop);
+
+       disable_irq(vop->irq);
+
+       vop->is_enabled = false;
+
        /*
-        * disable dclk to stop frame scan, so we can safely detach iommu,
+        * vop standby complete, so iommu detach is safe.
         */
-       clk_disable(vop->dclk);
-
        rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev);
 
+       clk_disable(vop->dclk);
        clk_disable(vop->aclk);
        clk_disable(vop->hclk);
+       pm_runtime_put(vop->dev);
 }
 
 /*
@@ -742,7 +803,7 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
        struct vop *vop = to_vop(crtc);
        unsigned long flags;
 
-       if (vop->dpms != DRM_MODE_DPMS_ON)
+       if (!vop->is_enabled)
                return -EPERM;
 
        spin_lock_irqsave(&vop->irq_lock, flags);
@@ -759,8 +820,9 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
        struct vop *vop = to_vop(crtc);
        unsigned long flags;
 
-       if (vop->dpms != DRM_MODE_DPMS_ON)
+       if (!vop->is_enabled)
                return;
+
        spin_lock_irqsave(&vop->irq_lock, flags);
        vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(0));
        spin_unlock_irqrestore(&vop->irq_lock, flags);
@@ -773,15 +835,8 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = {
 
 static void vop_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
-       struct vop *vop = to_vop(crtc);
-
        DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
 
-       if (vop->dpms == mode) {
-               DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
-               return;
-       }
-
        switch (mode) {
        case DRM_MODE_DPMS_ON:
                vop_enable(crtc);
@@ -795,8 +850,6 @@ static void vop_crtc_dpms(struct drm_crtc *crtc, int mode)
                DRM_DEBUG_KMS("unspecified mode %d\n", mode);
                break;
        }
-
-       vop->dpms = mode;
 }
 
 static void vop_crtc_prepare(struct drm_crtc *crtc)
@@ -847,7 +900,7 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
        u16 vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
        u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start;
        u16 vact_end = vact_st + vdisplay;
-       int ret;
+       int ret, ret_clk;
        uint32_t val;
 
        /*
@@ -869,13 +922,14 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
        default:
                DRM_ERROR("unsupport connector_type[%d]\n",
                          vop->connector_type);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        };
        VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode);
 
        val = 0x8;
-       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0;
-       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? (1 << 1) : 0;
+       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
+       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
        VOP_CTRL_SET(vop, pin_pol, val);
 
        VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len);
@@ -892,7 +946,7 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
 
        ret = vop_crtc_mode_set_base(crtc, x, y, fb);
        if (ret)
-               return ret;
+               goto out;
 
        /*
         * reset dclk, take all mode config affect, so the clk would run in
@@ -903,13 +957,14 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
        reset_control_deassert(vop->dclk_rst);
 
        clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
-       ret = clk_enable(vop->dclk);
-       if (ret < 0) {
-               dev_err(vop->dev, "failed to enable dclk - %d\n", ret);
-               return ret;
+out:
+       ret_clk = clk_enable(vop->dclk);
+       if (ret_clk < 0) {
+               dev_err(vop->dev, "failed to enable dclk - %d\n", ret_clk);
+               return ret_clk;
        }
 
-       return 0;
+       return ret;
 }
 
 static void vop_crtc_commit(struct drm_crtc *crtc)
@@ -934,9 +989,9 @@ static int vop_crtc_page_flip(struct drm_crtc *crtc,
        struct drm_framebuffer *old_fb = crtc->primary->fb;
        int ret;
 
-       /* when the page flip is requested, crtc's dpms should be on */
-       if (vop->dpms > DRM_MODE_DPMS_ON) {
-               DRM_DEBUG("failed page flip request at dpms[%d].\n", vop->dpms);
+       /* when the page flip is requested, crtc should be on */
+       if (!vop->is_enabled) {
+               DRM_DEBUG("page flip request rejected because crtc is off.\n");
                return 0;
        }
 
@@ -1081,6 +1136,7 @@ static irqreturn_t vop_isr(int irq, void *data)
        struct vop *vop = data;
        uint32_t intr0_reg, active_irqs;
        unsigned long flags;
+       int ret = IRQ_NONE;
 
        /*
         * INTR_CTRL0 register has interrupt status, enable and clear bits, we
@@ -1099,15 +1155,23 @@ static irqreturn_t vop_isr(int irq, void *data)
        if (!active_irqs)
                return IRQ_NONE;
 
-       /* Only Frame Start Interrupt is enabled; other irqs are spurious. */
-       if (!(active_irqs & FS_INTR)) {
-               DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
-               return IRQ_NONE;
+       if (active_irqs & DSP_HOLD_VALID_INTR) {
+               complete(&vop->dsp_hold_completion);
+               active_irqs &= ~DSP_HOLD_VALID_INTR;
+               ret = IRQ_HANDLED;
+       }
+
+       if (active_irqs & FS_INTR) {
+               drm_handle_vblank(vop->drm_dev, vop->pipe);
+               active_irqs &= ~FS_INTR;
+               ret = (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
        }
 
-       drm_handle_vblank(vop->drm_dev, vop->pipe);
+       /* Unhandled irqs are spurious. */
+       if (active_irqs)
+               DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
 
-       return (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+       return ret;
 }
 
 static int vop_create_crtc(struct vop *vop)
@@ -1189,6 +1253,7 @@ static int vop_create_crtc(struct vop *vop)
                goto err_cleanup_crtc;
        }
 
+       init_completion(&vop->dsp_hold_completion);
        crtc->port = port;
        vop->pipe = drm_crtc_index(crtc);
        rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe);
@@ -1302,7 +1367,7 @@ static int vop_initial(struct vop *vop)
 
        clk_disable(vop->hclk);
 
-       vop->dpms = DRM_MODE_DPMS_OFF;
+       vop->is_enabled = false;
 
        return 0;
 
index e6f6ef7c4866ad94eb7bd503eabc9aee7e2b8181..6b641c5a2ec7d10609f20a38cbe6bab56c9f4c5e 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/clk.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_plane_helper.h>
 
@@ -77,22 +79,18 @@ static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc,
 }
 
 static int
-sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
-                     struct drm_display_mode *adjusted_mode, int x, int y,
-                     struct drm_framebuffer *old_fb)
+sti_drm_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;
        struct sti_compositor *compo = dev_get_drvdata(dev);
-       struct sti_layer *layer;
        struct clk *clk;
        int rate = mode->clock * 1000;
        int res;
-       unsigned int w, h;
 
-       DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n",
+       DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n",
                      crtc->base.id, sti_mixer_to_str(mixer),
-                     crtc->primary->fb->base.id, mode->base.id, mode->name);
+                     mode->base.id, mode->name);
 
        DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
                      mode->vrefresh, mode->clock,
@@ -122,72 +120,13 @@ sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
        sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ?
                        compo->vtg_main : compo->vtg_aux, &crtc->mode);
 
-       /* a GDP is reserved to the CRTC FB */
-       layer = to_sti_layer(crtc->primary);
-       if (!layer) {
-               DRM_ERROR("Can not find GDP0)\n");
-               return -EINVAL;
-       }
-
-       /* copy the mode data adjusted by mode_fixup() into crtc->mode
-        * so that hardware can be set to proper mode
-        */
-       memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
-
-       res = sti_mixer_set_layer_depth(mixer, layer);
-       if (res) {
-               DRM_ERROR("Can not set layer depth\n");
-               return -EINVAL;
-       }
        res = sti_mixer_active_video_area(mixer, &crtc->mode);
        if (res) {
                DRM_ERROR("Can not set active video area\n");
                return -EINVAL;
        }
 
-       w = crtc->primary->fb->width - x;
-       h = crtc->primary->fb->height - y;
-
-       return sti_layer_prepare(layer, crtc,
-                       crtc->primary->fb, &crtc->mode,
-                       mixer->id, 0, 0, w, h, x, y, w, h);
-}
-
-static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-                                     struct drm_framebuffer *old_fb)
-{
-       struct sti_mixer *mixer = to_sti_mixer(crtc);
-       struct sti_layer *layer;
-       unsigned int w, h;
-       int ret;
-
-       DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n",
-                     crtc->base.id, sti_mixer_to_str(mixer),
-                     crtc->primary->fb->base.id, x, y);
-
-       /* GDP is reserved to the CRTC FB */
-       layer = to_sti_layer(crtc->primary);
-       if (!layer) {
-               DRM_ERROR("Can not find GDP0)\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       w = crtc->primary->fb->width - crtc->x;
-       h = crtc->primary->fb->height - crtc->y;
-
-       ret = sti_layer_prepare(layer, crtc,
-                               crtc->primary->fb, &crtc->mode,
-                               mixer->id, 0, 0, w, h,
-                               crtc->x, crtc->y, w, h);
-       if (ret) {
-               DRM_ERROR("Can not prepare layer\n");
-               goto out;
-       }
-
-       sti_drm_crtc_commit(crtc);
-out:
-       return ret;
+       return res;
 }
 
 static void sti_drm_crtc_disable(struct drm_crtc *crtc)
@@ -195,7 +134,6 @@ static void sti_drm_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);
-       struct sti_layer *layer;
 
        if (!mixer->enabled)
                return;
@@ -205,24 +143,6 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
        /* Disable Background */
        sti_mixer_set_background_status(mixer, false);
 
-       /* Disable GDP */
-       layer = to_sti_layer(crtc->primary);
-       if (!layer) {
-               DRM_ERROR("Cannot find GDP0\n");
-               return;
-       }
-
-       /* Disable layer at mixer level */
-       if (sti_mixer_set_layer_status(mixer, layer, false))
-               DRM_ERROR("Can not disable %s layer at mixer\n",
-                               sti_layer_to_str(layer));
-
-       /* Wait a while to be sure that a Vsync event is received */
-       msleep(WAIT_NEXT_VSYNC_MS);
-
-       /* Then disable layer itself */
-       sti_layer_disable(layer);
-
        drm_crtc_vblank_off(crtc);
 
        /* Disable pixel clock and compo IP clocks */
@@ -237,64 +157,44 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
        mixer->enabled = false;
 }
 
-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,
-       .mode_set = sti_drm_crtc_mode_set,
-       .mode_set_base = sti_drm_crtc_mode_set_base,
-       .disable = sti_drm_crtc_disable,
-};
+static void
+sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+       sti_drm_crtc_prepare(crtc);
+       sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
+}
 
-static int sti_drm_crtc_page_flip(struct drm_crtc *crtc,
-                                 struct drm_framebuffer *fb,
-                                 struct drm_pending_vblank_event *event,
-                                 uint32_t page_flip_flags)
+static void sti_drm_atomic_begin(struct drm_crtc *crtc)
 {
-       struct drm_device *drm_dev = crtc->dev;
-       struct drm_framebuffer *old_fb;
        struct sti_mixer *mixer = to_sti_mixer(crtc);
-       unsigned long flags;
-       int ret;
 
-       DRM_DEBUG_KMS("fb %d --> fb %d\n",
-                       crtc->primary->fb->base.id, fb->base.id);
+       if (crtc->state->event) {
+               crtc->state->event->pipe = drm_crtc_index(crtc);
 
-       mutex_lock(&drm_dev->struct_mutex);
+               WARN_ON(drm_crtc_vblank_get(crtc) != 0);
 
-       old_fb = crtc->primary->fb;
-       crtc->primary->fb = fb;
-       ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
-       if (ret) {
-               DRM_ERROR("failed\n");
-               crtc->primary->fb = old_fb;
-               goto out;
+               mixer->pending_event = crtc->state->event;
+               crtc->state->event = NULL;
        }
+}
 
-       if (event) {
-               event->pipe = mixer->id;
-
-               ret = drm_vblank_get(drm_dev, event->pipe);
-               if (ret) {
-                       DRM_ERROR("Cannot get vblank\n");
-                       goto out;
-               }
-
-               spin_lock_irqsave(&drm_dev->event_lock, flags);
-               if (mixer->pending_event) {
-                       drm_vblank_put(drm_dev, event->pipe);
-                       ret = -EBUSY;
-               } else {
-                       mixer->pending_event = event;
-               }
-               spin_unlock_irqrestore(&drm_dev->event_lock, flags);
-       }
-out:
-       mutex_unlock(&drm_dev->struct_mutex);
-       return ret;
+static void sti_drm_atomic_flush(struct drm_crtc *crtc)
+{
 }
 
+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,
+       .mode_set = drm_helper_crtc_mode_set,
+       .mode_set_nofb = sti_drm_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,
+};
+
 static void sti_drm_crtc_destroy(struct drm_crtc *crtc)
 {
        DRM_DEBUG_KMS("\n");
@@ -380,10 +280,13 @@ void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
 EXPORT_SYMBOL(sti_drm_crtc_disable_vblank);
 
 static struct drm_crtc_funcs sti_crtc_funcs = {
-       .set_config = drm_crtc_helper_set_config,
-       .page_flip = sti_drm_crtc_page_flip,
+       .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,
+       .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)
index 5239fa12172683cd2313e3863107acc26c7c08c0..59d558b400b33f390cdd6db00014ab29c94b84d4 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/module.h>
 #include <linux/of_platform.h>
 
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #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)
+{
+       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)
+{
+       struct drm_device *drm = private->drm_dev;
+
+       /*
+        * Everything below can be run asynchronously without the need to grab
+        * any modeset locks at all under one condition: It must be guaranteed
+        * that the asynchronous work has either been cancelled (if the driver
+        * supports it, which at least requires that the framebuffers get
+        * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
+        * before the new state gets committed on the software side with
+        * drm_atomic_helper_swap_state().
+        *
+        * This scheme allows new atomic state updates to be prepared and
+        * checked in parallel to the asynchronous completion of the previous
+        * update. Which is important since compositors need to figure out the
+        * composition of the next frame right after having submitted the
+        * current layout.
+        */
+
+       drm_atomic_helper_commit_modeset_disables(drm, state);
+       drm_atomic_helper_commit_planes(drm, state);
+       drm_atomic_helper_commit_modeset_enables(drm, state);
+
+       drm_atomic_helper_wait_for_vblanks(drm, state);
+
+       drm_atomic_helper_cleanup_planes(drm, state);
+       drm_atomic_state_free(state);
+}
+
+static void sti_drm_atomic_work(struct work_struct *work)
+{
+       struct sti_drm_private *private = container_of(work,
+                       struct sti_drm_private, commit.work);
+
+       sti_drm_atomic_complete(private, private->commit.state);
+}
+
+static int sti_drm_atomic_commit(struct drm_device *drm,
+                              struct drm_atomic_state *state, bool async)
+{
+       struct sti_drm_private *private = drm->dev_private;
+       int err;
+
+       err = drm_atomic_helper_prepare_planes(drm, state);
+       if (err)
+               return err;
+
+       /* serialize outstanding asynchronous commits */
+       mutex_lock(&private->commit.lock);
+       flush_work(&private->commit.work);
+
+       /*
+        * This is the point of no return - everything below never fails except
+        * when the hw goes bonghits. Which means we can commit the new state on
+        * the software side now.
+        */
+
+       drm_atomic_helper_swap_state(drm, state);
+
+       if (async)
+               sti_drm_atomic_schedule(private, state);
+       else
+               sti_drm_atomic_complete(private, state);
+
+       mutex_unlock(&private->commit.lock);
+       return 0;
+}
+
 static struct drm_mode_config_funcs sti_drm_mode_config_funcs = {
        .fb_create = drm_fb_cma_create,
+       .atomic_check = drm_atomic_helper_check,
+       .atomic_commit = sti_drm_atomic_commit,
 };
 
 static void sti_drm_mode_config_init(struct drm_device *dev)
@@ -61,6 +142,9 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags)
        dev->dev_private = (void *)private;
        private->drm_dev = dev;
 
+       mutex_init(&private->commit.lock);
+       INIT_WORK(&private->commit.work, sti_drm_atomic_work);
+
        drm_mode_config_init(dev);
        drm_kms_helper_poll_init(dev);
 
@@ -74,7 +158,7 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags)
                return ret;
        }
 
-       drm_helper_disable_unused_functions(dev);
+       drm_mode_config_reset(dev);
 
 #ifdef CONFIG_DRM_STI_FBDEV
        drm_fbdev_cma_init(dev, 32,
index ec5e2eb8dff91e24cc5c0a7321012b4b93d158ff..c413aa3ff4021449791f3ce73668d8beabdb94c9 100644 (file)
@@ -24,6 +24,12 @@ struct sti_drm_private {
        struct sti_compositor *compo;
        struct drm_property *plane_zorder_property;
        struct drm_device *drm_dev;
+
+       struct {
+               struct drm_atomic_state *state;
+               struct work_struct work;
+               struct mutex lock;
+       } commit;
 };
 
 #endif
index bb6a29339e1084bca0483e7ee643cfc62c06299a..64d4ed43dda3fa6e38a81a7bb4ba9bafba02287a 100644 (file)
@@ -6,6 +6,10 @@
  * 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"
@@ -33,9 +37,9 @@ sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        int res;
 
-       DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s) drm fb:%d\n",
+       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), fb->base.id);
+                     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);
@@ -110,7 +114,7 @@ static void sti_drm_plane_destroy(struct drm_plane *plane)
 {
        DRM_DEBUG_DRIVER("\n");
 
-       sti_drm_disable_plane(plane);
+       drm_plane_helper_disable(plane);
        drm_plane_cleanup(plane);
 }
 
@@ -133,10 +137,58 @@ static int sti_drm_plane_set_property(struct drm_plane *plane,
 }
 
 static struct drm_plane_funcs sti_drm_plane_funcs = {
-       .update_plane = sti_drm_update_plane,
-       .disable_plane = sti_drm_disable_plane,
+       .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,
@@ -178,11 +230,13 @@ struct drm_plane *sti_drm_plane_init(struct drm_device *dev,
                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;
+       default_zorder = i + 1;
 
        if (type == DRM_PLANE_TYPE_OVERLAY)
                sti_drm_plane_attach_zorder_property(&layer->plane,
index aeb5070c8363fb6307ab7c6c768dab9fefece269..a9b678af85a6f315716fa82871674519e017b9f3 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/platform_device.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_panel.h>
 
@@ -364,10 +365,13 @@ static void sti_dvo_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs sti_dvo_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = sti_dvo_connector_detect,
        .destroy = sti_dvo_connector_destroy,
+       .reset = drm_atomic_helper_connector_reset,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev)
index a9bbb081ecadc1165031b9c794b753d083b9ee2f..598cd78b0b163cd2e86f92a68e5386325a3a357f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/platform_device.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 
 /* HDformatter registers */
@@ -611,10 +612,13 @@ static void sti_hda_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs sti_hda_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = sti_hda_connector_detect,
        .destroy = sti_hda_connector_destroy,
+       .reset = drm_atomic_helper_connector_reset,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev)
index 1485ade98710a3078de14c8b577db2a5bd15cd21..ae5424bd6b4cbd00d1ffc5b4fd35f11cb56a11cd 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/reset.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 
@@ -663,10 +664,13 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs sti_hdmi_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = sti_hdmi_connector_detect,
        .destroy = sti_hdmi_connector_destroy,
+       .reset = drm_atomic_helper_connector_reset,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)
index 3aaa84ae26811fb8c731a89e76b91297b1ff3bf3..a287e4fec8653d91e55bb2765e2379984b65bef5 100644 (file)
@@ -425,8 +425,8 @@ static void tegra_plane_reset(struct drm_plane *plane)
 {
        struct tegra_plane_state *state;
 
-       if (plane->state && plane->state->fb)
-               drm_framebuffer_unreference(plane->state->fb);
+       if (plane->state)
+               __drm_atomic_helper_plane_destroy_state(plane, plane->state);
 
        kfree(plane->state);
        plane->state = NULL;
@@ -443,12 +443,14 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla
        struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
        struct tegra_plane_state *copy;
 
-       copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+       copy = kmalloc(sizeof(*copy), GFP_KERNEL);
        if (!copy)
                return NULL;
 
-       if (copy->base.fb)
-               drm_framebuffer_reference(copy->base.fb);
+       __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
+       copy->tiling = state->tiling;
+       copy->format = state->format;
+       copy->swap = state->swap;
 
        return &copy->base;
 }
@@ -456,9 +458,7 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla
 static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
                                             struct drm_plane_state *state)
 {
-       if (state->fb)
-               drm_framebuffer_unreference(state->fb);
-
+       __drm_atomic_helper_plane_destroy_state(plane, state);
        kfree(state);
 }
 
@@ -472,13 +472,15 @@ static const struct drm_plane_funcs tegra_primary_plane_funcs = {
 };
 
 static int tegra_plane_prepare_fb(struct drm_plane *plane,
-                                 struct drm_framebuffer *fb)
+                                 struct drm_framebuffer *fb,
+                                 const struct drm_plane_state *new_state)
 {
        return 0;
 }
 
 static void tegra_plane_cleanup_fb(struct drm_plane *plane,
-                                  struct drm_framebuffer *fb)
+                                  struct drm_framebuffer *fb,
+                                  const struct drm_plane_state *old_fb)
 {
 }
 
@@ -906,6 +908,15 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
        return 0;
 }
 
+u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc)
+{
+       if (dc->syncpt)
+               return host1x_syncpt_read(dc->syncpt);
+
+       /* fallback to software emulated VBLANK counter */
+       return drm_crtc_vblank_count(&dc->base);
+}
+
 void tegra_dc_enable_vblank(struct tegra_dc *dc)
 {
        unsigned long value, flags;
@@ -993,12 +1004,17 @@ static void tegra_crtc_reset(struct drm_crtc *crtc)
 {
        struct tegra_dc_state *state;
 
+       if (crtc->state)
+               __drm_atomic_helper_crtc_destroy_state(crtc, crtc->state);
+
        kfree(crtc->state);
        crtc->state = NULL;
 
        state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (state)
+       if (state) {
                crtc->state = &state->base;
+               crtc->state->crtc = crtc;
+       }
 }
 
 static struct drm_crtc_state *
@@ -1007,13 +1023,15 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
        struct tegra_dc_state *state = to_dc_state(crtc->state);
        struct tegra_dc_state *copy;
 
-       copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+       copy = kmalloc(sizeof(*copy), GFP_KERNEL);
        if (!copy)
                return NULL;
 
-       copy->base.mode_changed = false;
-       copy->base.planes_changed = false;
-       copy->base.event = NULL;
+       __drm_atomic_helper_crtc_duplicate_state(crtc, &copy->base);
+       copy->clk = state->clk;
+       copy->pclk = state->pclk;
+       copy->div = state->div;
+       copy->planes = state->planes;
 
        return &copy->base;
 }
@@ -1021,6 +1039,7 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
                                            struct drm_crtc_state *state)
 {
+       __drm_atomic_helper_crtc_destroy_state(crtc, state);
        kfree(state);
 }
 
@@ -1147,26 +1166,18 @@ static int tegra_dc_set_timings(struct tegra_dc *dc,
        return 0;
 }
 
-int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
-                        unsigned long pclk, unsigned int div)
-{
-       u32 value;
-       int err;
-
-       err = clk_set_parent(dc->clk, parent);
-       if (err < 0) {
-               dev_err(dc->dev, "failed to set parent clock: %d\n", err);
-               return err;
-       }
-
-       DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), div);
-
-       value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1;
-       tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
-
-       return 0;
-}
-
+/**
+ * tegra_dc_state_setup_clock - check clock settings and store them in atomic
+ *     state
+ * @dc: display controller
+ * @crtc_state: CRTC atomic state
+ * @clk: parent clock for display controller
+ * @pclk: pixel clock
+ * @div: shift clock divider
+ *
+ * Returns:
+ * 0 on success or a negative error-code on failure.
+ */
 int tegra_dc_state_setup_clock(struct tegra_dc *dc,
                               struct drm_crtc_state *crtc_state,
                               struct clk *clk, unsigned long pclk,
@@ -1174,6 +1185,9 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc,
 {
        struct tegra_dc_state *state = to_dc_state(crtc_state);
 
+       if (!clk_has_parent(dc->clk, clk))
+               return -EINVAL;
+
        state->clk = clk;
        state->pclk = pclk;
        state->div = div;
@@ -1227,9 +1241,6 @@ static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
        /* program display mode */
        tegra_dc_set_timings(dc, mode);
 
-       if (dc->soc->supports_border_color)
-               tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
-
        /* interlacing isn't supported yet, so disable it */
        if (dc->soc->supports_interlacing) {
                value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL);
@@ -1252,42 +1263,7 @@ static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
 
 static void tegra_crtc_prepare(struct drm_crtc *crtc)
 {
-       struct tegra_dc *dc = to_tegra_dc(crtc);
-       unsigned int syncpt;
-       unsigned long value;
-
        drm_crtc_vblank_off(crtc);
-
-       if (dc->pipe)
-               syncpt = SYNCPT_VBLANK1;
-       else
-               syncpt = SYNCPT_VBLANK0;
-
-       /* initialize display controller */
-       tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
-       tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
-
-       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
-       tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
-
-       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_POLARITY);
-
-       /* initialize timer */
-       value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
-               WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
-       tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);
-
-       value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |
-               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;
-       tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
-
-       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
-       tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
 }
 
 static void tegra_crtc_commit(struct drm_crtc *crtc)
@@ -1327,9 +1303,7 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc)
 static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
        .disable = tegra_crtc_disable,
        .mode_fixup = tegra_crtc_mode_fixup,
-       .mode_set = drm_helper_crtc_mode_set,
        .mode_set_nofb = tegra_crtc_mode_set_nofb,
-       .mode_set_base = drm_helper_crtc_mode_set_base,
        .prepare = tegra_crtc_prepare,
        .commit = tegra_crtc_commit,
        .atomic_check = tegra_crtc_atomic_check,
@@ -1664,6 +1638,7 @@ static int tegra_dc_init(struct host1x_client *client)
        struct tegra_drm *tegra = drm->dev_private;
        struct drm_plane *primary = NULL;
        struct drm_plane *cursor = NULL;
+       u32 value;
        int err;
 
        if (tegra->domain) {
@@ -1730,6 +1705,42 @@ static int tegra_dc_init(struct host1x_client *client)
                goto cleanup;
        }
 
+       /* initialize display controller */
+       if (dc->syncpt) {
+               u32 syncpt = host1x_syncpt_id(dc->syncpt);
+
+               value = SYNCPT_CNTRL_NO_STALL;
+               tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
+
+               value = SYNCPT_VSYNC_ENABLE | syncpt;
+               tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC);
+       }
+
+       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
+       tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
+
+       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_POLARITY);
+
+       /* initialize timer */
+       value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
+               WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
+       tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);
+
+       value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |
+               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;
+       tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
+
+       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_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);
+
        return 0;
 
 cleanup:
@@ -1871,6 +1882,7 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
 
 static int tegra_dc_probe(struct platform_device *pdev)
 {
+       unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
        const struct of_device_id *id;
        struct resource *regs;
        struct tegra_dc *dc;
@@ -1962,6 +1974,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
                return err;
        }
 
+       dc->syncpt = host1x_syncpt_request(&pdev->dev, flags);
+       if (!dc->syncpt)
+               dev_warn(&pdev->dev, "failed to allocate syncpoint\n");
+
        platform_set_drvdata(pdev, dc);
 
        return 0;
@@ -1972,6 +1988,8 @@ static int tegra_dc_remove(struct platform_device *pdev)
        struct tegra_dc *dc = platform_get_drvdata(pdev);
        int err;
 
+       host1x_syncpt_free(dc->syncpt);
+
        err = host1x_client_unregister(&dc->client);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
index 705c93b00794feb38f56a501b7546f9e6f07b1f9..55792daabbb587b80712c684742c902c1303ee65 100644 (file)
@@ -12,6 +12,8 @@
 
 #define DC_CMD_GENERAL_INCR_SYNCPT             0x000
 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL       0x001
+#define  SYNCPT_CNTRL_NO_STALL   (1 << 8)
+#define  SYNCPT_CNTRL_SOFT_RESET (1 << 0)
 #define DC_CMD_GENERAL_INCR_SYNCPT_ERROR       0x002
 #define DC_CMD_WIN_A_INCR_SYNCPT               0x008
 #define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL         0x009
@@ -23,6 +25,7 @@
 #define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL         0x019
 #define DC_CMD_WIN_C_INCR_SYNCPT_ERROR         0x01a
 #define DC_CMD_CONT_SYNCPT_VSYNC               0x028
+#define  SYNCPT_VSYNC_ENABLE (1 << 8)
 #define DC_CMD_DISPLAY_COMMAND_OPTION0         0x031
 #define DC_CMD_DISPLAY_COMMAND                 0x032
 #define DISP_CTRL_MODE_STOP (0 << 5)
 #define DC_WINBUF_BD_UFLOW_STATUS              0xdca
 #define DC_WINBUF_CD_UFLOW_STATUS              0xfca
 
-/* synchronization points */
-#define SYNCPT_VBLANK0 26
-#define SYNCPT_VBLANK1 27
-
 #endif /* TEGRA_DC_H */
index 7dd328d77996f77101d77e43f41049c66202bfcd..1833abd7d3aafa38c796cc5acb7d3bb9a8356c86 100644 (file)
@@ -55,9 +55,9 @@ static void tegra_atomic_complete(struct tegra_drm *tegra,
         * current layout.
         */
 
-       drm_atomic_helper_commit_pre_planes(drm, state);
+       drm_atomic_helper_commit_modeset_disables(drm, state);
        drm_atomic_helper_commit_planes(drm, state);
-       drm_atomic_helper_commit_post_planes(drm, state);
+       drm_atomic_helper_commit_modeset_enables(drm, state);
 
        drm_atomic_helper_wait_for_vblanks(drm, state);
 
@@ -172,6 +172,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
         */
        drm->irq_enabled = true;
 
+       /* syncpoints are used for full 32-bit hardware VBLANK counters */
+       drm->vblank_disable_immediate = true;
+       drm->max_vblank_count = 0xffffffff;
+
        err = drm_vblank_init(drm, drm->mode_config.num_crtc);
        if (err < 0)
                goto device;
@@ -813,12 +817,12 @@ static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm,
 static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe)
 {
        struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+       struct tegra_dc *dc = to_tegra_dc(crtc);
 
        if (!crtc)
                return 0;
 
-       /* TODO: implement real hardware counter using syncpoints */
-       return drm_crtc_vblank_count(crtc);
+       return tegra_dc_get_vblank_counter(dc);
 }
 
 static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
@@ -879,8 +883,18 @@ static int tegra_debugfs_framebuffers(struct seq_file *s, void *data)
        return 0;
 }
 
+static int tegra_debugfs_iova(struct seq_file *s, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *)s->private;
+       struct drm_device *drm = node->minor->dev;
+       struct tegra_drm *tegra = drm->dev_private;
+
+       return drm_mm_dump_table(s, &tegra->mm);
+}
+
 static struct drm_info_list tegra_debugfs_list[] = {
        { "framebuffers", tegra_debugfs_framebuffers, 0 },
+       { "iova", tegra_debugfs_iova, 0 },
 };
 
 static int tegra_debugfs_init(struct drm_minor *minor)
index 8cb2dfeaa957380a344a0e0c934d88eebcfa2c46..659b2fcc986dcf1c8ef4abc7364f288b128a3411 100644 (file)
@@ -106,6 +106,7 @@ struct tegra_output;
 
 struct tegra_dc {
        struct host1x_client client;
+       struct host1x_syncpt *syncpt;
        struct device *dev;
        spinlock_t lock;
 
@@ -180,12 +181,11 @@ struct tegra_dc_window {
 };
 
 /* from dc.c */
+u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc);
 void tegra_dc_enable_vblank(struct tegra_dc *dc);
 void tegra_dc_disable_vblank(struct tegra_dc *dc);
 void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
 void tegra_dc_commit(struct tegra_dc *dc);
-int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
-                        unsigned long pclk, unsigned int div);
 int tegra_dc_state_setup_clock(struct tegra_dc *dc,
                               struct drm_crtc_state *crtc_state,
                               struct clk *clk, unsigned long pclk,
index 7e06657ae58bc1eb2202e7da6c193eb4c8ca862b..06ab1783bba11e7b1299e3d950accf1547e20285 100644 (file)
@@ -851,6 +851,14 @@ static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder,
        h_back_porch = mode->htotal - mode->hsync_end;
        h_front_porch = mode->hsync_start - mode->hdisplay;
 
+       err = clk_set_rate(hdmi->clk, pclk);
+       if (err < 0) {
+               dev_err(hdmi->dev, "failed to set HDMI clock frequency: %d\n",
+                       err);
+       }
+
+       DRM_DEBUG_KMS("HDMI clock rate: %lu Hz\n", clk_get_rate(hdmi->clk));
+
        /* power up sequence */
        value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PLL0);
        value &= ~SOR_PLL_PDBG;
@@ -944,7 +952,7 @@ static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        tegra_hdmi_writel(hdmi,
-                         SOR_SEQ_CTL_PU_PC(0) |
+                         SOR_SEQ_PU_PC(0) |
                          SOR_SEQ_PU_PC_ALT(0) |
                          SOR_SEQ_PD_PC(8) |
                          SOR_SEQ_PD_PC_ALT(8),
@@ -1386,8 +1394,8 @@ static int tegra_hdmi_exit(struct host1x_client *client)
 
        tegra_output_exit(&hdmi->output);
 
-       clk_disable_unprepare(hdmi->clk);
        reset_control_assert(hdmi->rst);
+       clk_disable_unprepare(hdmi->clk);
 
        regulator_disable(hdmi->vdd);
        regulator_disable(hdmi->pll);
index 919a19df4e1b59257b3969887fc288c11e43e1d1..a882514389cd05a35e503c8b0adb2bb39ba91ae4 100644 (file)
 #define HDMI_NV_PDISP_SOR_CRCB                                 0x5d
 #define HDMI_NV_PDISP_SOR_BLANK                                        0x5e
 #define HDMI_NV_PDISP_SOR_SEQ_CTL                              0x5f
-#define SOR_SEQ_CTL_PU_PC(x) (((x) & 0xf) <<  0)
+#define SOR_SEQ_PU_PC(x)     (((x) & 0xf) <<  0)
 #define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) <<  4)
 #define SOR_SEQ_PD_PC(x)     (((x) & 0xf) <<  8)
 #define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12)
index 2afe478ded3ba78e215f678f0ecd0ce09f520755..7591d8901f9a24ddd61d035500116c617e4df3f6 100644 (file)
@@ -41,6 +41,8 @@ struct tegra_sor {
        struct mutex lock;
        bool enabled;
 
+       struct drm_info_list *debugfs_files;
+       struct drm_minor *minor;
        struct dentry *debugfs;
 };
 
@@ -68,13 +70,12 @@ static inline struct tegra_sor *to_sor(struct tegra_output *output)
        return container_of(output, struct tegra_sor, output);
 }
 
-static inline unsigned long tegra_sor_readl(struct tegra_sor *sor,
-                                           unsigned long offset)
+static inline u32 tegra_sor_readl(struct tegra_sor *sor, unsigned long offset)
 {
        return readl(sor->regs + (offset << 2));
 }
 
-static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value,
+static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value,
                                    unsigned long offset)
 {
        writel(value, sor->regs + (offset << 2));
@@ -83,9 +84,9 @@ static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value,
 static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
                                   struct drm_dp_link *link)
 {
-       unsigned long value;
        unsigned int i;
        u8 pattern;
+       u32 value;
        int err;
 
        /* setup lane parameters */
@@ -202,7 +203,7 @@ static void tegra_sor_update(struct tegra_sor *sor)
 
 static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout)
 {
-       unsigned long value;
+       u32 value;
 
        value = tegra_sor_readl(sor, SOR_PWM_DIV);
        value &= ~SOR_PWM_DIV_MASK;
@@ -281,7 +282,7 @@ static int tegra_sor_wakeup(struct tegra_sor *sor)
 
 static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout)
 {
-       unsigned long value;
+       u32 value;
 
        value = tegra_sor_readl(sor, SOR_PWR);
        value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU;
@@ -674,38 +675,195 @@ static const struct file_operations tegra_sor_crc_fops = {
        .release = tegra_sor_crc_release,
 };
 
+static int tegra_sor_show_regs(struct seq_file *s, void *data)
+{
+       struct drm_info_node *node = s->private;
+       struct tegra_sor *sor = node->info_ent->data;
+
+#define DUMP_REG(name)                                         \
+       seq_printf(s, "%-38s %#05x %08x\n", #name, name,        \
+                  tegra_sor_readl(sor, name))
+
+       DUMP_REG(SOR_CTXSW);
+       DUMP_REG(SOR_SUPER_STATE_0);
+       DUMP_REG(SOR_SUPER_STATE_1);
+       DUMP_REG(SOR_STATE_0);
+       DUMP_REG(SOR_STATE_1);
+       DUMP_REG(SOR_HEAD_STATE_0(0));
+       DUMP_REG(SOR_HEAD_STATE_0(1));
+       DUMP_REG(SOR_HEAD_STATE_1(0));
+       DUMP_REG(SOR_HEAD_STATE_1(1));
+       DUMP_REG(SOR_HEAD_STATE_2(0));
+       DUMP_REG(SOR_HEAD_STATE_2(1));
+       DUMP_REG(SOR_HEAD_STATE_3(0));
+       DUMP_REG(SOR_HEAD_STATE_3(1));
+       DUMP_REG(SOR_HEAD_STATE_4(0));
+       DUMP_REG(SOR_HEAD_STATE_4(1));
+       DUMP_REG(SOR_HEAD_STATE_5(0));
+       DUMP_REG(SOR_HEAD_STATE_5(1));
+       DUMP_REG(SOR_CRC_CNTRL);
+       DUMP_REG(SOR_DP_DEBUG_MVID);
+       DUMP_REG(SOR_CLK_CNTRL);
+       DUMP_REG(SOR_CAP);
+       DUMP_REG(SOR_PWR);
+       DUMP_REG(SOR_TEST);
+       DUMP_REG(SOR_PLL_0);
+       DUMP_REG(SOR_PLL_1);
+       DUMP_REG(SOR_PLL_2);
+       DUMP_REG(SOR_PLL_3);
+       DUMP_REG(SOR_CSTM);
+       DUMP_REG(SOR_LVDS);
+       DUMP_REG(SOR_CRC_A);
+       DUMP_REG(SOR_CRC_B);
+       DUMP_REG(SOR_BLANK);
+       DUMP_REG(SOR_SEQ_CTL);
+       DUMP_REG(SOR_LANE_SEQ_CTL);
+       DUMP_REG(SOR_SEQ_INST(0));
+       DUMP_REG(SOR_SEQ_INST(1));
+       DUMP_REG(SOR_SEQ_INST(2));
+       DUMP_REG(SOR_SEQ_INST(3));
+       DUMP_REG(SOR_SEQ_INST(4));
+       DUMP_REG(SOR_SEQ_INST(5));
+       DUMP_REG(SOR_SEQ_INST(6));
+       DUMP_REG(SOR_SEQ_INST(7));
+       DUMP_REG(SOR_SEQ_INST(8));
+       DUMP_REG(SOR_SEQ_INST(9));
+       DUMP_REG(SOR_SEQ_INST(10));
+       DUMP_REG(SOR_SEQ_INST(11));
+       DUMP_REG(SOR_SEQ_INST(12));
+       DUMP_REG(SOR_SEQ_INST(13));
+       DUMP_REG(SOR_SEQ_INST(14));
+       DUMP_REG(SOR_SEQ_INST(15));
+       DUMP_REG(SOR_PWM_DIV);
+       DUMP_REG(SOR_PWM_CTL);
+       DUMP_REG(SOR_VCRC_A_0);
+       DUMP_REG(SOR_VCRC_A_1);
+       DUMP_REG(SOR_VCRC_B_0);
+       DUMP_REG(SOR_VCRC_B_1);
+       DUMP_REG(SOR_CCRC_A_0);
+       DUMP_REG(SOR_CCRC_A_1);
+       DUMP_REG(SOR_CCRC_B_0);
+       DUMP_REG(SOR_CCRC_B_1);
+       DUMP_REG(SOR_EDATA_A_0);
+       DUMP_REG(SOR_EDATA_A_1);
+       DUMP_REG(SOR_EDATA_B_0);
+       DUMP_REG(SOR_EDATA_B_1);
+       DUMP_REG(SOR_COUNT_A_0);
+       DUMP_REG(SOR_COUNT_A_1);
+       DUMP_REG(SOR_COUNT_B_0);
+       DUMP_REG(SOR_COUNT_B_1);
+       DUMP_REG(SOR_DEBUG_A_0);
+       DUMP_REG(SOR_DEBUG_A_1);
+       DUMP_REG(SOR_DEBUG_B_0);
+       DUMP_REG(SOR_DEBUG_B_1);
+       DUMP_REG(SOR_TRIG);
+       DUMP_REG(SOR_MSCHECK);
+       DUMP_REG(SOR_XBAR_CTRL);
+       DUMP_REG(SOR_XBAR_POL);
+       DUMP_REG(SOR_DP_LINKCTL_0);
+       DUMP_REG(SOR_DP_LINKCTL_1);
+       DUMP_REG(SOR_LANE_DRIVE_CURRENT_0);
+       DUMP_REG(SOR_LANE_DRIVE_CURRENT_1);
+       DUMP_REG(SOR_LANE4_DRIVE_CURRENT_0);
+       DUMP_REG(SOR_LANE4_DRIVE_CURRENT_1);
+       DUMP_REG(SOR_LANE_PREEMPHASIS_0);
+       DUMP_REG(SOR_LANE_PREEMPHASIS_1);
+       DUMP_REG(SOR_LANE4_PREEMPHASIS_0);
+       DUMP_REG(SOR_LANE4_PREEMPHASIS_1);
+       DUMP_REG(SOR_LANE_POST_CURSOR_0);
+       DUMP_REG(SOR_LANE_POST_CURSOR_1);
+       DUMP_REG(SOR_DP_CONFIG_0);
+       DUMP_REG(SOR_DP_CONFIG_1);
+       DUMP_REG(SOR_DP_MN_0);
+       DUMP_REG(SOR_DP_MN_1);
+       DUMP_REG(SOR_DP_PADCTL_0);
+       DUMP_REG(SOR_DP_PADCTL_1);
+       DUMP_REG(SOR_DP_DEBUG_0);
+       DUMP_REG(SOR_DP_DEBUG_1);
+       DUMP_REG(SOR_DP_SPARE_0);
+       DUMP_REG(SOR_DP_SPARE_1);
+       DUMP_REG(SOR_DP_AUDIO_CTRL);
+       DUMP_REG(SOR_DP_AUDIO_HBLANK_SYMBOLS);
+       DUMP_REG(SOR_DP_AUDIO_VBLANK_SYMBOLS);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_HEADER);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_0);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_1);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_2);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_3);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_4);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_5);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_6);
+       DUMP_REG(SOR_DP_TPG);
+       DUMP_REG(SOR_DP_TPG_CONFIG);
+       DUMP_REG(SOR_DP_LQ_CSTM_0);
+       DUMP_REG(SOR_DP_LQ_CSTM_1);
+       DUMP_REG(SOR_DP_LQ_CSTM_2);
+
+#undef DUMP_REG
+
+       return 0;
+}
+
+static const struct drm_info_list debugfs_files[] = {
+       { "regs", tegra_sor_show_regs, 0, NULL },
+};
+
 static int tegra_sor_debugfs_init(struct tegra_sor *sor,
                                  struct drm_minor *minor)
 {
        struct dentry *entry;
+       unsigned int i;
        int err = 0;
 
        sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root);
        if (!sor->debugfs)
                return -ENOMEM;
 
+       sor->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
+                                    GFP_KERNEL);
+       if (!sor->debugfs_files) {
+               err = -ENOMEM;
+               goto remove;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
+               sor->debugfs_files[i].data = sor;
+
+       err = drm_debugfs_create_files(sor->debugfs_files,
+                                      ARRAY_SIZE(debugfs_files),
+                                      sor->debugfs, minor);
+       if (err < 0)
+               goto free;
+
        entry = debugfs_create_file("crc", 0644, sor->debugfs, sor,
                                    &tegra_sor_crc_fops);
        if (!entry) {
-               dev_err(sor->dev,
-                       "cannot create /sys/kernel/debug/dri/%s/sor/crc\n",
-                       minor->debugfs_root->d_name.name);
                err = -ENOMEM;
-               goto remove;
+               goto free;
        }
 
        return err;
 
+free:
+       kfree(sor->debugfs_files);
+       sor->debugfs_files = NULL;
 remove:
-       debugfs_remove(sor->debugfs);
+       debugfs_remove_recursive(sor->debugfs);
        sor->debugfs = NULL;
        return err;
 }
 
 static void tegra_sor_debugfs_exit(struct tegra_sor *sor)
 {
-       debugfs_remove_recursive(sor->debugfs);
+       drm_debugfs_remove_files(sor->debugfs_files, ARRAY_SIZE(debugfs_files),
+                                sor->minor);
+       sor->minor = NULL;
+
+       kfree(sor->debugfs_files);
        sor->debugfs = NULL;
+
+       debugfs_remove_recursive(sor->debugfs);
+       sor->debugfs_files = NULL;
 }
 
 static void tegra_sor_connector_dpms(struct drm_connector *connector, int mode)
@@ -791,8 +949,8 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
        struct tegra_sor_config config;
        struct drm_dp_link link;
        struct drm_dp_aux *aux;
-       unsigned long value;
        int err = 0;
+       u32 value;
 
        mutex_lock(&sor->lock);
 
@@ -1354,12 +1512,30 @@ static int tegra_sor_init(struct host1x_client *client)
                }
        }
 
+       /*
+        * XXX: Remove this reset once proper hand-over from firmware to
+        * kernel is possible.
+        */
+       err = reset_control_assert(sor->rst);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to assert SOR reset: %d\n", err);
+               return err;
+       }
+
        err = clk_prepare_enable(sor->clk);
        if (err < 0) {
                dev_err(sor->dev, "failed to enable clock: %d\n", err);
                return err;
        }
 
+       usleep_range(1000, 3000);
+
+       err = reset_control_deassert(sor->rst);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to deassert SOR reset: %d\n", err);
+               return err;
+       }
+
        err = clk_prepare_enable(sor->clk_safe);
        if (err < 0)
                return err;
index d395b0bef73b0ce8afffa1d40fb9ea47022ac7fd..8d9b7de2561339b03e2b191e45454eadfd454668 100644 (file)
@@ -74,7 +74,7 @@ static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type)
        pr_err("    has_type: %d\n", man->has_type);
        pr_err("    use_type: %d\n", man->use_type);
        pr_err("    flags: 0x%08X\n", man->flags);
-       pr_err("    gpu_offset: 0x%08lX\n", man->gpu_offset);
+       pr_err("    gpu_offset: 0x%08llX\n", man->gpu_offset);
        pr_err("    size: %llu\n", man->size);
        pr_err("    available_caching: 0x%08X\n", man->available_caching);
        pr_err("    default_caching: 0x%08X\n", man->default_caching);
diff --git a/drivers/gpu/drm/vgem/Makefile b/drivers/gpu/drm/vgem/Makefile
new file mode 100644 (file)
index 0000000..1055cb7
--- /dev/null
@@ -0,0 +1,4 @@
+ccflags-y := -Iinclude/drm
+vgem-y := vgem_drv.o vgem_dma_buf.o
+
+obj-$(CONFIG_DRM_VGEM) += vgem.o
diff --git a/drivers/gpu/drm/vgem/vgem_dma_buf.c b/drivers/gpu/drm/vgem/vgem_dma_buf.c
new file mode 100644 (file)
index 0000000..0254438
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright Â© 2012 Intel Corporation
+ * Copyright Â© 2014 The Chromium OS Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#include <linux/dma-buf.h>
+#include "vgem_drv.h"
+
+struct sg_table *vgem_gem_prime_get_sg_table(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       BUG_ON(obj->pages == NULL);
+
+       return drm_prime_pages_to_sg(obj->pages, obj->base.size / PAGE_SIZE);
+}
+
+int vgem_gem_prime_pin(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       return vgem_gem_get_pages(obj);
+}
+
+void vgem_gem_prime_unpin(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       vgem_gem_put_pages(obj);
+}
+
+void *vgem_gem_prime_vmap(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       BUG_ON(obj->pages == NULL);
+
+       return vmap(obj->pages, obj->base.size / PAGE_SIZE, 0, PAGE_KERNEL);
+}
+
+void vgem_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+       vunmap(vaddr);
+}
+
+struct drm_gem_object *vgem_gem_prime_import(struct drm_device *dev,
+                                            struct dma_buf *dma_buf)
+{
+       struct drm_vgem_gem_object *obj = NULL;
+       int ret;
+
+       obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+       if (obj == NULL) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = drm_gem_object_init(dev, &obj->base, dma_buf->size);
+       if (ret) {
+               ret = -ENOMEM;
+               goto fail_free;
+       }
+
+       get_dma_buf(dma_buf);
+
+       obj->base.dma_buf = dma_buf;
+       obj->use_dma_buf = true;
+
+       return &obj->base;
+
+fail_free:
+       kfree(obj);
+fail:
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
new file mode 100644 (file)
index 0000000..cb3b435
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ * Copyright Â© 2014 The Chromium OS Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software")
+ * to deal in the software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * them Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Adam Jackson <ajax@redhat.com>
+ *     Ben Widawsky <ben@bwidawsk.net>
+ */
+
+/**
+ * This is vgem, a (non-hardware-backed) GEM service.  This is used by Mesa's
+ * software renderer and the X server for efficient buffer sharing.
+ */
+
+#include <linux/module.h>
+#include <linux/ramfs.h>
+#include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
+#include "vgem_drv.h"
+
+#define DRIVER_NAME    "vgem"
+#define DRIVER_DESC    "Virtual GEM provider"
+#define DRIVER_DATE    "20120112"
+#define DRIVER_MAJOR   1
+#define DRIVER_MINOR   0
+
+void vgem_gem_put_pages(struct drm_vgem_gem_object *obj)
+{
+       drm_gem_put_pages(&obj->base, obj->pages, false, false);
+       obj->pages = NULL;
+}
+
+static void vgem_gem_free_object(struct drm_gem_object *obj)
+{
+       struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj);
+
+       drm_gem_free_mmap_offset(obj);
+
+       if (vgem_obj->use_dma_buf && obj->dma_buf) {
+               dma_buf_put(obj->dma_buf);
+               obj->dma_buf = NULL;
+       }
+
+       drm_gem_object_release(obj);
+
+       if (vgem_obj->pages)
+               vgem_gem_put_pages(vgem_obj);
+
+       vgem_obj->pages = NULL;
+
+       kfree(vgem_obj);
+}
+
+int vgem_gem_get_pages(struct drm_vgem_gem_object *obj)
+{
+       struct page **pages;
+
+       if (obj->pages || obj->use_dma_buf)
+               return 0;
+
+       pages = drm_gem_get_pages(&obj->base);
+       if (IS_ERR(pages)) {
+               return PTR_ERR(pages);
+       }
+
+       obj->pages = pages;
+
+       return 0;
+}
+
+static int vgem_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct drm_vgem_gem_object *obj = vma->vm_private_data;
+       struct drm_device *dev = obj->base.dev;
+       loff_t num_pages;
+       pgoff_t page_offset;
+       int ret;
+
+       /* We don't use vmf->pgoff since that has the fake offset */
+       page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >>
+               PAGE_SHIFT;
+
+       num_pages = DIV_ROUND_UP(obj->base.size, PAGE_SIZE);
+
+       if (page_offset > num_pages)
+               return VM_FAULT_SIGBUS;
+
+       mutex_lock(&dev->struct_mutex);
+
+       ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address,
+                            obj->pages[page_offset]);
+
+       mutex_unlock(&dev->struct_mutex);
+       switch (ret) {
+       case 0:
+               return VM_FAULT_NOPAGE;
+       case -ENOMEM:
+               return VM_FAULT_OOM;
+       case -EBUSY:
+               return VM_FAULT_RETRY;
+       case -EFAULT:
+       case -EINVAL:
+               return VM_FAULT_SIGBUS;
+       default:
+               WARN_ON(1);
+               return VM_FAULT_SIGBUS;
+       }
+}
+
+static struct vm_operations_struct vgem_gem_vm_ops = {
+       .fault = vgem_gem_fault,
+       .open = drm_gem_vm_open,
+       .close = drm_gem_vm_close,
+};
+
+/* ioctls */
+
+static struct drm_gem_object *vgem_gem_create(struct drm_device *dev,
+                                             struct drm_file *file,
+                                             unsigned int *handle,
+                                             unsigned long size)
+{
+       struct drm_vgem_gem_object *obj;
+       struct drm_gem_object *gem_object;
+       int err;
+
+       size = roundup(size, PAGE_SIZE);
+
+       obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+       if (!obj)
+               return ERR_PTR(-ENOMEM);
+
+       gem_object = &obj->base;
+
+       err = drm_gem_object_init(dev, gem_object, size);
+       if (err)
+               goto out;
+
+       err = drm_gem_handle_create(file, gem_object, handle);
+       if (err)
+               goto handle_out;
+
+       drm_gem_object_unreference_unlocked(gem_object);
+
+       return gem_object;
+
+handle_out:
+       drm_gem_object_release(gem_object);
+out:
+       kfree(obj);
+       return ERR_PTR(err);
+}
+
+static int vgem_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
+                               struct drm_mode_create_dumb *args)
+{
+       struct drm_gem_object *gem_object;
+       uint64_t size;
+       uint64_t pitch = args->width * DIV_ROUND_UP(args->bpp, 8);
+
+       size = args->height * pitch;
+       if (size == 0)
+               return -EINVAL;
+
+       gem_object = vgem_gem_create(dev, file, &args->handle, size);
+
+       if (IS_ERR(gem_object)) {
+               DRM_DEBUG_DRIVER("object creation failed\n");
+               return PTR_ERR(gem_object);
+       }
+
+       args->size = gem_object->size;
+       args->pitch = pitch;
+
+       DRM_DEBUG_DRIVER("Created object of size %lld\n", size);
+
+       return 0;
+}
+
+int vgem_gem_dumb_map(struct drm_file *file, struct drm_device *dev,
+                     uint32_t handle, uint64_t *offset)
+{
+       int ret = 0;
+       struct drm_gem_object *obj;
+
+       mutex_lock(&dev->struct_mutex);
+       obj = drm_gem_object_lookup(dev, file, handle);
+       if (!obj) {
+               ret = -ENOENT;
+               goto unlock;
+       }
+
+       if (!drm_vma_node_has_offset(&obj->vma_node)) {
+               ret = drm_gem_create_mmap_offset(obj);
+               if (ret)
+                       goto unref;
+       }
+
+       BUG_ON(!obj->filp);
+
+       obj->filp->private_data = obj;
+
+       ret = vgem_gem_get_pages(to_vgem_bo(obj));
+       if (ret)
+               goto fail_get_pages;
+
+       *offset = drm_vma_node_offset_addr(&obj->vma_node);
+
+       goto unref;
+
+fail_get_pages:
+       drm_gem_free_mmap_offset(obj);
+unref:
+       drm_gem_object_unreference(obj);
+unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+int vgem_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_file *priv = filp->private_data;
+       struct drm_device *dev = priv->minor->dev;
+       struct drm_vma_offset_node *node;
+       struct drm_gem_object *obj;
+       struct drm_vgem_gem_object *vgem_obj;
+       int ret = 0;
+
+       mutex_lock(&dev->struct_mutex);
+
+       node = drm_vma_offset_exact_lookup(dev->vma_offset_manager,
+                                          vma->vm_pgoff,
+                                          vma_pages(vma));
+       if (!node) {
+               ret = -EINVAL;
+               goto out_unlock;
+       } else if (!drm_vma_node_is_allowed(node, filp)) {
+               ret = -EACCES;
+               goto out_unlock;
+       }
+
+       obj = container_of(node, struct drm_gem_object, vma_node);
+
+       vgem_obj = to_vgem_bo(obj);
+
+       if (obj->dma_buf && vgem_obj->use_dma_buf) {
+               ret = dma_buf_mmap(obj->dma_buf, vma, 0);
+               goto out_unlock;
+       }
+
+       if (!obj->dev->driver->gem_vm_ops) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
+       vma->vm_ops = obj->dev->driver->gem_vm_ops;
+       vma->vm_private_data = vgem_obj;
+       vma->vm_page_prot =
+               pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+
+       mutex_unlock(&dev->struct_mutex);
+       drm_gem_vm_open(vma);
+       return ret;
+
+out_unlock:
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
+}
+
+
+static struct drm_ioctl_desc vgem_ioctls[] = {
+};
+
+static const struct file_operations vgem_driver_fops = {
+       .owner          = THIS_MODULE,
+       .open           = drm_open,
+       .mmap           = vgem_drm_gem_mmap,
+       .poll           = drm_poll,
+       .read           = drm_read,
+       .unlocked_ioctl = drm_ioctl,
+       .release        = drm_release,
+};
+
+static struct drm_driver vgem_driver = {
+       .driver_features                = DRIVER_GEM | DRIVER_PRIME,
+       .gem_free_object                = vgem_gem_free_object,
+       .gem_vm_ops                     = &vgem_gem_vm_ops,
+       .ioctls                         = vgem_ioctls,
+       .fops                           = &vgem_driver_fops,
+       .dumb_create                    = vgem_gem_dumb_create,
+       .dumb_map_offset                = vgem_gem_dumb_map,
+       .prime_handle_to_fd             = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle             = drm_gem_prime_fd_to_handle,
+       .gem_prime_export               = drm_gem_prime_export,
+       .gem_prime_import               = vgem_gem_prime_import,
+       .gem_prime_pin                  = vgem_gem_prime_pin,
+       .gem_prime_unpin                = vgem_gem_prime_unpin,
+       .gem_prime_get_sg_table         = vgem_gem_prime_get_sg_table,
+       .gem_prime_vmap                 = vgem_gem_prime_vmap,
+       .gem_prime_vunmap               = vgem_gem_prime_vunmap,
+       .name   = DRIVER_NAME,
+       .desc   = DRIVER_DESC,
+       .date   = DRIVER_DATE,
+       .major  = DRIVER_MAJOR,
+       .minor  = DRIVER_MINOR,
+};
+
+struct drm_device *vgem_device;
+
+static int __init vgem_init(void)
+{
+       int ret;
+
+       vgem_device = drm_dev_alloc(&vgem_driver, NULL);
+       if (!vgem_device) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret  = drm_dev_register(vgem_device, 0);
+
+       if (ret)
+               goto out_unref;
+
+       return 0;
+
+out_unref:
+       drm_dev_unref(vgem_device);
+out:
+       return ret;
+}
+
+static void __exit vgem_exit(void)
+{
+       drm_dev_unregister(vgem_device);
+       drm_dev_unref(vgem_device);
+}
+
+module_init(vgem_init);
+module_exit(vgem_exit);
+
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/vgem/vgem_drv.h b/drivers/gpu/drm/vgem/vgem_drv.h
new file mode 100644 (file)
index 0000000..57ab4d8
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright Â© 2012 Intel Corporation
+ * Copyright Â© 2014 The Chromium OS Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#ifndef _VGEM_DRV_H_
+#define _VGEM_DRV_H_
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+
+#define to_vgem_bo(x) container_of(x, struct drm_vgem_gem_object, base)
+struct drm_vgem_gem_object {
+       struct drm_gem_object base;
+       struct page **pages;
+       bool use_dma_buf;
+};
+
+/* vgem_drv.c */
+extern void vgem_gem_put_pages(struct drm_vgem_gem_object *obj);
+extern int vgem_gem_get_pages(struct drm_vgem_gem_object *obj);
+
+/* vgem_dma_buf.c */
+extern struct sg_table *vgem_gem_prime_get_sg_table(
+                       struct drm_gem_object *gobj);
+extern int vgem_gem_prime_pin(struct drm_gem_object *gobj);
+extern void vgem_gem_prime_unpin(struct drm_gem_object *gobj);
+extern void *vgem_gem_prime_vmap(struct drm_gem_object *gobj);
+extern void vgem_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+extern struct drm_gem_object *vgem_gem_prime_import(struct drm_device *dev,
+                                                   struct dma_buf *dma_buf);
+
+
+#endif
index 6c6b655defcf4eac679913e70896810208dfd6ce..620bb5cf617c9689a9113e989d585346f420de3d 100644 (file)
  */
 
 #define VMW_IOCTL_DEF(ioctl, func, flags) \
-  [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_##ioctl, flags, func, DRM_IOCTL_##ioctl}
+  [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_IOCTL_##ioctl, flags, func}
 
 /**
  * Ioctl definitions.
@@ -725,32 +725,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                goto out_err1;
        }
 
-       ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM,
-                            (dev_priv->vram_size >> PAGE_SHIFT));
-       if (unlikely(ret != 0)) {
-               DRM_ERROR("Failed initializing memory manager for VRAM.\n");
-               goto out_err2;
-       }
-
-       dev_priv->has_gmr = true;
-       if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) ||
-           refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
-                                        VMW_PL_GMR) != 0) {
-               DRM_INFO("No GMR memory available. "
-                        "Graphics memory resources are very limited.\n");
-               dev_priv->has_gmr = false;
-       }
-
-       if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
-               dev_priv->has_mob = true;
-               if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB,
-                                  VMW_PL_MOB) != 0) {
-                       DRM_INFO("No MOB memory available. "
-                                "3D will be disabled.\n");
-                       dev_priv->has_mob = false;
-               }
-       }
-
        dev_priv->mmio_mtrr = arch_phys_wc_add(dev_priv->mmio_start,
                                               dev_priv->mmio_size);
 
@@ -813,6 +787,33 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                goto out_no_fman;
        }
 
+
+       ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM,
+                            (dev_priv->vram_size >> PAGE_SHIFT));
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Failed initializing memory manager for VRAM.\n");
+               goto out_no_vram;
+       }
+
+       dev_priv->has_gmr = true;
+       if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) ||
+           refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
+                                        VMW_PL_GMR) != 0) {
+               DRM_INFO("No GMR memory available. "
+                        "Graphics memory resources are very limited.\n");
+               dev_priv->has_gmr = false;
+       }
+
+       if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
+               dev_priv->has_mob = true;
+               if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB,
+                                  VMW_PL_MOB) != 0) {
+                       DRM_INFO("No MOB memory available. "
+                                "3D will be disabled.\n");
+                       dev_priv->has_mob = false;
+               }
+       }
+
        vmw_kms_save_vga(dev_priv);
 
        /* Start kms and overlay systems, needs fifo. */
@@ -838,6 +839,12 @@ out_no_fifo:
        vmw_kms_close(dev_priv);
 out_no_kms:
        vmw_kms_restore_vga(dev_priv);
+       if (dev_priv->has_mob)
+               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
+       if (dev_priv->has_gmr)
+               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
+       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
+out_no_vram:
        vmw_fence_manager_takedown(dev_priv->fman);
 out_no_fman:
        if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
@@ -853,12 +860,6 @@ out_err4:
        iounmap(dev_priv->mmio_virt);
 out_err3:
        arch_phys_wc_del(dev_priv->mmio_mtrr);
-       if (dev_priv->has_mob)
-               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
-       if (dev_priv->has_gmr)
-               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
-       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
-out_err2:
        (void)ttm_bo_device_release(&dev_priv->bdev);
 out_err1:
        vmw_ttm_global_release(dev_priv);
@@ -887,6 +888,13 @@ static int vmw_driver_unload(struct drm_device *dev)
        }
        vmw_kms_close(dev_priv);
        vmw_overlay_close(dev_priv);
+
+       if (dev_priv->has_mob)
+               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
+       if (dev_priv->has_gmr)
+               (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
+       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
+
        vmw_fence_manager_takedown(dev_priv->fman);
        if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
                drm_irq_uninstall(dev_priv->dev);
@@ -898,11 +906,6 @@ static int vmw_driver_unload(struct drm_device *dev)
        ttm_object_device_release(&dev_priv->tdev);
        iounmap(dev_priv->mmio_virt);
        arch_phys_wc_del(dev_priv->mmio_mtrr);
-       if (dev_priv->has_mob)
-               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
-       if (dev_priv->has_gmr)
-               (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
-       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
        (void)ttm_bo_device_release(&dev_priv->bdev);
        vmw_ttm_global_release(dev_priv);
 
@@ -1041,7 +1044,7 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
                const struct drm_ioctl_desc *ioctl =
                        &vmw_ioctls[nr - DRM_COMMAND_BASE];
 
-               if (unlikely(ioctl->cmd_drv != cmd)) {
+               if (unlikely(ioctl->cmd != cmd)) {
                        DRM_ERROR("Invalid command format, ioctl %d\n",
                                  nr - DRM_COMMAND_BASE);
                        return -EINVAL;
@@ -1235,6 +1238,7 @@ static void vmw_remove(struct pci_dev *pdev)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
 
+       pci_disable_device(pdev);
        drm_put_dev(dev);
 }
 
index 33176d05db3542903f1c919b59f68cad2da22044..654c8daeb5ab3d0dd84a2ed1d32af633d6955ac9 100644 (file)
@@ -890,7 +890,8 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
        ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not find or use MOB buffer.\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_no_reloc;
        }
        bo = &vmw_bo->base;
 
@@ -914,7 +915,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
 
 out_no_reloc:
        vmw_dmabuf_unreference(&vmw_bo);
-       vmw_bo_p = NULL;
+       *vmw_bo_p = NULL;
        return ret;
 }
 
@@ -951,7 +952,8 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
        ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not find or use GMR region.\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_no_reloc;
        }
        bo = &vmw_bo->base;
 
@@ -974,7 +976,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
 
 out_no_reloc:
        vmw_dmabuf_unreference(&vmw_bo);
-       vmw_bo_p = NULL;
+       *vmw_bo_p = NULL;
        return ret;
 }
 
@@ -2780,13 +2782,11 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
                                  NULL, arg->command_size, arg->throttle_us,
                                  (void __user *)(unsigned long)arg->fence_rep,
                                  NULL);
-
+       ttm_read_unlock(&dev_priv->reservation_sem);
        if (unlikely(ret != 0))
-               goto out_unlock;
+               return ret;
 
        vmw_kms_cursor_post_execbuf(dev_priv);
 
-out_unlock:
-       ttm_read_unlock(&dev_priv->reservation_sem);
-       return ret;
+       return 0;
 }
index 8725b79e7847d68239a25413c482883e44024704..07cda8cbbddbcb5e6f56127c57dac0e683541fb9 100644 (file)
@@ -2033,23 +2033,17 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
        int i;
        struct drm_mode_config *mode_config = &dev->mode_config;
 
-       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
-       if (unlikely(ret != 0))
-               return ret;
-
        if (!arg->num_outputs) {
                struct drm_vmw_rect def_rect = {0, 0, 800, 600};
                vmw_du_update_layout(dev_priv, 1, &def_rect);
-               goto out_unlock;
+               return 0;
        }
 
        rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect);
        rects = kcalloc(arg->num_outputs, sizeof(struct drm_vmw_rect),
                        GFP_KERNEL);
-       if (unlikely(!rects)) {
-               ret = -ENOMEM;
-               goto out_unlock;
-       }
+       if (unlikely(!rects))
+               return -ENOMEM;
 
        user_rects = (void __user *)(unsigned long)arg->rects;
        ret = copy_from_user(rects, user_rects, rects_size);
@@ -2074,7 +2068,5 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
 
 out_free:
        kfree(rects);
-out_unlock:
-       ttm_read_unlock(&dev_priv->reservation_sem);
        return ret;
 }
index b10550ee1d8958366b208f3e1927426663e8b91f..6b7fdc1e2ed078c337c8fa235633fcc105c4ccde 100644 (file)
@@ -425,6 +425,12 @@ u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
 }
 EXPORT_SYMBOL(host1x_syncpt_read_min);
 
+u32 host1x_syncpt_read(struct host1x_syncpt *sp)
+{
+       return host1x_syncpt_load(sp);
+}
+EXPORT_SYMBOL(host1x_syncpt_read);
+
 int host1x_syncpt_nb_pts(struct host1x *host)
 {
        return host->info->nb_pts;
index b61d6be97602222d3ae51b39d939d00cf8f5731b..3ddfb3d0b64d266cb95345ccb68c1a991521cc1d 100644 (file)
@@ -459,6 +459,8 @@ static void ipu_di_config_clock(struct ipu_di *di,
 
                clkrate = clk_get_rate(di->clk_ipu);
                div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
+               if (div == 0)
+                       div = 1;
                rate = clkrate / div;
 
                error = rate / (sig->mode.pixelclock / 1000);
index db4fb6e1cc5b3ca83d14d3f1e0e52e66fe75979a..56ce8c2b5530db20d851b585fa0c4f88ef81afa6 100644 (file)
@@ -1872,6 +1872,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
@@ -1926,6 +1927,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 #endif
 #if IS_ENABLED(CONFIG_HID_SAITEK)
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
@@ -1957,6 +1959,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_PRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
index 46edb4d3ed28efc61582811ea6b5fdeac2a2808a..9c4786759f16f4f397a839214600524b9826254c 100644 (file)
 #define USB_VENDOR_ID_LOGITECH         0x046d
 #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
 #define USB_DEVICE_ID_LOGITECH_T651    0xb00c
+#define USB_DEVICE_ID_LOGITECH_C077    0xc007
 #define USB_DEVICE_ID_LOGITECH_RECEIVER        0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
 #define USB_DEVICE_ID_MS_LK6K          0x00f9
 #define USB_DEVICE_ID_MS_PRESENTER_8K_BT       0x0701
 #define USB_DEVICE_ID_MS_PRESENTER_8K_USB      0x0713
+#define USB_DEVICE_ID_MS_NE7K          0x071d
 #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K      0x0730
 #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500    0x076c
 #define USB_DEVICE_ID_MS_SURFACE_PRO_2   0x0799
 #define USB_VENDOR_ID_SAITEK           0x06a3
 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
 #define USB_DEVICE_ID_SAITEK_PS1000    0x0621
+#define USB_DEVICE_ID_SAITEK_RAT7_OLD  0x0ccb
 #define USB_DEVICE_ID_SAITEK_RAT7      0x0cd7
 #define USB_DEVICE_ID_SAITEK_MMO7      0x0cd0
 
 #define USB_VENDOR_ID_TIVO             0x150a
 #define USB_DEVICE_ID_TIVO_SLIDE_BT    0x1200
 #define USB_DEVICE_ID_TIVO_SLIDE       0x1201
+#define USB_DEVICE_ID_TIVO_SLIDE_PRO   0x1203
 
 #define USB_VENDOR_ID_TOPSEED          0x0766
 #define USB_DEVICE_ID_TOPSEED_CYBERLINK        0x0204
index fbaea6eb882e21afb6cba576279834a099780434..af935eb198c93549867c4e50bb48a997e5cd3f2b 100644 (file)
@@ -264,6 +264,8 @@ static const struct hid_device_id ms_devices[] = {
                .driver_data = MS_ERGONOMY },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
                .driver_data = MS_ERGONOMY },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K),
+               .driver_data = MS_ERGONOMY },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
                .driver_data = MS_ERGONOMY | MS_RDESC },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
index 5632c54eadf0206faee31afefc99235763c37e14..a014f21275d8bfada33701b4bef5013f3b81eb2a 100644 (file)
@@ -177,6 +177,8 @@ static int saitek_event(struct hid_device *hdev, struct hid_field *field,
 static const struct hid_device_id saitek_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
                .driver_data = SAITEK_FIX_PS1000 },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD),
+               .driver_data = SAITEK_RELEASE_MODE_RAT7 },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
                .driver_data = SAITEK_RELEASE_MODE_RAT7 },
        { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9),
index 6a58b6c723aa215408051e2b3c967205569a7b94..e54ce1097e2cc57f5049cf852016087a32534c47 100644 (file)
@@ -135,8 +135,9 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
 {
        struct hid_sensor_hub_callbacks_list *callback;
        struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+       unsigned long flags;
 
-       spin_lock(&pdata->dyn_callback_lock);
+       spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
        list_for_each_entry(callback, &pdata->dyn_callback_list, list)
                if (callback->usage_id == usage_id &&
                        (collection_index >=
@@ -145,10 +146,11 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
                                callback->hsdev->end_collection_index)) {
                        *priv = callback->priv;
                        *hsdev = callback->hsdev;
-                       spin_unlock(&pdata->dyn_callback_lock);
+                       spin_unlock_irqrestore(&pdata->dyn_callback_lock,
+                                              flags);
                        return callback->usage_callback;
                }
-       spin_unlock(&pdata->dyn_callback_lock);
+       spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
 
        return NULL;
 }
index 31e9d25611064d0500eba47ea0b710beac31bb0b..1896c019e302934aa13c6f9ac434c51637f450ce 100644 (file)
@@ -804,7 +804,7 @@ union sixaxis_output_report_01 {
 #define DS4_REPORT_0x81_SIZE 7
 #define SIXAXIS_REPORT_0xF2_SIZE 18
 
-static spinlock_t sony_dev_list_lock;
+static DEFINE_SPINLOCK(sony_dev_list_lock);
 static LIST_HEAD(sony_device_list);
 static DEFINE_IDA(sony_device_id_allocator);
 
@@ -1944,6 +1944,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                return -ENOMEM;
        }
 
+       spin_lock_init(&sc->lock);
+
        sc->quirks = quirks;
        hid_set_drvdata(hdev, sc);
        sc->hdev = hdev;
@@ -2147,8 +2149,8 @@ static void __exit sony_exit(void)
 {
        dbg_hid("Sony:%s\n", __func__);
 
-       ida_destroy(&sony_device_id_allocator);
        hid_unregister_driver(&sony_driver);
+       ida_destroy(&sony_device_id_allocator);
 }
 module_init(sony_init);
 module_exit(sony_exit);
index d790d8d71f7fc6829f405b7665cc37f0af1bf5a8..d9869692745399b0406dc62b66c1269295ee9835 100644 (file)
@@ -64,6 +64,7 @@ static const struct hid_device_id tivo_devices[] = {
        /* TiVo Slide Bluetooth remote, pairs with a Broadcom dongle */
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_PRO) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, tivo_devices);
index d43e967e75339ec7972e734e284c4356e31a4e38..36053f33d6d93e97009b0d6ba3f4aa5416be8fea 100644 (file)
@@ -370,7 +370,10 @@ static int i2c_hid_hwreset(struct i2c_client *client)
 static void i2c_hid_get_input(struct i2c_hid *ihid)
 {
        int ret, ret_size;
-       int size = ihid->bufsize;
+       int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
+
+       if (size > ihid->bufsize)
+               size = ihid->bufsize;
 
        ret = i2c_master_recv(ihid->client, ihid->inbuf, size);
        if (ret != size) {
@@ -785,7 +788,7 @@ static int i2c_hid_init_irq(struct i2c_client *client)
        dev_dbg(&client->dev, "Requesting IRQ: %d\n", client->irq);
 
        ret = request_threaded_irq(client->irq, NULL, i2c_hid_irq,
-                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                       IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                        client->name, ihid);
        if (ret < 0) {
                dev_warn(&client->dev,
index 9be99a67bfe2ec9f042e765904913628f8c2b654..a821277534611708973ccf080ad78f4136ef0df5 100644 (file)
@@ -78,6 +78,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS },
index 1a6507999a6534f0b851e209bb702696d1f50e58..bbe32d66e5000157b4d3670c23350ff3fa1a0104 100644 (file)
@@ -551,9 +551,13 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
           (features->type == CINTIQ && !(data[1] & 0x40)))
                return 1;
 
-       if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
+       if (wacom->shared) {
                wacom->shared->stylus_in_proximity = true;
 
+               if (wacom->shared->touch_down)
+                       return 1;
+       }
+
        /* in Range while exiting */
        if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) {
                input_report_key(input, BTN_TOUCH, 0);
@@ -778,6 +782,11 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                        input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
                        input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
                        input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
+                       if ((data[2] & 0x07) | data[4] | data[5] | data[6] | data[7] | data[8] | data[9]) {
+                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+                       } else {
+                               input_report_abs(input, ABS_MISC, 0);
+                       }
                } else if (features->type == CINTIQ_HYBRID) {
                        /*
                         * Do not send hardware buttons under Android. They
@@ -1038,27 +1047,28 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
        struct input_dev *input = wacom->input;
        unsigned char *data = wacom->data;
        int i;
-       int current_num_contacts = 0;
+       int current_num_contacts = data[61];
        int contacts_to_send = 0;
        int num_contacts_left = 4; /* maximum contacts per packet */
        int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
        int y_offset = 2;
+       static int contact_with_no_pen_down_count = 0;
 
        if (wacom->features.type == WACOM_27QHDT) {
                current_num_contacts = data[63];
                num_contacts_left = 10;
                byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET;
                y_offset = 0;
-       } else {
-               current_num_contacts = data[61];
        }
 
        /*
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts)
+       if (current_num_contacts) {
                wacom->num_contacts_left = current_num_contacts;
+               contact_with_no_pen_down_count = 0;
+       }
 
        contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
 
@@ -1091,15 +1101,16 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
                                input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
                                input_report_abs(input, ABS_MT_ORIENTATION, w > h);
                        }
+                       contact_with_no_pen_down_count++;
                }
        }
        input_mt_report_pointer_emulation(input, true);
 
        wacom->num_contacts_left -= contacts_to_send;
-       if (wacom->num_contacts_left <= 0)
+       if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-
-       wacom->shared->touch_down = (wacom->num_contacts_left > 0);
+               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       }
        return 1;
 }
 
@@ -1111,6 +1122,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
        int current_num_contacts = data[2];
        int contacts_to_send = 0;
        int x_offset = 0;
+       static int contact_with_no_pen_down_count = 0;
 
        /* MTTPC does not support Height and Width */
        if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
@@ -1120,8 +1132,10 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts)
+       if (current_num_contacts) {
                wacom->num_contacts_left = current_num_contacts;
+               contact_with_no_pen_down_count = 0;
+       }
 
        /* There are at most 5 contacts per packet */
        contacts_to_send = min(5, wacom->num_contacts_left);
@@ -1142,15 +1156,16 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
                        int y = get_unaligned_le16(&data[offset + x_offset + 9]);
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       contact_with_no_pen_down_count++;
                }
        }
        input_mt_report_pointer_emulation(input, true);
 
        wacom->num_contacts_left -= contacts_to_send;
-       if (wacom->num_contacts_left < 0)
+       if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-
-       wacom->shared->touch_down = (wacom->num_contacts_left > 0);
+               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       }
        return 1;
 }
 
@@ -1188,29 +1203,25 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
 {
        unsigned char *data = wacom->data;
        struct input_dev *input = wacom->input;
-       bool prox;
+       bool prox = !wacom->shared->stylus_in_proximity;
        int x = 0, y = 0;
 
        if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
                return 0;
 
-       if (!wacom->shared->stylus_in_proximity) {
-               if (len == WACOM_PKGLEN_TPC1FG) {
-                       prox = data[0] & 0x01;
-                       x = get_unaligned_le16(&data[1]);
-                       y = get_unaligned_le16(&data[3]);
-               } else if (len == WACOM_PKGLEN_TPC1FG_B) {
-                       prox = data[2] & 0x01;
-                       x = get_unaligned_le16(&data[3]);
-                       y = get_unaligned_le16(&data[5]);
-               } else {
-                       prox = data[1] & 0x01;
-                       x = le16_to_cpup((__le16 *)&data[2]);
-                       y = le16_to_cpup((__le16 *)&data[4]);
-               }
-       } else
-               /* force touch out when pen is in prox */
-               prox = 0;
+       if (len == WACOM_PKGLEN_TPC1FG) {
+               prox = prox && (data[0] & 0x01);
+               x = get_unaligned_le16(&data[1]);
+               y = get_unaligned_le16(&data[3]);
+       } else if (len == WACOM_PKGLEN_TPC1FG_B) {
+               prox = prox && (data[2] & 0x01);
+               x = get_unaligned_le16(&data[3]);
+               y = get_unaligned_le16(&data[5]);
+       } else {
+               prox = prox && (data[1] & 0x01);
+               x = le16_to_cpup((__le16 *)&data[2]);
+               y = le16_to_cpup((__le16 *)&data[4]);
+       }
 
        if (prox) {
                input_report_abs(input, ABS_X, x);
@@ -1608,6 +1619,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
        struct input_dev *pad_input = wacom->pad_input;
        unsigned char *data = wacom->data;
        int i;
+       int contact_with_no_pen_down_count = 0;
 
        if (data[0] != 0x02)
            return 0;
@@ -1635,6 +1647,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
                        }
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       contact_with_no_pen_down_count++;
                }
        }
 
@@ -1644,11 +1657,12 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
        input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
        input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
        input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
+       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
        return 1;
 }
 
-static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
+static int wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data, int last_touch_count)
 {
        struct wacom_features *features = &wacom->features;
        struct input_dev *input = wacom->input;
@@ -1656,7 +1670,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
        int slot = input_mt_get_slot_by_key(input, data[0]);
 
        if (slot < 0)
-               return;
+               return 0;
 
        touch = touch && !wacom->shared->stylus_in_proximity;
 
@@ -1688,7 +1702,9 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
                input_report_abs(input, ABS_MT_POSITION_Y, y);
                input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
                input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
+               last_touch_count++;
        }
+       return last_touch_count;
 }
 
 static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
@@ -1713,6 +1729,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
        unsigned char *data = wacom->data;
        int count = data[1] & 0x07;
        int i;
+       int contact_with_no_pen_down_count = 0;
 
        if (data[0] != 0x02)
            return 0;
@@ -1723,12 +1740,15 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
                int msg_id = data[offset];
 
                if (msg_id >= 2 && msg_id <= 17)
-                       wacom_bpt3_touch_msg(wacom, data + offset);
+                       contact_with_no_pen_down_count = 
+                           wacom_bpt3_touch_msg(wacom, data + offset,
+                                                contact_with_no_pen_down_count);
                else if (msg_id == 128)
                        wacom_bpt3_button_msg(wacom, data + offset);
 
        }
        input_mt_report_pointer_emulation(input, true);
+       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
        return 1;
 }
@@ -1754,6 +1774,9 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
                return 0;
        }
 
+       if (wacom->shared->touch_down)
+               return 0;
+
        prox = (data[1] & 0x20) == 0x20;
 
        /*
@@ -2725,9 +2748,9 @@ static const struct wacom_features wacom_features_0xF6 =
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x32A =
-       { "Wacom Cintiq 27QHD", 119740, 67520, 2047,
-         63, WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
-         WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Cintiq 27QHD", 119740, 67520, 2047, 63,
+         WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
 static const struct wacom_features wacom_features_0x32B =
        { "Wacom Cintiq 27QHD touch", 119740, 67520, 2047, 63,
          WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
index bce4e9ff21bff76606484f0a04ad1bf52b1ffee2..6c99ee7bafa3fdf47d6479b7198697ec835a23e8 100644 (file)
@@ -147,6 +147,9 @@ static int ads7828_probe(struct i2c_client *client,
                                                    &ads2830_regmap_config);
        }
 
+       if (IS_ERR(data->regmap))
+               return PTR_ERR(data->regmap);
+
        data->cmd_byte = ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
        if (!diff_input)
                data->cmd_byte |= ADS7828_CMD_SD_SE;
index 5f1ff4cc5c34036ea6284adf9d00fce0ef1fabae..7d7ae97476e2c4cec01765e700e0748bece538bc 100644 (file)
 #include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
+
 #include <asm/iosf_mbi.h>
+
 #include "i2c-designware-core.h"
 
 #define SEMAPHORE_TIMEOUT      100
 #define PUNIT_SEMAPHORE                0x7
+#define PUNIT_SEMAPHORE_BIT    BIT(0)
+#define PUNIT_SEMAPHORE_ACQUIRE        BIT(1)
 
 static unsigned long acquired;
 
 static int get_sem(struct device *dev, u32 *sem)
 {
-       u32 reg_val;
+       u32 data;
        int ret;
 
        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE,
-                           &reg_val);
+                               &data);
        if (ret) {
                dev_err(dev, "iosf failed to read punit semaphore\n");
                return ret;
        }
 
-       *sem = reg_val & 0x1;
+       *sem = data & PUNIT_SEMAPHORE_BIT;
 
        return 0;
 }
@@ -52,27 +56,29 @@ static void reset_semaphore(struct device *dev)
                return;
        }
 
-       data = data & 0xfffffffe;
+       data &= ~PUNIT_SEMAPHORE_BIT;
        if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
-                                PUNIT_SEMAPHORE, data))
+                               PUNIT_SEMAPHORE, data))
                dev_err(dev, "iosf failed to reset punit semaphore during write\n");
 }
 
-int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
+static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
 {
-       u32 sem = 0;
+       u32 sem;
        int ret;
        unsigned long start, end;
 
+       might_sleep();
+
        if (!dev || !dev->dev)
                return -ENODEV;
 
-       if (!dev->acquire_lock)
+       if (!dev->release_lock)
                return 0;
 
-       /* host driver writes 0x2 to side band semaphore register */
+       /* host driver writes to side band semaphore register */
        ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
-                                PUNIT_SEMAPHORE, 0x2);
+                               PUNIT_SEMAPHORE, PUNIT_SEMAPHORE_ACQUIRE);
        if (ret) {
                dev_err(dev->dev, "iosf punit semaphore request failed\n");
                return ret;
@@ -81,7 +87,7 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
        /* host driver waits for bit 0 to be set in semaphore register */
        start = jiffies;
        end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
-       while (!time_after(jiffies, end)) {
+       do {
                ret = get_sem(dev->dev, &sem);
                if (!ret && sem) {
                        acquired = jiffies;
@@ -91,14 +97,14 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
                }
 
                usleep_range(1000, 2000);
-       }
+       } while (time_before(jiffies, end));
 
        dev_err(dev->dev, "punit semaphore timed out, resetting\n");
        reset_semaphore(dev->dev);
 
        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
-               PUNIT_SEMAPHORE, &sem);
-       if (!ret)
+                               PUNIT_SEMAPHORE, &sem);
+       if (ret)
                dev_err(dev->dev, "iosf failed to read punit semaphore\n");
        else
                dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
@@ -107,9 +113,8 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
 
        return -ETIMEDOUT;
 }
-EXPORT_SYMBOL(baytrail_i2c_acquire);
 
-void baytrail_i2c_release(struct dw_i2c_dev *dev)
+static void baytrail_i2c_release(struct dw_i2c_dev *dev)
 {
        if (!dev || !dev->dev)
                return;
@@ -121,7 +126,6 @@ void baytrail_i2c_release(struct dw_i2c_dev *dev)
        dev_dbg(dev->dev, "punit semaphore held for %ums\n",
                jiffies_to_msecs(jiffies - acquired));
 }
-EXPORT_SYMBOL(baytrail_i2c_release);
 
 int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
 {
@@ -137,7 +141,6 @@ int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
                return 0;
 
        status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
-
        if (ACPI_FAILURE(status))
                return 0;
 
@@ -153,7 +156,6 @@ int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
 
        return 0;
 }
-EXPORT_SYMBOL(i2c_dw_eval_lock_support);
 
 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
 MODULE_DESCRIPTION("Baytrail I2C Semaphore driver");
index 210cf4874cb7ea2415df5fb3e1d30ec8065de5d4..edf274cabe817208f0c4b3fceb98bca95f2671f4 100644 (file)
@@ -679,9 +679,6 @@ static int i2c_device_remove(struct device *dev)
                status = driver->remove(client);
        }
 
-       if (dev->of_node)
-               irq_dispose_mapping(client->irq);
-
        dev_pm_domain_detach(&client->dev, true);
        return status;
 }
index 1793aea4a7d2c58192f6023d43e90c10daedbb52..6eb738ca6d2f353717aac1e63bade383f763afa5 100644 (file)
@@ -1793,11 +1793,11 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
        tape->best_dsc_rw_freq = clamp_t(unsigned long, t, IDETAPE_DSC_RW_MIN,
                                         IDETAPE_DSC_RW_MAX);
        printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
-               "%lums tDSC%s\n",
+               "%ums tDSC%s\n",
                drive->name, tape->name, *(u16 *)&tape->caps[14],
                (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size,
                tape->buffer_size / 1024,
-               tape->best_dsc_rw_freq * 1000 / HZ,
+               jiffies_to_msecs(tape->best_dsc_rw_freq),
                (drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : "");
 
        ide_proc_register_driver(drive, tape->driver);
index 51672256072bc8db2778e6c60982f320c680f3d4..b96c636470ef504e3b7f3d5612602bcc76a3a3a0 100644 (file)
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
        }
 
-/* LSB is in nV to eliminate floating point */
-static const u32 rates_to_lsb[] = {1000000, 250000, 62500, 15625};
-
-/*
- *  scales calculated as:
- *  rates_to_lsb[sample_rate] / (1 << pga);
- *  pga is 1 for 0, 2
- */
-
 static const int mcp3422_scales[4][4] = {
-       { 1000000, 250000, 62500, 15625 },
-       { 500000 , 125000, 31250, 7812 },
-       { 250000 , 62500 , 15625, 3906 },
-       { 125000 , 31250 , 7812 , 1953 } };
+       { 1000000, 500000, 250000, 125000 },
+       { 250000 , 125000, 62500 , 31250  },
+       { 62500  , 31250 , 15625 , 7812   },
+       { 15625  , 7812  , 3906  , 1953   } };
 
 /* Constant msleep times for data acquisitions */
 static const int mcp3422_read_times[4] = {
index b9666f2f5e514f8d3a66a0a192b190bcbd2a44d5..fabd24edc2a1d07534d2a67e9a1c8e78ef353cae 100644 (file)
@@ -296,7 +296,8 @@ static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data)
        if (iadc->poll_eoc) {
                ret = iadc_poll_wait_eoc(iadc, wait);
        } else {
-               ret = wait_for_completion_timeout(&iadc->complete, wait);
+               ret = wait_for_completion_timeout(&iadc->complete,
+                       usecs_to_jiffies(wait));
                if (!ret)
                        ret = -ETIMEDOUT;
                else
index 52d70435f5a11c55ed186003c70bce311002f918..55a90082a29bd4846aaea896f8c7f847d96fcb45 100644 (file)
@@ -640,6 +640,7 @@ static int ssp_remove(struct spi_device *spi)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int ssp_suspend(struct device *dev)
 {
        int ret;
@@ -688,6 +689,7 @@ static int ssp_resume(struct device *dev)
 
        return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static const struct dev_pm_ops ssp_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume)
index f57562aa396f44462a9fdc822741d09bf37531f4..15c73e20272d874655e544366e2a8d6f1c24912a 100644 (file)
@@ -322,7 +322,7 @@ static int ad5686_probe(struct spi_device *spi)
        st = iio_priv(indio_dev);
        spi_set_drvdata(spi, indio_dev);
 
-       st->reg = devm_regulator_get(&spi->dev, "vcc");
+       st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
        if (!IS_ERR(st->reg)) {
                ret = regulator_enable(st->reg);
                if (ret)
index 623c145d8a97241bd0c2e284d9bb273dfcfb72da..7d79a1ac5f5f09ba332fee3ebb94c486280ce024 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/wait.h>
 #include <linux/bitops.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 
 #define DHT11_DATA_VALID_TIME  2000000000  /* 2s in ns */
 
-#define DHT11_EDGES_PREAMBLE 4
+#define DHT11_EDGES_PREAMBLE 2
 #define DHT11_BITS_PER_READ 40
+/*
+ * Note that when reading the sensor actually 84 edges are detected, but
+ * since the last edge is not significant, we only store 83:
+ */
 #define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1)
 
 /* Data transmission timing (nano seconds) */
@@ -57,6 +62,7 @@ struct dht11 {
        int                             irq;
 
        struct completion               completion;
+       struct mutex                    lock;
 
        s64                             timestamp;
        int                             temperature;
@@ -88,7 +94,7 @@ static int dht11_decode(struct dht11 *dht11, int offset)
        unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
 
        /* Calculate timestamp resolution */
-       for (i = 0; i < dht11->num_edges; ++i) {
+       for (i = 1; i < dht11->num_edges; ++i) {
                t = dht11->edges[i].ts - dht11->edges[i-1].ts;
                if (t > 0 && t < timeres)
                        timeres = t;
@@ -138,6 +144,27 @@ static int dht11_decode(struct dht11 *dht11, int offset)
        return 0;
 }
 
+/*
+ * IRQ handler called on GPIO edges
+ */
+static irqreturn_t dht11_handle_irq(int irq, void *data)
+{
+       struct iio_dev *iio = data;
+       struct dht11 *dht11 = iio_priv(iio);
+
+       /* TODO: Consider making the handler safe for IRQ sharing */
+       if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
+               dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
+               dht11->edges[dht11->num_edges++].value =
+                                               gpio_get_value(dht11->gpio);
+
+               if (dht11->num_edges >= DHT11_EDGES_PER_READ)
+                       complete(&dht11->completion);
+       }
+
+       return IRQ_HANDLED;
+}
+
 static int dht11_read_raw(struct iio_dev *iio_dev,
                        const struct iio_chan_spec *chan,
                        int *val, int *val2, long m)
@@ -145,6 +172,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
        struct dht11 *dht11 = iio_priv(iio_dev);
        int ret;
 
+       mutex_lock(&dht11->lock);
        if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) {
                reinit_completion(&dht11->completion);
 
@@ -157,8 +185,17 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
                if (ret)
                        goto err;
 
+               ret = request_irq(dht11->irq, dht11_handle_irq,
+                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                                 iio_dev->name, iio_dev);
+               if (ret)
+                       goto err;
+
                ret = wait_for_completion_killable_timeout(&dht11->completion,
                                                                 HZ);
+
+               free_irq(dht11->irq, iio_dev);
+
                if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {
                        dev_err(&iio_dev->dev,
                                        "Only %d signal edges detected\n",
@@ -185,6 +222,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
                ret = -EINVAL;
 err:
        dht11->num_edges = -1;
+       mutex_unlock(&dht11->lock);
        return ret;
 }
 
@@ -193,27 +231,6 @@ static const struct iio_info dht11_iio_info = {
        .read_raw               = dht11_read_raw,
 };
 
-/*
- * IRQ handler called on GPIO edges
-*/
-static irqreturn_t dht11_handle_irq(int irq, void *data)
-{
-       struct iio_dev *iio = data;
-       struct dht11 *dht11 = iio_priv(iio);
-
-       /* TODO: Consider making the handler safe for IRQ sharing */
-       if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
-               dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
-               dht11->edges[dht11->num_edges++].value =
-                                               gpio_get_value(dht11->gpio);
-
-               if (dht11->num_edges >= DHT11_EDGES_PER_READ)
-                       complete(&dht11->completion);
-       }
-
-       return IRQ_HANDLED;
-}
-
 static const struct iio_chan_spec dht11_chan_spec[] = {
        { .type = IIO_TEMP,
                .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), },
@@ -256,11 +273,6 @@ static int dht11_probe(struct platform_device *pdev)
                dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio);
                return -EINVAL;
        }
-       ret = devm_request_irq(dev, dht11->irq, dht11_handle_irq,
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                               pdev->name, iio);
-       if (ret)
-               return ret;
 
        dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1;
        dht11->num_edges = -1;
@@ -268,6 +280,7 @@ static int dht11_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, iio);
 
        init_completion(&dht11->completion);
+       mutex_init(&dht11->lock);
        iio->name = pdev->name;
        iio->dev.parent = &pdev->dev;
        iio->info = &dht11_iio_info;
index b54164677b898d5c9e5b4b9983fe61271f3c80b5..fa3b809aff5efd425ce96031aec1c066b644feb2 100644 (file)
@@ -45,12 +45,12 @@ static int si7020_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan, int *val,
                           int *val2, long mask)
 {
-       struct i2c_client *client = iio_priv(indio_dev);
+       struct i2c_client **client = iio_priv(indio_dev);
        int ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               ret = i2c_smbus_read_word_data(client,
+               ret = i2c_smbus_read_word_data(*client,
                                               chan->type == IIO_TEMP ?
                                               SI7020CMD_TEMP_HOLD :
                                               SI7020CMD_RH_HOLD);
@@ -126,7 +126,7 @@ static int si7020_probe(struct i2c_client *client,
        /* Wait the maximum power-up time after software reset. */
        msleep(15);
 
-       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*client));
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
        if (!indio_dev)
                return -ENOMEM;
 
index b70873de04ea50a7cb73f34835f15c43ceff9eb1..fa795dcd5f75ec0a1e8de143bc0122ef36bf9409 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/debugfs.h>
+#include <linux/bitops.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -414,7 +415,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
                mutex_unlock(&indio_dev->mlock);
                if (ret)
                        return ret;
-               val16 = ((val16 & 0xFFF) << 4) >> 4;
+               val16 = sign_extend32(val16, 11);
                *val = val16;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_OFFSET:
index f73e60b7a79611b8825bfe90ea3ba5a5e1b253b1..d8d5bed65e072cae577968edb78e2e592c2a5bfa 100644 (file)
@@ -780,7 +780,11 @@ static int inv_mpu_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, indio_dev);
        indio_dev->dev.parent = &client->dev;
-       indio_dev->name = id->name;
+       /* id will be NULL when enumerated via ACPI */
+       if (id)
+               indio_dev->name = (char *)id->name;
+       else
+               indio_dev->name = (char *)dev_name(&client->dev);
        indio_dev->channels = inv_mpu_channels;
        indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
 
index ae68c64bdad3ef7480d15da5d1187c1fd4f7ba4f..a224afd6380c84eff7c76996c7c38eb621493140 100644 (file)
@@ -73,6 +73,7 @@ config CM36651
 config GP2AP020A00F
        tristate "Sharp GP2AP020A00F Proximity/ALS sensor"
        depends on I2C
+       select REGMAP_I2C
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        select IRQ_WORK
@@ -126,6 +127,7 @@ config HID_SENSOR_PROX
 config JSA1212
        tristate "JSA1212 ALS and proximity sensor driver"
        depends on I2C
+       select REGMAP_I2C
        help
         Say Y here if you want to build a IIO driver for JSA1212
         proximity & ALS sensor device.
index 4c7a4c52dd06bf7be91a6a1b1d9d56ff7984650c..a5d6de72c523bab274f003cc8431ce05b29630c7 100644 (file)
@@ -18,6 +18,8 @@ config AK8975
 
 config AK09911
        tristate "Asahi Kasei AK09911 3-axis Compass"
+       depends on I2C
+       depends on GPIOLIB
        select AK8975
        help
          Deprecated: AK09911 is now supported by AK8975 driver.
index c7619716c31dd92cb5ddad4f77d98528392698b5..59040265e3614a23fc8508e88dd5b2138e7107e8 100644 (file)
@@ -64,6 +64,14 @@ enum {
 #define GUID_TBL_BLK_NUM_ENTRIES 8
 #define GUID_TBL_BLK_SIZE (GUID_TBL_ENTRY_SIZE * GUID_TBL_BLK_NUM_ENTRIES)
 
+/* Counters should be saturate once they reach their maximum value */
+#define ASSIGN_32BIT_COUNTER(counter, value) do {\
+       if ((value) > U32_MAX)                   \
+               counter = cpu_to_be32(U32_MAX); \
+       else                                     \
+               counter = cpu_to_be32(value);    \
+} while (0)
+
 struct mlx4_mad_rcv_buf {
        struct ib_grh grh;
        u8 payload[256];
@@ -806,10 +814,14 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
 static void edit_counter(struct mlx4_counter *cnt,
                                        struct ib_pma_portcounters *pma_cnt)
 {
-       pma_cnt->port_xmit_data = cpu_to_be32((be64_to_cpu(cnt->tx_bytes)>>2));
-       pma_cnt->port_rcv_data  = cpu_to_be32((be64_to_cpu(cnt->rx_bytes)>>2));
-       pma_cnt->port_xmit_packets = cpu_to_be32(be64_to_cpu(cnt->tx_frames));
-       pma_cnt->port_rcv_packets  = cpu_to_be32(be64_to_cpu(cnt->rx_frames));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data,
+                            (be64_to_cpu(cnt->tx_bytes) >> 2));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data,
+                            (be64_to_cpu(cnt->rx_bytes) >> 2));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets,
+                            be64_to_cpu(cnt->tx_frames));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets,
+                            be64_to_cpu(cnt->rx_frames));
 }
 
 static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
index ac6e2b710ea6fef928271869f0e170f2bbdb158d..b972c0b41799b51e2f554c1abc703d78e0c4636e 100644 (file)
@@ -2697,8 +2697,12 @@ static void handle_bonded_port_state_event(struct work_struct *work)
        spin_lock_bh(&ibdev->iboe.lock);
        for (i = 0; i < MLX4_MAX_PORTS; ++i) {
                struct net_device *curr_netdev = ibdev->iboe.netdevs[i];
+               enum ib_port_state curr_port_state;
 
-               enum ib_port_state curr_port_state =
+               if (!curr_netdev)
+                       continue;
+
+               curr_port_state =
                        (netif_running(curr_netdev) &&
                         netif_carrier_ok(curr_netdev)) ?
                        IB_PORT_ACTIVE : IB_PORT_DOWN;
index 8ff612d160b07ec61b7084d668f04468ee116b36..563932500ff1bbfbf83c84c06b4f64205450045b 100644 (file)
@@ -411,9 +411,9 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
 
        input_set_drvdata(input, keypad);
 
-       error = request_threaded_irq(irq, NULL,
-                       tc3589x_keypad_irq, plat->irqtype,
-                       "tc3589x-keypad", keypad);
+       error = request_threaded_irq(irq, NULL, tc3589x_keypad_irq,
+                                    plat->irqtype | IRQF_ONESHOT,
+                                    "tc3589x-keypad", keypad);
        if (error < 0) {
                dev_err(&pdev->dev,
                                "Could not allocate irq %d,error %d\n",
index 59d4dcddf6de0cf4d1c5384c977a36c319d66389..98228773a1118bfd448ec0143c4b572a534af499 100644 (file)
@@ -187,6 +187,7 @@ static int mma8450_probe(struct i2c_client *c,
        idev->private           = m;
        idev->input->name       = MMA8450_DRV_NAME;
        idev->input->id.bustype = BUS_I2C;
+       idev->input->dev.parent = &c->dev;
        idev->poll              = mma8450_poll;
        idev->poll_interval     = POLL_INTERVAL;
        idev->poll_interval_max = POLL_INTERVAL_MAX;
index d28726a0ef858e252948d2e5f2fd009bfd6c5506..1bd15ebc01f2df5002eca38f7089a61701471f5d 100644 (file)
@@ -2605,8 +2605,10 @@ int alps_detect(struct psmouse *psmouse, bool set_properties)
                return -ENOMEM;
 
        error = alps_identify(psmouse, priv);
-       if (error)
+       if (error) {
+               kfree(priv);
                return error;
+       }
 
        if (set_properties) {
                psmouse->vendor = "ALPS";
index 77e9d70a986bc049ecc48650bff28d34d97443d8..1e2291c378feb8856b319dc5c2e6492360de1ada 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/input/mt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 #include "cyapa.h"
 
 
index ddf5393a118098fc87337d34e3808c0cfc28ce95..5b611dd71e790660fa1492dab505499222390d02 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/completion.h>
 #include <linux/slab.h>
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 #include <linux/crc-itu-t.h>
 #include "cyapa.h"
 
@@ -1926,7 +1926,7 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa,
                                electrodes_tx = cyapa->electrodes_x;
                        max_element_cnt = ((cyapa->aligned_electrodes_rx + 7) &
                                                ~7u) * electrodes_tx;
-               } else if (idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
+               } else {
                        offset = 2;
                        max_element_cnt = cyapa->electrodes_x +
                                                cyapa->electrodes_y;
index 757f78a94aeccb1be6b80819f75752a09e705bf6..23d259416f2f4d90d40a04271e98e6f8acca3966 100644 (file)
@@ -67,9 +67,6 @@ static void focaltech_reset(struct psmouse *psmouse)
 
 #define FOC_MAX_FINGERS 5
 
-#define FOC_MAX_X 2431
-#define FOC_MAX_Y 1663
-
 /*
  * Current state of a single finger on the touchpad.
  */
@@ -129,9 +126,17 @@ static void focaltech_report_state(struct psmouse *psmouse)
                input_mt_slot(dev, i);
                input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
                if (active) {
-                       input_report_abs(dev, ABS_MT_POSITION_X, finger->x);
+                       unsigned int clamped_x, clamped_y;
+                       /*
+                        * The touchpad might report invalid data, so we clamp
+                        * the resulting values so that we do not confuse
+                        * userspace.
+                        */
+                       clamped_x = clamp(finger->x, 0U, priv->x_max);
+                       clamped_y = clamp(finger->y, 0U, priv->y_max);
+                       input_report_abs(dev, ABS_MT_POSITION_X, clamped_x);
                        input_report_abs(dev, ABS_MT_POSITION_Y,
-                                        FOC_MAX_Y - finger->y);
+                                        priv->y_max - clamped_y);
                }
        }
        input_mt_report_pointer_emulation(dev, true);
@@ -180,16 +185,6 @@ static void focaltech_process_abs_packet(struct psmouse *psmouse,
 
        state->pressed = (packet[0] >> 4) & 1;
 
-       /*
-        * packet[5] contains some kind of tool size in the most
-        * significant nibble. 0xff is a special value (latching) that
-        * signals a large contact area.
-        */
-       if (packet[5] == 0xff) {
-               state->fingers[finger].valid = false;
-               return;
-       }
-
        state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2];
        state->fingers[finger].y = (packet[3] << 8) | packet[4];
        state->fingers[finger].valid = true;
@@ -381,6 +376,23 @@ static int focaltech_read_size(struct psmouse *psmouse)
 
        return 0;
 }
+
+void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+       /* not supported yet */
+}
+
+static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate)
+{
+       /* not supported yet */
+}
+
+static void focaltech_set_scale(struct psmouse *psmouse,
+                               enum psmouse_scale scale)
+{
+       /* not supported yet */
+}
+
 int focaltech_init(struct psmouse *psmouse)
 {
        struct focaltech_data *priv;
@@ -415,6 +427,14 @@ int focaltech_init(struct psmouse *psmouse)
        psmouse->cleanup = focaltech_reset;
        /* resync is not supported yet */
        psmouse->resync_time = 0;
+       /*
+        * rate/resolution/scale changes are not supported yet, and
+        * the generic implementations of these functions seem to
+        * confuse some touchpads
+        */
+       psmouse->set_resolution = focaltech_set_resolution;
+       psmouse->set_rate = focaltech_set_rate;
+       psmouse->set_scale = focaltech_set_scale;
 
        return 0;
 
index 4ccd01d7a48de9639a637db4a757c2c09c6c6836..8bc61237bc1b1c95d43b0d7e3d11e90275aa8d4a 100644 (file)
@@ -453,6 +453,17 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
        psmouse->rate = r;
 }
 
+/*
+ * Here we set the mouse scaling.
+ */
+
+static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale)
+{
+       ps2_command(&psmouse->ps2dev, NULL,
+                   scale == PSMOUSE_SCALE21 ? PSMOUSE_CMD_SETSCALE21 :
+                                              PSMOUSE_CMD_SETSCALE11);
+}
+
 /*
  * psmouse_poll() - default poll handler. Everyone except for ALPS uses it.
  */
@@ -689,6 +700,7 @@ static void psmouse_apply_defaults(struct psmouse *psmouse)
 
        psmouse->set_rate = psmouse_set_rate;
        psmouse->set_resolution = psmouse_set_resolution;
+       psmouse->set_scale = psmouse_set_scale;
        psmouse->poll = psmouse_poll;
        psmouse->protocol_handler = psmouse_process_byte;
        psmouse->pktsize = 3;
@@ -1160,7 +1172,7 @@ static void psmouse_initialize(struct psmouse *psmouse)
        if (psmouse_max_proto != PSMOUSE_PS2) {
                psmouse->set_rate(psmouse, psmouse->rate);
                psmouse->set_resolution(psmouse, psmouse->resolution);
-               ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+               psmouse->set_scale(psmouse, PSMOUSE_SCALE11);
        }
 }
 
index c2ff137ecbdb636ba75da72fe14c61a73ec59a5e..d02e1bdc9ae4934d56e5290f8adedcb3a2297566 100644 (file)
@@ -36,6 +36,11 @@ typedef enum {
        PSMOUSE_FULL_PACKET
 } psmouse_ret_t;
 
+enum psmouse_scale {
+       PSMOUSE_SCALE11,
+       PSMOUSE_SCALE21
+};
+
 struct psmouse {
        void *private;
        struct input_dev *dev;
@@ -67,6 +72,7 @@ struct psmouse {
        psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse);
        void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
        void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution);
+       void (*set_scale)(struct psmouse *psmouse, enum psmouse_scale scale);
 
        int (*reconnect)(struct psmouse *psmouse);
        void (*disconnect)(struct psmouse *psmouse);
index f2cceb6493a0aea304c838043735ac3889041438..dda605836546847afbdbdd4c77c976134a914a2e 100644 (file)
@@ -67,9 +67,6 @@
 #define X_MAX_POSITIVE 8176
 #define Y_MAX_POSITIVE 8176
 
-/* maximum ABS_MT_POSITION displacement (in mm) */
-#define DMAX 10
-
 /*****************************************************************************
  *     Stuff we need even when we do not want native Synaptics support
  ****************************************************************************/
@@ -123,32 +120,41 @@ void synaptics_reset(struct psmouse *psmouse)
 
 static bool cr48_profile_sensor;
 
+#define ANY_BOARD_ID 0
 struct min_max_quirk {
        const char * const *pnp_ids;
+       struct {
+               unsigned long int min, max;
+       } board_id;
        int x_min, x_max, y_min, y_max;
 };
 
 static const struct min_max_quirk min_max_pnpid_table[] = {
        {
                (const char * const []){"LEN0033", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1024, 5052, 2258, 4832
        },
        {
-               (const char * const []){"LEN0035", "LEN0042", NULL},
+               (const char * const []){"LEN0042", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1232, 5710, 1156, 4696
        },
        {
                (const char * const []){"LEN0034", "LEN0036", "LEN0037",
                                        "LEN0039", "LEN2002", "LEN2004",
                                        NULL},
+               {ANY_BOARD_ID, 2961},
                1024, 5112, 2024, 4832
        },
        {
                (const char * const []){"LEN2001", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1024, 5022, 2508, 4832
        },
        {
                (const char * const []){"LEN2006", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1264, 5675, 1171, 4688
        },
        { }
@@ -175,9 +181,7 @@ static const char * const topbuttonpad_pnp_ids[] = {
        "LEN0041",
        "LEN0042", /* Yoga */
        "LEN0045",
-       "LEN0046",
        "LEN0047",
-       "LEN0048",
        "LEN0049",
        "LEN2000",
        "LEN2001", /* Edge E431 */
@@ -235,18 +239,39 @@ static int synaptics_model_id(struct psmouse *psmouse)
        return 0;
 }
 
+static int synaptics_more_extended_queries(struct psmouse *psmouse)
+{
+       struct synaptics_data *priv = psmouse->private;
+       unsigned char buf[3];
+
+       if (synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf))
+               return -1;
+
+       priv->ext_cap_10 = (buf[0]<<16) | (buf[1]<<8) | buf[2];
+
+       return 0;
+}
+
 /*
- * Read the board id from the touchpad
+ * Read the board id and the "More Extended Queries" from the touchpad
  * The board id is encoded in the "QUERY MODES" response
  */
-static int synaptics_board_id(struct psmouse *psmouse)
+static int synaptics_query_modes(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        unsigned char bid[3];
 
+       /* firmwares prior 7.5 have no board_id encoded */
+       if (SYN_ID_FULL(priv->identity) < 0x705)
+               return 0;
+
        if (synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid))
                return -1;
        priv->board_id = ((bid[0] & 0xfc) << 6) | bid[1];
+
+       if (SYN_MEXT_CAP_BIT(bid[0]))
+               return synaptics_more_extended_queries(psmouse);
+
        return 0;
 }
 
@@ -346,7 +371,6 @@ static int synaptics_resolution(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        unsigned char resp[3];
-       int i;
 
        if (SYN_ID_MAJOR(priv->identity) < 4)
                return 0;
@@ -358,17 +382,6 @@ static int synaptics_resolution(struct psmouse *psmouse)
                }
        }
 
-       for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
-               if (psmouse_matches_pnp_id(psmouse,
-                                          min_max_pnpid_table[i].pnp_ids)) {
-                       priv->x_min = min_max_pnpid_table[i].x_min;
-                       priv->x_max = min_max_pnpid_table[i].x_max;
-                       priv->y_min = min_max_pnpid_table[i].y_min;
-                       priv->y_max = min_max_pnpid_table[i].y_max;
-                       return 0;
-               }
-       }
-
        if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
            SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
                if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
@@ -377,23 +390,69 @@ static int synaptics_resolution(struct psmouse *psmouse)
                } else {
                        priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
                        priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
+                       psmouse_info(psmouse,
+                                    "queried max coordinates: x [..%d], y [..%d]\n",
+                                    priv->x_max, priv->y_max);
                }
        }
 
-       if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 &&
-           SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) {
+       if (SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c) &&
+           (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 ||
+            /*
+             * Firmware v8.1 does not report proper number of extended
+             * capabilities, but has been proven to report correct min
+             * coordinates.
+             */
+            SYN_ID_FULL(priv->identity) == 0x801)) {
                if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) {
                        psmouse_warn(psmouse,
                                     "device claims to have min coordinates query, but I'm not able to read it.\n");
                } else {
                        priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
                        priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
+                       psmouse_info(psmouse,
+                                    "queried min coordinates: x [%d..], y [%d..]\n",
+                                    priv->x_min, priv->y_min);
                }
        }
 
        return 0;
 }
 
+/*
+ * Apply quirk(s) if the hardware matches
+ */
+
+static void synaptics_apply_quirks(struct psmouse *psmouse)
+{
+       struct synaptics_data *priv = psmouse->private;
+       int i;
+
+       for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
+               if (!psmouse_matches_pnp_id(psmouse,
+                                           min_max_pnpid_table[i].pnp_ids))
+                       continue;
+
+               if (min_max_pnpid_table[i].board_id.min != ANY_BOARD_ID &&
+                   priv->board_id < min_max_pnpid_table[i].board_id.min)
+                       continue;
+
+               if (min_max_pnpid_table[i].board_id.max != ANY_BOARD_ID &&
+                   priv->board_id > min_max_pnpid_table[i].board_id.max)
+                       continue;
+
+               priv->x_min = min_max_pnpid_table[i].x_min;
+               priv->x_max = min_max_pnpid_table[i].x_max;
+               priv->y_min = min_max_pnpid_table[i].y_min;
+               priv->y_max = min_max_pnpid_table[i].y_max;
+               psmouse_info(psmouse,
+                            "quirked min/max coordinates: x [%d..%d], y [%d..%d]\n",
+                            priv->x_min, priv->x_max,
+                            priv->y_min, priv->y_max);
+               break;
+       }
+}
+
 static int synaptics_query_hardware(struct psmouse *psmouse)
 {
        if (synaptics_identify(psmouse))
@@ -402,13 +461,15 @@ static int synaptics_query_hardware(struct psmouse *psmouse)
                return -1;
        if (synaptics_firmware_id(psmouse))
                return -1;
-       if (synaptics_board_id(psmouse))
+       if (synaptics_query_modes(psmouse))
                return -1;
        if (synaptics_capability(psmouse))
                return -1;
        if (synaptics_resolution(psmouse))
                return -1;
 
+       synaptics_apply_quirks(psmouse);
+
        return 0;
 }
 
@@ -516,18 +577,22 @@ static int synaptics_is_pt_packet(unsigned char *buf)
        return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
 }
 
-static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
+static void synaptics_pass_pt_packet(struct psmouse *psmouse,
+                                    struct serio *ptport,
+                                    unsigned char *packet)
 {
+       struct synaptics_data *priv = psmouse->private;
        struct psmouse *child = serio_get_drvdata(ptport);
 
        if (child && child->state == PSMOUSE_ACTIVATED) {
-               serio_interrupt(ptport, packet[1], 0);
+               serio_interrupt(ptport, packet[1] | priv->pt_buttons, 0);
                serio_interrupt(ptport, packet[4], 0);
                serio_interrupt(ptport, packet[5], 0);
                if (child->pktsize == 4)
                        serio_interrupt(ptport, packet[2], 0);
-       } else
+       } else {
                serio_interrupt(ptport, packet[1], 0);
+       }
 }
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
@@ -605,6 +670,18 @@ static void synaptics_parse_agm(const unsigned char buf[],
        }
 }
 
+static void synaptics_parse_ext_buttons(const unsigned char buf[],
+                                       struct synaptics_data *priv,
+                                       struct synaptics_hw_state *hw)
+{
+       unsigned int ext_bits =
+               (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1;
+       unsigned int ext_mask = GENMASK(ext_bits - 1, 0);
+
+       hw->ext_buttons = buf[4] & ext_mask;
+       hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits;
+}
+
 static bool is_forcepad;
 
 static int synaptics_parse_hw_state(const unsigned char buf[],
@@ -691,28 +768,9 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
                        hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
                }
 
-               if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
+               if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 0 &&
                    ((buf[0] ^ buf[3]) & 0x02)) {
-                       switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
-                       default:
-                               /*
-                                * if nExtBtn is greater than 8 it should be
-                                * considered invalid and treated as 0
-                                */
-                               break;
-                       case 8:
-                               hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
-                       case 6:
-                               hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
-                       case 4:
-                               hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
-                       case 2:
-                               hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
-                       }
+                       synaptics_parse_ext_buttons(buf, priv, hw);
                }
        } else {
                hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
@@ -774,12 +832,54 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev,
        }
 }
 
+static void synaptics_report_ext_buttons(struct psmouse *psmouse,
+                                        const struct synaptics_hw_state *hw)
+{
+       struct input_dev *dev = psmouse->dev;
+       struct synaptics_data *priv = psmouse->private;
+       int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1;
+       char buf[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+       int i;
+
+       if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+               return;
+
+       /* Bug in FW 8.1, buttons are reported only when ExtBit is 1 */
+       if (SYN_ID_FULL(priv->identity) == 0x801 &&
+           !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02))
+               return;
+
+       if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) {
+               for (i = 0; i < ext_bits; i++) {
+                       input_report_key(dev, BTN_0 + 2 * i,
+                               hw->ext_buttons & (1 << i));
+                       input_report_key(dev, BTN_1 + 2 * i,
+                               hw->ext_buttons & (1 << (i + ext_bits)));
+               }
+               return;
+       }
+
+       /*
+        * This generation of touchpads has the trackstick buttons
+        * physically wired to the touchpad. Re-route them through
+        * the pass-through interface.
+        */
+       if (!priv->pt_port)
+               return;
+
+       /* The trackstick expects at most 3 buttons */
+       priv->pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons)      |
+                          SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 |
+                          SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2;
+
+       synaptics_pass_pt_packet(psmouse, priv->pt_port, buf);
+}
+
 static void synaptics_report_buttons(struct psmouse *psmouse,
                                     const struct synaptics_hw_state *hw)
 {
        struct input_dev *dev = psmouse->dev;
        struct synaptics_data *priv = psmouse->private;
-       int i;
 
        input_report_key(dev, BTN_LEFT, hw->left);
        input_report_key(dev, BTN_RIGHT, hw->right);
@@ -792,8 +892,7 @@ static void synaptics_report_buttons(struct psmouse *psmouse,
                input_report_key(dev, BTN_BACK, hw->down);
        }
 
-       for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
-               input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i));
+       synaptics_report_ext_buttons(psmouse, hw);
 }
 
 static void synaptics_report_mt_data(struct psmouse *psmouse,
@@ -813,7 +912,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse,
                pos[i].y = synaptics_invert_y(hw[i]->y);
        }
 
-       input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res);
+       input_mt_assign_slots(dev, slot, pos, nsemi, 0);
 
        for (i = 0; i < nsemi; i++) {
                input_mt_slot(dev, slot[i]);
@@ -1014,7 +1113,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
                if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
                    synaptics_is_pt_packet(psmouse->packet)) {
                        if (priv->pt_port)
-                               synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
+                               synaptics_pass_pt_packet(psmouse, priv->pt_port,
+                                                        psmouse->packet);
                } else
                        synaptics_process_packet(psmouse);
 
@@ -1116,8 +1216,9 @@ static void set_input_params(struct psmouse *psmouse,
                __set_bit(BTN_BACK, dev->keybit);
        }
 
-       for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
-               __set_bit(BTN_0 + i, dev->keybit);
+       if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10))
+               for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
+                       __set_bit(BTN_0 + i, dev->keybit);
 
        __clear_bit(EV_REL, dev->evbit);
        __clear_bit(REL_X, dev->relbit);
@@ -1125,7 +1226,8 @@ static void set_input_params(struct psmouse *psmouse,
 
        if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
                __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
-               if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids))
+               if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
+                   !SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10))
                        __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit);
                /* Clickpads report only left button */
                __clear_bit(BTN_RIGHT, dev->keybit);
index aedc3299b14e2b753c1e9d51da95b0953ea081cb..ee4bd0d12b26fa2770445a381134b62124be6741 100644 (file)
@@ -22,6 +22,7 @@
 #define SYN_QUE_EXT_CAPAB_0C           0x0c
 #define SYN_QUE_EXT_MAX_COORDS         0x0d
 #define SYN_QUE_EXT_MIN_COORDS         0x0f
+#define SYN_QUE_MEXT_CAPAB_10          0x10
 
 /* synatics modes */
 #define SYN_BIT_ABSOLUTE_MODE          (1 << 7)
@@ -53,6 +54,7 @@
 #define SYN_EXT_CAP_REQUESTS(c)                (((c) & 0x700000) >> 20)
 #define SYN_CAP_MULTI_BUTTON_NO(ec)    (((ec) & 0x00f000) >> 12)
 #define SYN_CAP_PRODUCT_ID(ec)         (((ec) & 0xff0000) >> 16)
+#define SYN_MEXT_CAP_BIT(m)            ((m) & (1 << 1))
 
 /*
  * The following describes response for the 0x0c query.
 #define SYN_CAP_REDUCED_FILTERING(ex0c)        ((ex0c) & 0x000400)
 #define SYN_CAP_IMAGE_SENSOR(ex0c)     ((ex0c) & 0x000800)
 
+/*
+ * The following descibes response for the 0x10 query.
+ *
+ * byte        mask    name                    meaning
+ * ----        ----    -------                 ------------
+ * 1   0x01    ext buttons are stick   buttons exported in the extended
+ *                                     capability are actually meant to be used
+ *                                     by the tracktick (pass-through).
+ * 1   0x02    SecurePad               the touchpad is a SecurePad, so it
+ *                                     contains a built-in fingerprint reader.
+ * 1   0xe0    more ext count          how many more extented queries are
+ *                                     available after this one.
+ * 2   0xff    SecurePad width         the width of the SecurePad fingerprint
+ *                                     reader.
+ * 3   0xff    SecurePad height        the height of the SecurePad fingerprint
+ *                                     reader.
+ */
+#define SYN_CAP_EXT_BUTTONS_STICK(ex10)        ((ex10) & 0x010000)
+#define SYN_CAP_SECUREPAD(ex10)                ((ex10) & 0x020000)
+
+#define SYN_CAP_EXT_BUTTON_STICK_L(eb) (!!((eb) & 0x01))
+#define SYN_CAP_EXT_BUTTON_STICK_M(eb) (!!((eb) & 0x02))
+#define SYN_CAP_EXT_BUTTON_STICK_R(eb) (!!((eb) & 0x04))
+
 /* synaptics modes query bits */
 #define SYN_MODE_ABSOLUTE(m)           ((m) & (1 << 7))
 #define SYN_MODE_RATE(m)               ((m) & (1 << 6))
@@ -143,6 +169,7 @@ struct synaptics_data {
        unsigned long int capabilities;         /* Capabilities */
        unsigned long int ext_cap;              /* Extended Capabilities */
        unsigned long int ext_cap_0c;           /* Ext Caps from 0x0c query */
+       unsigned long int ext_cap_10;           /* Ext Caps from 0x10 query */
        unsigned long int identity;             /* Identification */
        unsigned int x_res, y_res;              /* X/Y resolution in units/mm */
        unsigned int x_max, y_max;              /* Max coordinates (from FW) */
@@ -156,6 +183,7 @@ struct synaptics_data {
        bool disable_gesture;                   /* disable gestures */
 
        struct serio *pt_port;                  /* Pass-through serio port */
+       unsigned char pt_buttons;               /* Pass-through buttons */
 
        /*
         * Last received Advanced Gesture Mode (AGM) packet. An AGM packet
index 58917525126e86fd06cb632b2cbb3f558b0a2f83..6261fd6d7c3c4ddcb758b6796b0ba6ca0c222c99 100644 (file)
@@ -943,6 +943,7 @@ config TOUCHSCREEN_SUN4I
        tristate "Allwinner sun4i resistive touchscreen controller support"
        depends on ARCH_SUNXI || COMPILE_TEST
        depends on HWMON
+       depends on THERMAL || !THERMAL_OF
        help
          This selects support for the resistive touchscreen controller
          found on Allwinner sunxi SoCs.
index baa0d9786f506bfeff064459e1f2277cd2506b6b..1ae4e547b419b909a9748b54cc6b973d31ff0221 100644 (file)
@@ -23,6 +23,7 @@ config IOMMU_IO_PGTABLE
 config IOMMU_IO_PGTABLE_LPAE
        bool "ARMv7/v8 Long Descriptor Format"
        select IOMMU_IO_PGTABLE
+       depends on ARM || ARM64 || COMPILE_TEST
        help
          Enable support for the ARM long descriptor pagetable format.
          This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page
@@ -63,6 +64,7 @@ config MSM_IOMMU
        bool "MSM IOMMU Support"
        depends on ARM
        depends on ARCH_MSM8X60 || ARCH_MSM8960 || COMPILE_TEST
+       depends on BROKEN
        select IOMMU_API
        help
          Support for the IOMMUs found on certain Qualcomm SOCs.
index 7ce52737c7a129c825397733041d945cd05761bf..dc14fec4ede123b0af6564f641d81dcfcb958b25 100644 (file)
@@ -1186,8 +1186,15 @@ static const struct iommu_ops exynos_iommu_ops = {
 
 static int __init exynos_iommu_init(void)
 {
+       struct device_node *np;
        int ret;
 
+       np = of_find_matching_node(NULL, sysmmu_of_match);
+       if (!np)
+               return 0;
+
+       of_node_put(np);
+
        lv2table_kmem_cache = kmem_cache_create("exynos-iommu-lv2table",
                                LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL);
        if (!lv2table_kmem_cache) {
index 5a500edf00cc146805d0a346525e0b9169c816c5..b610a8dee23820573b6362472b4ab5ec31c4003f 100644 (file)
@@ -56,7 +56,8 @@
        ((((d)->levels - ((l) - ARM_LPAE_START_LVL(d) + 1))             \
          * (d)->bits_per_level) + (d)->pg_shift)
 
-#define ARM_LPAE_PAGES_PER_PGD(d)      ((d)->pgd_size >> (d)->pg_shift)
+#define ARM_LPAE_PAGES_PER_PGD(d)                                      \
+       DIV_ROUND_UP((d)->pgd_size, 1UL << (d)->pg_shift)
 
 /*
  * Calculate the index at level l used to map virtual address a using the
@@ -66,7 +67,7 @@
        ((l) == ARM_LPAE_START_LVL(d) ? ilog2(ARM_LPAE_PAGES_PER_PGD(d)) : 0)
 
 #define ARM_LPAE_LVL_IDX(a,l,d)                                                \
-       (((a) >> ARM_LPAE_LVL_SHIFT(l,d)) &                             \
+       (((u64)(a) >> ARM_LPAE_LVL_SHIFT(l,d)) &                        \
         ((1 << ((d)->bits_per_level + ARM_LPAE_PGD_IDX(l,d))) - 1))
 
 /* Calculate the block/page mapping size at level l for pagetable in d. */
index f59f857b702e8e3f65080edd43b743a54091170f..a4ba851825c235b5bfa7ab93a8256adfca160ca7 100644 (file)
@@ -1376,6 +1376,13 @@ static int __init omap_iommu_init(void)
        struct kmem_cache *p;
        const unsigned long flags = SLAB_HWCACHE_ALIGN;
        size_t align = 1 << 10; /* L2 pagetable alignement */
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, omap_iommu_of_match);
+       if (!np)
+               return 0;
+
+       of_node_put(np);
 
        p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, align, flags,
                              iopte_cachep_ctor);
index 6a8b1ec4a48a1f1100bc0f9f301fc658758a35ca..9f74fddcd304f76bd8a9d546f1d2caf74e7dc588 100644 (file)
@@ -1015,8 +1015,15 @@ static struct platform_driver rk_iommu_driver = {
 
 static int __init rk_iommu_init(void)
 {
+       struct device_node *np;
        int ret;
 
+       np = of_find_matching_node(NULL, rk_iommu_dt_ids);
+       if (!np)
+               return 0;
+
+       of_node_put(np);
+
        ret = bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
        if (ret)
                return ret;
index 463c235acbdcdc1758329205e3c79e380b5fa7a6..4387dae14e453a949bb297ec1a74a59e400a3089 100644 (file)
@@ -69,6 +69,7 @@ static void __iomem *per_cpu_int_base;
 static void __iomem *main_int_base;
 static struct irq_domain *armada_370_xp_mpic_domain;
 static u32 doorbell_mask_reg;
+static int parent_irq;
 #ifdef CONFIG_PCI_MSI
 static struct irq_domain *armada_370_xp_msi_domain;
 static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
@@ -356,6 +357,7 @@ static int armada_xp_mpic_secondary_init(struct notifier_block *nfb,
 {
        if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
                armada_xp_mpic_smp_cpu_init();
+
        return NOTIFY_OK;
 }
 
@@ -364,6 +366,20 @@ static struct notifier_block armada_370_xp_mpic_cpu_notifier = {
        .priority = 100,
 };
 
+static int mpic_cascaded_secondary_init(struct notifier_block *nfb,
+                                       unsigned long action, void *hcpu)
+{
+       if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
+               enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block mpic_cascaded_cpu_notifier = {
+       .notifier_call = mpic_cascaded_secondary_init,
+       .priority = 100,
+};
+
 #endif /* CONFIG_SMP */
 
 static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
@@ -539,7 +555,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
                                             struct device_node *parent)
 {
        struct resource main_int_res, per_cpu_int_res;
-       int parent_irq, nr_irqs, i;
+       int nr_irqs, i;
        u32 control;
 
        BUG_ON(of_address_to_resource(node, 0, &main_int_res));
@@ -587,6 +603,9 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
                register_cpu_notifier(&armada_370_xp_mpic_cpu_notifier);
 #endif
        } else {
+#ifdef CONFIG_SMP
+               register_cpu_notifier(&mpic_cascaded_cpu_notifier);
+#endif
                irq_set_chained_handler(parent_irq,
                                        armada_370_xp_mpic_handle_cascade_irq);
        }
index d8996bdf0f61e95e45ee670e44e565d045fb9535..596b0a9eee99a9f2ea1beaac726bddc4069c4937 100644 (file)
@@ -416,13 +416,14 @@ static void its_send_single_command(struct its_node *its,
 {
        struct its_cmd_block *cmd, *sync_cmd, *next_cmd;
        struct its_collection *sync_col;
+       unsigned long flags;
 
-       raw_spin_lock(&its->lock);
+       raw_spin_lock_irqsave(&its->lock, flags);
 
        cmd = its_allocate_entry(its);
        if (!cmd) {             /* We're soooooo screewed... */
                pr_err_ratelimited("ITS can't allocate, dropping command\n");
-               raw_spin_unlock(&its->lock);
+               raw_spin_unlock_irqrestore(&its->lock, flags);
                return;
        }
        sync_col = builder(cmd, desc);
@@ -442,7 +443,7 @@ static void its_send_single_command(struct its_node *its,
 
 post:
        next_cmd = its_post_commands(its);
-       raw_spin_unlock(&its->lock);
+       raw_spin_unlock_irqrestore(&its->lock, flags);
 
        its_wait_for_range_completion(its, cmd, next_cmd);
 }
@@ -799,21 +800,43 @@ static int its_alloc_tables(struct its_node *its)
 {
        int err;
        int i;
-       int psz = PAGE_SIZE;
+       int psz = SZ_64K;
        u64 shr = GITS_BASER_InnerShareable;
 
        for (i = 0; i < GITS_BASER_NR_REGS; i++) {
                u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
                u64 type = GITS_BASER_TYPE(val);
                u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
+               int order = get_order(psz);
+               int alloc_size;
                u64 tmp;
                void *base;
 
                if (type == GITS_BASER_TYPE_NONE)
                        continue;
 
-               /* We're lazy and only allocate a single page for now */
-               base = (void *)get_zeroed_page(GFP_KERNEL);
+               /*
+                * Allocate as many entries as required to fit the
+                * range of device IDs that the ITS can grok... The ID
+                * space being incredibly sparse, this results in a
+                * massive waste of memory.
+                *
+                * For other tables, only allocate a single page.
+                */
+               if (type == GITS_BASER_TYPE_DEVICE) {
+                       u64 typer = readq_relaxed(its->base + GITS_TYPER);
+                       u32 ids = GITS_TYPER_DEVBITS(typer);
+
+                       order = get_order((1UL << ids) * entry_size);
+                       if (order >= MAX_ORDER) {
+                               order = MAX_ORDER - 1;
+                               pr_warn("%s: Device Table too large, reduce its page order to %u\n",
+                                       its->msi_chip.of_node->full_name, order);
+                       }
+               }
+
+               alloc_size = (1 << order) * PAGE_SIZE;
+               base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
                if (!base) {
                        err = -ENOMEM;
                        goto out_free;
@@ -841,7 +864,7 @@ retry_baser:
                        break;
                }
 
-               val |= (PAGE_SIZE / psz) - 1;
+               val |= (alloc_size / psz) - 1;
 
                writeq_relaxed(val, its->base + GITS_BASER + i * 8);
                tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
@@ -882,7 +905,7 @@ retry_baser:
                }
 
                pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
-                       (int)(PAGE_SIZE / entry_size),
+                       (int)(alloc_size / entry_size),
                        its_base_type_string[type],
                        (unsigned long)virt_to_phys(base),
                        psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
@@ -1020,8 +1043,9 @@ static void its_cpu_init_collection(void)
 static struct its_device *its_find_device(struct its_node *its, u32 dev_id)
 {
        struct its_device *its_dev = NULL, *tmp;
+       unsigned long flags;
 
-       raw_spin_lock(&its->lock);
+       raw_spin_lock_irqsave(&its->lock, flags);
 
        list_for_each_entry(tmp, &its->its_device_list, entry) {
                if (tmp->device_id == dev_id) {
@@ -1030,7 +1054,7 @@ static struct its_device *its_find_device(struct its_node *its, u32 dev_id)
                }
        }
 
-       raw_spin_unlock(&its->lock);
+       raw_spin_unlock_irqrestore(&its->lock, flags);
 
        return its_dev;
 }
@@ -1040,6 +1064,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 {
        struct its_device *dev;
        unsigned long *lpi_map;
+       unsigned long flags;
        void *itt;
        int lpi_base;
        int nr_lpis;
@@ -1056,7 +1081,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
        nr_ites = max(2UL, roundup_pow_of_two(nvecs));
        sz = nr_ites * its->ite_size;
        sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
-       itt = kmalloc(sz, GFP_KERNEL);
+       itt = kzalloc(sz, GFP_KERNEL);
        lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis);
 
        if (!dev || !itt || !lpi_map) {
@@ -1075,9 +1100,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
        dev->device_id = dev_id;
        INIT_LIST_HEAD(&dev->entry);
 
-       raw_spin_lock(&its->lock);
+       raw_spin_lock_irqsave(&its->lock, flags);
        list_add(&dev->entry, &its->its_device_list);
-       raw_spin_unlock(&its->lock);
+       raw_spin_unlock_irqrestore(&its->lock, flags);
 
        /* Bind the device to the first possible CPU */
        cpu = cpumask_first(cpu_online_mask);
@@ -1091,9 +1116,11 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 
 static void its_free_device(struct its_device *its_dev)
 {
-       raw_spin_lock(&its_dev->its->lock);
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&its_dev->its->lock, flags);
        list_del(&its_dev->entry);
-       raw_spin_unlock(&its_dev->its->lock);
+       raw_spin_unlock_irqrestore(&its_dev->its->lock, flags);
        kfree(its_dev->itt);
        kfree(its_dev);
 }
@@ -1112,31 +1139,69 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
        return 0;
 }
 
+struct its_pci_alias {
+       struct pci_dev  *pdev;
+       u32             dev_id;
+       u32             count;
+};
+
+static int its_pci_msi_vec_count(struct pci_dev *pdev)
+{
+       int msi, msix;
+
+       msi = max(pci_msi_vec_count(pdev), 0);
+       msix = max(pci_msix_vec_count(pdev), 0);
+
+       return max(msi, msix);
+}
+
+static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
+{
+       struct its_pci_alias *dev_alias = data;
+
+       dev_alias->dev_id = alias;
+       if (pdev != dev_alias->pdev)
+               dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev);
+
+       return 0;
+}
+
 static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
                           int nvec, msi_alloc_info_t *info)
 {
        struct pci_dev *pdev;
        struct its_node *its;
-       u32 dev_id;
        struct its_device *its_dev;
+       struct its_pci_alias dev_alias;
 
        if (!dev_is_pci(dev))
                return -EINVAL;
 
        pdev = to_pci_dev(dev);
-       dev_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
+       dev_alias.pdev = pdev;
+       dev_alias.count = nvec;
+
+       pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias);
        its = domain->parent->host_data;
 
-       its_dev = its_find_device(its, dev_id);
-       if (WARN_ON(its_dev))
-               return -EINVAL;
+       its_dev = its_find_device(its, dev_alias.dev_id);
+       if (its_dev) {
+               /*
+                * We already have seen this ID, probably through
+                * another alias (PCI bridge of some sort). No need to
+                * create the device.
+                */
+               dev_dbg(dev, "Reusing ITT for devID %x\n", dev_alias.dev_id);
+               goto out;
+       }
 
-       its_dev = its_create_device(its, dev_id, nvec);
+       its_dev = its_create_device(its, dev_alias.dev_id, dev_alias.count);
        if (!its_dev)
                return -ENOMEM;
 
-       dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n", nvec, ilog2(nvec));
-
+       dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n",
+               dev_alias.count, ilog2(dev_alias.count));
+out:
        info->scratchpad[0].ptr = its_dev;
        info->scratchpad[1].ptr = dev;
        return 0;
@@ -1255,6 +1320,34 @@ static const struct irq_domain_ops its_domain_ops = {
        .deactivate             = its_irq_domain_deactivate,
 };
 
+static int its_force_quiescent(void __iomem *base)
+{
+       u32 count = 1000000;    /* 1s */
+       u32 val;
+
+       val = readl_relaxed(base + GITS_CTLR);
+       if (val & GITS_CTLR_QUIESCENT)
+               return 0;
+
+       /* Disable the generation of all interrupts to this ITS */
+       val &= ~GITS_CTLR_ENABLE;
+       writel_relaxed(val, base + GITS_CTLR);
+
+       /* Poll GITS_CTLR and wait until ITS becomes quiescent */
+       while (1) {
+               val = readl_relaxed(base + GITS_CTLR);
+               if (val & GITS_CTLR_QUIESCENT)
+                       return 0;
+
+               count--;
+               if (!count)
+                       return -EBUSY;
+
+               cpu_relax();
+               udelay(1);
+       }
+}
+
 static int its_probe(struct device_node *node, struct irq_domain *parent)
 {
        struct resource res;
@@ -1283,6 +1376,13 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
                goto out_unmap;
        }
 
+       err = its_force_quiescent(its_base);
+       if (err) {
+               pr_warn("%s: failed to quiesce, giving up\n",
+                       node->full_name);
+               goto out_unmap;
+       }
+
        pr_info("ITS: %s\n", node->full_name);
 
        its = kzalloc(sizeof(*its), GFP_KERNEL);
@@ -1323,7 +1423,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
        writeq_relaxed(baser, its->base + GITS_CBASER);
        tmp = readq_relaxed(its->base + GITS_CBASER);
        writeq_relaxed(0, its->base + GITS_CWRITER);
-       writel_relaxed(1, its->base + GITS_CTLR);
+       writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
 
        if ((tmp ^ baser) & GITS_BASER_SHAREABILITY_MASK) {
                pr_info("ITS: using cache flushing for cmd queue\n");
@@ -1382,12 +1482,11 @@ static bool gic_rdists_supports_plpis(void)
 
 int its_cpu_init(void)
 {
-       if (!gic_rdists_supports_plpis()) {
-               pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
-               return -ENXIO;
-       }
-
        if (!list_empty(&its_nodes)) {
+               if (!gic_rdists_supports_plpis()) {
+                       pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
+                       return -ENXIO;
+               }
                its_cpu_init_lpis();
                its_cpu_init_collection();
        }
index 1c6dea2fbc34ce2d7b00007250111166315d8b78..fd8850def1b86a3310e376c821c3aaf33153f1cc 100644 (file)
@@ -466,7 +466,7 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
                tlist |= 1 << (mpidr & 0xf);
 
                cpu = cpumask_next(cpu, mask);
-               if (cpu == nr_cpu_ids)
+               if (cpu >= nr_cpu_ids)
                        goto out;
 
                mpidr = cpu_logical_map(cpu);
index 4634cf7d0ec379d5578319d45194cb18c9997510..471e1cdc193365dce99dcb53e3c8b21a388e0faa 100644 (file)
@@ -154,23 +154,25 @@ static inline unsigned int gic_irq(struct irq_data *d)
 static void gic_mask_irq(struct irq_data *d)
 {
        u32 mask = 1 << (gic_irq(d) % 32);
+       unsigned long flags;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
        writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
        if (gic_arch_extn.irq_mask)
                gic_arch_extn.irq_mask(d);
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 static void gic_unmask_irq(struct irq_data *d)
 {
        u32 mask = 1 << (gic_irq(d) % 32);
+       unsigned long flags;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
        if (gic_arch_extn.irq_unmask)
                gic_arch_extn.irq_unmask(d);
        writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 static void gic_eoi_irq(struct irq_data *d)
@@ -188,6 +190,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 {
        void __iomem *base = gic_dist_base(d);
        unsigned int gicirq = gic_irq(d);
+       unsigned long flags;
        int ret;
 
        /* Interrupt configuration for SGIs can't be changed */
@@ -199,14 +202,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
                            type != IRQ_TYPE_EDGE_RISING)
                return -EINVAL;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
        if (gic_arch_extn.irq_set_type)
                gic_arch_extn.irq_set_type(d, type);
 
        ret = gic_configure_irq(gicirq, type, base, NULL);
 
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 
        return ret;
 }
@@ -227,6 +230,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
        void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
        unsigned int cpu, shift = (gic_irq(d) % 4) * 8;
        u32 val, mask, bit;
+       unsigned long flags;
 
        if (!force)
                cpu = cpumask_any_and(mask_val, cpu_online_mask);
@@ -236,12 +240,12 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
        if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
                return -EINVAL;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
        mask = 0xff << shift;
        bit = gic_cpu_map[cpu] << shift;
        val = readl_relaxed(reg) & ~mask;
        writel_relaxed(val | bit, reg);
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 
        return IRQ_SET_MASK_OK;
 }
index 3c92780bda09e17843f3cea5c7c35161e103c25c..ff48da61c94c849bf06cbb9ab9cb149515dcd626 100644 (file)
@@ -1755,7 +1755,7 @@ init_card(struct hfc_pci *hc)
                enable_hwirq(hc);
                spin_unlock_irqrestore(&hc->lock, flags);
                /* Timeout 80ms */
-               current->state = TASK_UNINTERRUPTIBLE;
+               set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout((80 * HZ) / 1000);
                printk(KERN_INFO "HFC PCI: IRQ %d count %d\n",
                       hc->irq, hc->irqcnt);
index 6a7447c304acc39e6edc422bf8f6533acfde93b5..358a574d9e8be4d2bfed217b0448c89fe458d8f6 100644 (file)
@@ -1609,7 +1609,7 @@ icn_setup(char *line)
        if (ints[0] > 1)
                membase = (unsigned long)ints[2];
        if (str && *str) {
-               strcpy(sid, str);
+               strlcpy(sid, str, sizeof(sid));
                icn_id = sid;
                if ((p = strchr(sid, ','))) {
                        *p++ = 0;
index 37de0173b6d2324ed15de95442df37bc5a990e16..74adcd2c967ec8680d0cfd5c9d876c93074dbe10 100644 (file)
@@ -289,9 +289,16 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
        struct request_queue *q = bdev_get_queue(where->bdev);
        unsigned short logical_block_size = queue_logical_block_size(q);
        sector_t num_sectors;
+       unsigned int uninitialized_var(special_cmd_max_sectors);
 
-       /* Reject unsupported discard requests */
-       if ((rw & REQ_DISCARD) && !blk_queue_discard(q)) {
+       /*
+        * Reject unsupported discard and write same requests.
+        */
+       if (rw & REQ_DISCARD)
+               special_cmd_max_sectors = q->limits.max_discard_sectors;
+       else if (rw & REQ_WRITE_SAME)
+               special_cmd_max_sectors = q->limits.max_write_same_sectors;
+       if ((rw & (REQ_DISCARD | REQ_WRITE_SAME)) && special_cmd_max_sectors == 0) {
                dec_count(io, region, -EOPNOTSUPP);
                return;
        }
@@ -317,7 +324,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                store_io_and_region_in_bio(bio, io, region);
 
                if (rw & REQ_DISCARD) {
-                       num_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
+                       num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining);
                        bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
                        remaining -= num_sectors;
                } else if (rw & REQ_WRITE_SAME) {
@@ -326,7 +333,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                         */
                        dp->get_page(dp, &page, &len, &offset);
                        bio_add_page(bio, page, logical_block_size, offset);
-                       num_sectors = min_t(sector_t, q->limits.max_write_same_sectors, remaining);
+                       num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining);
                        bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
 
                        offset = 0;
index 8b204ae216ab62d354c814277dc413c34f0bf9a4..f83a0f3fc3656680c7bdba2dcd4bdaaac9f2f624 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/log2.h>
 #include <linux/dm-kcopyd.h>
 
+#include "dm.h"
+
 #include "dm-exception-store.h"
 
 #define DM_MSG_PREFIX "snapshots"
@@ -290,6 +292,16 @@ struct origin {
        struct list_head snapshots;
 };
 
+/*
+ * This structure is allocated for each origin target
+ */
+struct dm_origin {
+       struct dm_dev *dev;
+       struct dm_target *ti;
+       unsigned split_boundary;
+       struct list_head hash_list;
+};
+
 /*
  * Size of the hash table for origin volumes. If we make this
  * the size of the minors list then it should be nearly perfect
@@ -297,6 +309,7 @@ struct origin {
 #define ORIGIN_HASH_SIZE 256
 #define ORIGIN_MASK      0xFF
 static struct list_head *_origins;
+static struct list_head *_dm_origins;
 static struct rw_semaphore _origins_lock;
 
 static DECLARE_WAIT_QUEUE_HEAD(_pending_exceptions_done);
@@ -310,12 +323,22 @@ static int init_origin_hash(void)
        _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
                           GFP_KERNEL);
        if (!_origins) {
-               DMERR("unable to allocate memory");
+               DMERR("unable to allocate memory for _origins");
                return -ENOMEM;
        }
-
        for (i = 0; i < ORIGIN_HASH_SIZE; i++)
                INIT_LIST_HEAD(_origins + i);
+
+       _dm_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
+                             GFP_KERNEL);
+       if (!_dm_origins) {
+               DMERR("unable to allocate memory for _dm_origins");
+               kfree(_origins);
+               return -ENOMEM;
+       }
+       for (i = 0; i < ORIGIN_HASH_SIZE; i++)
+               INIT_LIST_HEAD(_dm_origins + i);
+
        init_rwsem(&_origins_lock);
 
        return 0;
@@ -324,6 +347,7 @@ static int init_origin_hash(void)
 static void exit_origin_hash(void)
 {
        kfree(_origins);
+       kfree(_dm_origins);
 }
 
 static unsigned origin_hash(struct block_device *bdev)
@@ -350,6 +374,30 @@ static void __insert_origin(struct origin *o)
        list_add_tail(&o->hash_list, sl);
 }
 
+static struct dm_origin *__lookup_dm_origin(struct block_device *origin)
+{
+       struct list_head *ol;
+       struct dm_origin *o;
+
+       ol = &_dm_origins[origin_hash(origin)];
+       list_for_each_entry (o, ol, hash_list)
+               if (bdev_equal(o->dev->bdev, origin))
+                       return o;
+
+       return NULL;
+}
+
+static void __insert_dm_origin(struct dm_origin *o)
+{
+       struct list_head *sl = &_dm_origins[origin_hash(o->dev->bdev)];
+       list_add_tail(&o->hash_list, sl);
+}
+
+static void __remove_dm_origin(struct dm_origin *o)
+{
+       list_del(&o->hash_list);
+}
+
 /*
  * _origins_lock must be held when calling this function.
  * Returns number of snapshots registered using the supplied cow device, plus:
@@ -1840,9 +1888,40 @@ static int snapshot_preresume(struct dm_target *ti)
 static void snapshot_resume(struct dm_target *ti)
 {
        struct dm_snapshot *s = ti->private;
-       struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
+       struct dm_snapshot *snap_src = NULL, *snap_dest = NULL, *snap_merging = NULL;
+       struct dm_origin *o;
+       struct mapped_device *origin_md = NULL;
+       bool must_restart_merging = false;
 
        down_read(&_origins_lock);
+
+       o = __lookup_dm_origin(s->origin->bdev);
+       if (o)
+               origin_md = dm_table_get_md(o->ti->table);
+       if (!origin_md) {
+               (void) __find_snapshots_sharing_cow(s, NULL, NULL, &snap_merging);
+               if (snap_merging)
+                       origin_md = dm_table_get_md(snap_merging->ti->table);
+       }
+       if (origin_md == dm_table_get_md(ti->table))
+               origin_md = NULL;
+       if (origin_md) {
+               if (dm_hold(origin_md))
+                       origin_md = NULL;
+       }
+
+       up_read(&_origins_lock);
+
+       if (origin_md) {
+               dm_internal_suspend_fast(origin_md);
+               if (snap_merging && test_bit(RUNNING_MERGE, &snap_merging->state_bits)) {
+                       must_restart_merging = true;
+                       stop_merge(snap_merging);
+               }
+       }
+
+       down_read(&_origins_lock);
+
        (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
        if (snap_src && snap_dest) {
                down_write(&snap_src->lock);
@@ -1851,8 +1930,16 @@ static void snapshot_resume(struct dm_target *ti)
                up_write(&snap_dest->lock);
                up_write(&snap_src->lock);
        }
+
        up_read(&_origins_lock);
 
+       if (origin_md) {
+               if (must_restart_merging)
+                       start_merge(snap_merging);
+               dm_internal_resume_fast(origin_md);
+               dm_put(origin_md);
+       }
+
        /* Now we have correct chunk size, reregister */
        reregister_snapshot(s);
 
@@ -2133,11 +2220,6 @@ static int origin_write_extent(struct dm_snapshot *merging_snap,
  * Origin: maps a linear range of a device, with hooks for snapshotting.
  */
 
-struct dm_origin {
-       struct dm_dev *dev;
-       unsigned split_boundary;
-};
-
 /*
  * Construct an origin mapping: <dev_path>
  * The context for an origin is merely a 'struct dm_dev *'
@@ -2166,6 +2248,7 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad_open;
        }
 
+       o->ti = ti;
        ti->private = o;
        ti->num_flush_bios = 1;
 
@@ -2180,6 +2263,7 @@ bad_alloc:
 static void origin_dtr(struct dm_target *ti)
 {
        struct dm_origin *o = ti->private;
+
        dm_put_device(ti, o->dev);
        kfree(o);
 }
@@ -2216,6 +2300,19 @@ static void origin_resume(struct dm_target *ti)
        struct dm_origin *o = ti->private;
 
        o->split_boundary = get_origin_minimum_chunksize(o->dev->bdev);
+
+       down_write(&_origins_lock);
+       __insert_dm_origin(o);
+       up_write(&_origins_lock);
+}
+
+static void origin_postsuspend(struct dm_target *ti)
+{
+       struct dm_origin *o = ti->private;
+
+       down_write(&_origins_lock);
+       __remove_dm_origin(o);
+       up_write(&_origins_lock);
 }
 
 static void origin_status(struct dm_target *ti, status_type_t type,
@@ -2258,12 +2355,13 @@ static int origin_iterate_devices(struct dm_target *ti,
 
 static struct target_type origin_target = {
        .name    = "snapshot-origin",
-       .version = {1, 8, 1},
+       .version = {1, 9, 0},
        .module  = THIS_MODULE,
        .ctr     = origin_ctr,
        .dtr     = origin_dtr,
        .map     = origin_map,
        .resume  = origin_resume,
+       .postsuspend = origin_postsuspend,
        .status  = origin_status,
        .merge   = origin_merge,
        .iterate_devices = origin_iterate_devices,
@@ -2271,7 +2369,7 @@ static struct target_type origin_target = {
 
 static struct target_type snapshot_target = {
        .name    = "snapshot",
-       .version = {1, 12, 0},
+       .version = {1, 13, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
@@ -2285,7 +2383,7 @@ static struct target_type snapshot_target = {
 
 static struct target_type merge_target = {
        .name    = dm_snapshot_merge_target_name,
-       .version = {1, 2, 0},
+       .version = {1, 3, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
index 654773cb1eeea23b39db0fcf0e6fb00d91d9476d..921aafd12aee6754c373fbbd0df8941219b5c1eb 100644 (file)
@@ -2358,17 +2358,6 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_REMAPPED;
 
        case -ENODATA:
-               if (get_pool_mode(tc->pool) == PM_READ_ONLY) {
-                       /*
-                        * This block isn't provisioned, and we have no way
-                        * of doing so.
-                        */
-                       handle_unserviceable_bio(tc->pool, bio);
-                       cell_defer_no_holder(tc, virt_cell);
-                       return DM_MAPIO_SUBMITTED;
-               }
-               /* fall through */
-
        case -EWOULDBLOCK:
                thin_defer_cell(tc, virt_cell);
                return DM_MAPIO_SUBMITTED;
index 73f28802dc7abc3cb46dc38c8ef6fb5bb521e66b..8001fe9e3434734ad92c8109ef8fa860906238ce 100644 (file)
@@ -433,7 +433,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode)
 
        dm_get(md);
        atomic_inc(&md->open_count);
-
 out:
        spin_unlock(&_minor_lock);
 
@@ -442,16 +441,20 @@ out:
 
 static void dm_blk_close(struct gendisk *disk, fmode_t mode)
 {
-       struct mapped_device *md = disk->private_data;
+       struct mapped_device *md;
 
        spin_lock(&_minor_lock);
 
+       md = disk->private_data;
+       if (WARN_ON(!md))
+               goto out;
+
        if (atomic_dec_and_test(&md->open_count) &&
            (test_bit(DMF_DEFERRED_REMOVE, &md->flags)))
                queue_work(deferred_remove_workqueue, &deferred_remove_work);
 
        dm_put(md);
-
+out:
        spin_unlock(&_minor_lock);
 }
 
@@ -2241,7 +2244,6 @@ static void free_dev(struct mapped_device *md)
        int minor = MINOR(disk_devt(md->disk));
 
        unlock_fs(md);
-       bdput(md->bdev);
        destroy_workqueue(md->wq);
 
        if (md->kworker_task)
@@ -2252,19 +2254,22 @@ static void free_dev(struct mapped_device *md)
                mempool_destroy(md->rq_pool);
        if (md->bs)
                bioset_free(md->bs);
-       blk_integrity_unregister(md->disk);
-       del_gendisk(md->disk);
+
        cleanup_srcu_struct(&md->io_barrier);
        free_table_devices(&md->table_devices);
-       free_minor(minor);
+       dm_stats_cleanup(&md->stats);
 
        spin_lock(&_minor_lock);
        md->disk->private_data = NULL;
        spin_unlock(&_minor_lock);
-
+       if (blk_get_integrity(md->disk))
+               blk_integrity_unregister(md->disk);
+       del_gendisk(md->disk);
        put_disk(md->disk);
        blk_cleanup_queue(md->queue);
-       dm_stats_cleanup(&md->stats);
+       bdput(md->bdev);
+       free_minor(minor);
+
        module_put(THIS_MODULE);
        kfree(md);
 }
@@ -2616,6 +2621,19 @@ void dm_get(struct mapped_device *md)
        BUG_ON(test_bit(DMF_FREEING, &md->flags));
 }
 
+int dm_hold(struct mapped_device *md)
+{
+       spin_lock(&_minor_lock);
+       if (test_bit(DMF_FREEING, &md->flags)) {
+               spin_unlock(&_minor_lock);
+               return -EBUSY;
+       }
+       dm_get(md);
+       spin_unlock(&_minor_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dm_hold);
+
 const char *dm_device_name(struct mapped_device *md)
 {
        return md->name;
@@ -2629,8 +2647,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
 
        might_sleep();
 
-       spin_lock(&_minor_lock);
        map = dm_get_live_table(md, &srcu_idx);
+
+       spin_lock(&_minor_lock);
        idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md))));
        set_bit(DMF_FREEING, &md->flags);
        spin_unlock(&_minor_lock);
@@ -2638,10 +2657,16 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
        if (dm_request_based(md))
                flush_kthread_worker(&md->kworker);
 
+       /*
+        * Take suspend_lock so that presuspend and postsuspend methods
+        * do not race with internal suspend.
+        */
+       mutex_lock(&md->suspend_lock);
        if (!dm_suspended_md(md)) {
                dm_table_presuspend_targets(map);
                dm_table_postsuspend_targets(map);
        }
+       mutex_unlock(&md->suspend_lock);
 
        /* dm_put_live_table must be before msleep, otherwise deadlock is possible */
        dm_put_live_table(md, srcu_idx);
@@ -3115,6 +3140,7 @@ void dm_internal_suspend_fast(struct mapped_device *md)
        flush_workqueue(md->wq);
        dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
 }
+EXPORT_SYMBOL_GPL(dm_internal_suspend_fast);
 
 void dm_internal_resume_fast(struct mapped_device *md)
 {
@@ -3126,6 +3152,7 @@ void dm_internal_resume_fast(struct mapped_device *md)
 done:
        mutex_unlock(&md->suspend_lock);
 }
+EXPORT_SYMBOL_GPL(dm_internal_resume_fast);
 
 /*-----------------------------------------------------------------
  * Event notification.
index c8d2bac4e28be4a65edb63d613b0336b7ff35783..717daad71fb101b2b97efd03b1bb41d8b35ecfe7 100644 (file)
@@ -2555,7 +2555,7 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
        return err ? err : len;
 }
 static struct rdev_sysfs_entry rdev_state =
-__ATTR(state, S_IRUGO|S_IWUSR, state_show, state_store);
+__ATTR_PREALLOC(state, S_IRUGO|S_IWUSR, state_show, state_store);
 
 static ssize_t
 errors_show(struct md_rdev *rdev, char *page)
@@ -3638,7 +3638,8 @@ resync_start_store(struct mddev *mddev, const char *buf, size_t len)
        return err ?: len;
 }
 static struct md_sysfs_entry md_resync_start =
-__ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store);
+__ATTR_PREALLOC(resync_start, S_IRUGO|S_IWUSR,
+               resync_start_show, resync_start_store);
 
 /*
  * The array state can be:
@@ -3851,7 +3852,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
        return err ?: len;
 }
 static struct md_sysfs_entry md_array_state =
-__ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
+__ATTR_PREALLOC(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
 
 static ssize_t
 max_corrected_read_errors_show(struct mddev *mddev, char *page) {
@@ -4101,7 +4102,7 @@ out_unlock:
 }
 
 static struct md_sysfs_entry md_metadata =
-__ATTR(metadata_version, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
+__ATTR_PREALLOC(metadata_version, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
 
 static ssize_t
 action_show(struct mddev *mddev, char *page)
@@ -4189,7 +4190,7 @@ action_store(struct mddev *mddev, const char *page, size_t len)
 }
 
 static struct md_sysfs_entry md_scan_mode =
-__ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
+__ATTR_PREALLOC(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
 
 static ssize_t
 last_sync_action_show(struct mddev *mddev, char *page)
@@ -4335,7 +4336,8 @@ sync_completed_show(struct mddev *mddev, char *page)
        return sprintf(page, "%llu / %llu\n", resync, max_sectors);
 }
 
-static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
+static struct md_sysfs_entry md_sync_completed =
+       __ATTR_PREALLOC(sync_completed, S_IRUGO, sync_completed_show, NULL);
 
 static ssize_t
 min_sync_show(struct mddev *mddev, char *page)
@@ -5078,7 +5080,8 @@ int md_run(struct mddev *mddev)
        }
        if (err) {
                mddev_detach(mddev);
-               pers->free(mddev, mddev->private);
+               if (mddev->private)
+                       pers->free(mddev, mddev->private);
                module_put(pers->owner);
                bitmap_destroy(mddev);
                return err;
index a13f738a7b39f60fa340dec21612cf25b99570a7..3ed9f42ddca65e10351a1a453f16383e63c52634 100644 (file)
@@ -467,8 +467,6 @@ static int raid0_run(struct mddev *mddev)
        dump_zones(mddev);
 
        ret = md_integrity_register(mddev);
-       if (ret)
-               raid0_free(mddev, conf);
 
        return ret;
 }
index 4153da5d40111844616e8247a78e16c561602395..d34e238afa54c24ccaefbc7c6d58974dc2104be6 100644 (file)
@@ -560,7 +560,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
                if (test_bit(WriteMostly, &rdev->flags)) {
                        /* Don't balance among write-mostly, just
                         * use the first as a last resort */
-                       if (best_disk < 0) {
+                       if (best_dist_disk < 0) {
                                if (is_badblock(rdev, this_sector, sectors,
                                                &first_bad, &bad_sectors)) {
                                        if (first_bad < this_sector)
@@ -569,7 +569,8 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
                                        best_good_sectors = first_bad - this_sector;
                                } else
                                        best_good_sectors = sectors;
-                               best_disk = disk;
+                               best_dist_disk = disk;
+                               best_pending_disk = disk;
                        }
                        continue;
                }
index e75d48c0421a41788c9159ef7e74d22ad93d9695..cd2f96b2c57263628ef0816af3b114ad9437b740 100644 (file)
@@ -5121,12 +5121,17 @@ static inline sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int
                schedule_timeout_uninterruptible(1);
        }
        /* Need to check if array will still be degraded after recovery/resync
-        * We don't need to check the 'failed' flag as when that gets set,
-        * recovery aborts.
+        * Note in case of > 1 drive failures it's possible we're rebuilding
+        * one drive while leaving another faulty drive in array.
         */
-       for (i = 0; i < conf->raid_disks; i++)
-               if (conf->disks[i].rdev == NULL)
+       rcu_read_lock();
+       for (i = 0; i < conf->raid_disks; i++) {
+               struct md_rdev *rdev = ACCESS_ONCE(conf->disks[i].rdev);
+
+               if (rdev == NULL || test_bit(Faulty, &rdev->flags))
                        still_degraded = 1;
+       }
+       rcu_read_unlock();
 
        bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded);
 
index f38ec424872e362b934aaa6edd2fb21358bcb326..5615522f8d628b0f9d4b43d240d18d7bad02c835 100644 (file)
@@ -739,7 +739,7 @@ static int __init kempld_init(void)
                for (id = kempld_dmi_table;
                     id->matches[0].slot != DMI_NONE; id++)
                        if (strstr(id->ident, force_device_id))
-                               if (id->callback && id->callback(id))
+                               if (id->callback && !id->callback(id))
                                        break;
                if (id->matches[0].slot == DMI_NONE)
                        return -ENODEV;
index ede50244f265b14d950fba0448652960304fa971..dbd907d7170ebe990cb63fede374624ea03b6fd4 100644 (file)
@@ -196,18 +196,27 @@ EXPORT_SYMBOL_GPL(rtsx_usb_ep0_write_register);
 int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
 {
        u16 value;
+       u8 *buf;
+       int ret;
 
        if (!data)
                return -EINVAL;
-       *data = 0;
+
+       buf = kzalloc(sizeof(u8), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        addr |= EP0_READ_REG_CMD << EP0_OP_SHIFT;
        value = swab16(addr);
 
-       return usb_control_msg(ucr->pusb_dev,
+       ret = usb_control_msg(ucr->pusb_dev,
                        usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value, 0, data, 1, 100);
+                       value, 0, buf, 1, 100);
+       *data = *buf;
+
+       kfree(buf);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(rtsx_usb_ep0_read_register);
 
@@ -288,18 +297,27 @@ static int rtsx_usb_get_status_with_bulk(struct rtsx_ucr *ucr, u16 *status)
 int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status)
 {
        int ret;
+       u16 *buf;
 
        if (!status)
                return -EINVAL;
 
-       if (polling_pipe == 0)
+       if (polling_pipe == 0) {
+               buf = kzalloc(sizeof(u16), GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+
                ret = usb_control_msg(ucr->pusb_dev,
                                usb_rcvctrlpipe(ucr->pusb_dev, 0),
                                RTSX_USB_REQ_POLL,
                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               0, 0, status, 2, 100);
-       else
+                               0, 0, buf, 2, 100);
+               *status = *buf;
+
+               kfree(buf);
+       } else {
                ret = rtsx_usb_get_status_with_bulk(ucr, status);
+       }
 
        /* usb_control_msg may return positive when success */
        if (ret < 0)
index 9306219d5675442b186b0ab6381fdd246ad09e60..6ad049a08e4d9d27880e62b69a8d249207fa5a13 100644 (file)
@@ -341,6 +341,8 @@ void mei_stop(struct mei_device *dev)
 
        dev->dev_state = MEI_DEV_POWER_DOWN;
        mei_reset(dev);
+       /* move device to disabled state unconditionally */
+       dev->dev_state = MEI_DEV_DISABLED;
 
        mutex_unlock(&dev->device_lock);
 
index e9f1d8d8461353cd88831c154ae6dc43fe994772..c53f14a7ce546533c300313a54078e1bad327bf9 100644 (file)
@@ -124,7 +124,7 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
                    PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) {
                        ret = PTR_ERR(pwrseq->reset_gpios[i]);
 
-                       while (--i)
+                       while (i--)
                                gpiod_put(pwrseq->reset_gpios[i]);
 
                        goto clk_put;
index 5b76a173cd95d6d59c41c47d15c081ff39473c53..5897d8d8fa5a962d896e6726edde207b99575d39 100644 (file)
@@ -526,6 +526,7 @@ config MTD_NAND_SUNXI
 
 config MTD_NAND_HISI504
        tristate "Support for NAND controller on Hisilicon SoC Hip04"
+       depends on HAS_DMA
        help
          Enables support for NAND controller on Hisilicon SoC Hip04.
 
index 96b0b1d27df1b23846d09e81be2065ea59c66b7b..10b1f7a4fe50511e9fdac06242343f14df9cf71f 100644 (file)
@@ -480,6 +480,42 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
        nand_writel(info, NDCR, ndcr | int_mask);
 }
 
+static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
+{
+       if (info->ecc_bch) {
+               int timeout;
+
+               /*
+                * According to the datasheet, when reading from NDDB
+                * with BCH enabled, after each 32 bytes reads, we
+                * have to make sure that the NDSR.RDDREQ bit is set.
+                *
+                * Drain the FIFO 8 32 bits reads at a time, and skip
+                * the polling on the last read.
+                */
+               while (len > 8) {
+                       __raw_readsl(info->mmio_base + NDDB, data, 8);
+
+                       for (timeout = 0;
+                            !(nand_readl(info, NDSR) & NDSR_RDDREQ);
+                            timeout++) {
+                               if (timeout >= 5) {
+                                       dev_err(&info->pdev->dev,
+                                               "Timeout on RDDREQ while draining the FIFO\n");
+                                       return;
+                               }
+
+                               mdelay(1);
+                       }
+
+                       data += 32;
+                       len -= 8;
+               }
+       }
+
+       __raw_readsl(info->mmio_base + NDDB, data, len);
+}
+
 static void handle_data_pio(struct pxa3xx_nand_info *info)
 {
        unsigned int do_bytes = min(info->data_size, info->chunk_size);
@@ -496,14 +532,14 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
                                      DIV_ROUND_UP(info->oob_size, 4));
                break;
        case STATE_PIO_READING:
-               __raw_readsl(info->mmio_base + NDDB,
-                            info->data_buff + info->data_buff_pos,
-                            DIV_ROUND_UP(do_bytes, 4));
+               drain_fifo(info,
+                          info->data_buff + info->data_buff_pos,
+                          DIV_ROUND_UP(do_bytes, 4));
 
                if (info->oob_size > 0)
-                       __raw_readsl(info->mmio_base + NDDB,
-                                    info->oob_buff + info->oob_buff_pos,
-                                    DIV_ROUND_UP(info->oob_size, 4));
+                       drain_fifo(info,
+                                  info->oob_buff + info->oob_buff_pos,
+                                  DIV_ROUND_UP(info->oob_size, 4));
                break;
        default:
                dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
@@ -1572,6 +1608,8 @@ static int alloc_nand_resource(struct platform_device *pdev)
        int ret, irq, cs;
 
        pdata = dev_get_platdata(&pdev->dev);
+       if (pdata->num_cs <= 0)
+               return -ENODEV;
        info = devm_kzalloc(&pdev->dev, sizeof(*info) + (sizeof(*mtd) +
                            sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
        if (!info)
index da4c79259f67f3e2bd63a62570845eb10c89e989..16e34b37d134cee7797651f4ad8586db8d11faa1 100644 (file)
@@ -425,9 +425,10 @@ retry:
                                        ubi_warn(ubi, "corrupted VID header at PEB %d, LEB %d:%d",
                                                 pnum, vol_id, lnum);
                                        err = -EBADMSG;
-                               } else
+                               } else {
                                        err = -EINVAL;
                                        ubi_ro_mode(ubi);
+                               }
                        }
                        goto out_free;
                } else if (err == UBI_IO_BITFLIPS)
index 84673ebcf428846fadf26ae881c39172fd45d612..df51d6025a9017413500046edb78401abe0dfdb3 100644 (file)
@@ -157,7 +157,7 @@ config IPVLAN
       making it transparent to the connected L2 switch.
 
       Ipvlan devices can be added using the "ip" command from the
-      iproute2 package starting with the iproute2-X.Y.ZZ release:
+      iproute2 package starting with the iproute2-3.19 release:
 
       "ip link add link <main-dev> [ NAME ] type ipvlan"
 
index 4ce6ca5f3d365a48ab554c7477b157437fff9357..dc6b78e5342f937e6b3b2d498d4694bc0d0fe6c0 100644 (file)
@@ -40,7 +40,7 @@ config DEV_APPLETALK
 
 config LTPC
        tristate "Apple/Farallon LocalTalk PC support"
-       depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API
+       depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API && VIRT_TO_BUS
        help
          This allows you to use the AppleTalk PC card to connect to LocalTalk
          networks. The card is also known as the Farallon PhoneNet PC card.
index 98d73aab52fe962888a675d1293ae69f9731f7d0..58808f6514520c869631b356d6476f8cbc060a14 100644 (file)
@@ -131,7 +131,7 @@ config CAN_RCAR
 
 config CAN_XILINXCAN
        tristate "Xilinx CAN"
-       depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
+       depends on ARCH_ZYNQ || ARM64 || MICROBLAZE || COMPILE_TEST
        depends on COMMON_CLK && HAS_IOMEM
        ---help---
          Xilinx CAN driver. This driver supports both soft AXI CAN IP and
index 3c82e02e3daee633b65274abce48a4ae71257d5a..b0f69248cb71cd5642f9e34f67d291ee8a842dd2 100644 (file)
@@ -579,6 +579,10 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
        skb->pkt_type = PACKET_BROADCAST;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
+
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
 
@@ -603,6 +607,10 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
        skb->pkt_type = PACKET_BROADCAST;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
+
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
 
index 2928f7003041d92c099d31d19621f1a429ea0848..e97a08ce0b90c298577fed09c96dc7a711076e5e 100644 (file)
@@ -14,6 +14,8 @@
  * Copyright (C) 2015 Valeo S.A.
  */
 
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
 #include <linux/completion.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -466,10 +468,11 @@ struct kvaser_usb {
 struct kvaser_usb_net_priv {
        struct can_priv can;
 
-       atomic_t active_tx_urbs;
-       struct usb_anchor tx_submitted;
+       spinlock_t tx_contexts_lock;
+       int active_tx_contexts;
        struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
 
+       struct usb_anchor tx_submitted;
        struct completion start_comp, stop_comp;
 
        struct kvaser_usb *dev;
@@ -584,8 +587,15 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
                while (pos <= actual_len - MSG_HEADER_LEN) {
                        tmp = buf + pos;
 
-                       if (!tmp->len)
-                               break;
+                       /* Handle messages crossing the USB endpoint max packet
+                        * size boundary. Check kvaser_usb_read_bulk_callback()
+                        * for further details.
+                        */
+                       if (tmp->len == 0) {
+                               pos = round_up(pos,
+                                              dev->bulk_in->wMaxPacketSize);
+                               continue;
+                       }
 
                        if (pos + tmp->len > actual_len) {
                                dev_err(dev->udev->dev.parent,
@@ -686,6 +696,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
        struct kvaser_usb_net_priv *priv;
        struct sk_buff *skb;
        struct can_frame *cf;
+       unsigned long flags;
        u8 channel, tid;
 
        channel = msg->u.tx_acknowledge_header.channel;
@@ -729,12 +740,15 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 
        stats->tx_packets++;
        stats->tx_bytes += context->dlc;
-       can_get_echo_skb(priv->netdev, context->echo_index);
 
-       context->echo_index = MAX_TX_URBS;
-       atomic_dec(&priv->active_tx_urbs);
+       spin_lock_irqsave(&priv->tx_contexts_lock, flags);
 
+       can_get_echo_skb(priv->netdev, context->echo_index);
+       context->echo_index = MAX_TX_URBS;
+       --priv->active_tx_contexts;
        netif_wake_queue(priv->netdev);
+
+       spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
 }
 
 static void kvaser_usb_simple_msg_callback(struct urb *urb)
@@ -787,7 +801,6 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
                netdev_err(netdev, "Error transmitting URB\n");
                usb_unanchor_urb(urb);
                usb_free_urb(urb);
-               kfree(buf);
                return err;
        }
 
@@ -796,17 +809,6 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
        return 0;
 }
 
-static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
-{
-       int i;
-
-       usb_kill_anchored_urbs(&priv->tx_submitted);
-       atomic_set(&priv->active_tx_urbs, 0);
-
-       for (i = 0; i < MAX_TX_URBS; i++)
-               priv->tx_contexts[i].echo_index = MAX_TX_URBS;
-}
-
 static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
                                                 const struct kvaser_usb_error_summary *es,
                                                 struct can_frame *cf)
@@ -1317,8 +1319,19 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
        while (pos <= urb->actual_length - MSG_HEADER_LEN) {
                msg = urb->transfer_buffer + pos;
 
-               if (!msg->len)
-                       break;
+               /* The Kvaser firmware can only read and write messages that
+                * does not cross the USB's endpoint wMaxPacketSize boundary.
+                * If a follow-up command crosses such boundary, firmware puts
+                * a placeholder zero-length command in its place then aligns
+                * the real command to the next max packet size.
+                *
+                * Handle such cases or we're going to miss a significant
+                * number of events in case of a heavy rx load on the bus.
+                */
+               if (msg->len == 0) {
+                       pos = round_up(pos, dev->bulk_in->wMaxPacketSize);
+                       continue;
+               }
 
                if (pos + msg->len > urb->actual_length) {
                        dev_err(dev->udev->dev.parent, "Format error\n");
@@ -1326,7 +1339,6 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
                }
 
                kvaser_usb_handle_message(dev, msg);
-
                pos += msg->len;
        }
 
@@ -1498,6 +1510,24 @@ error:
        return err;
 }
 
+static void kvaser_usb_reset_tx_urb_contexts(struct kvaser_usb_net_priv *priv)
+{
+       int i;
+
+       priv->active_tx_contexts = 0;
+       for (i = 0; i < MAX_TX_URBS; i++)
+               priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+}
+
+/* This method might sleep. Do not call it in the atomic context
+ * of URB completions.
+ */
+static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
+{
+       usb_kill_anchored_urbs(&priv->tx_submitted);
+       kvaser_usb_reset_tx_urb_contexts(priv);
+}
+
 static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
 {
        int i;
@@ -1615,9 +1645,9 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        struct urb *urb;
        void *buf;
        struct kvaser_msg *msg;
-       int i, err;
-       int ret = NETDEV_TX_OK;
+       int i, err, ret = NETDEV_TX_OK;
        u8 *msg_tx_can_flags = NULL;            /* GCC */
+       unsigned long flags;
 
        if (can_dropped_invalid_skb(netdev, skb))
                return NETDEV_TX_OK;
@@ -1634,7 +1664,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        if (!buf) {
                stats->tx_dropped++;
                dev_kfree_skb(skb);
-               goto nobufmem;
+               goto freeurb;
        }
 
        msg = buf;
@@ -1671,22 +1701,32 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        if (cf->can_id & CAN_RTR_FLAG)
                *msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
 
+       spin_lock_irqsave(&priv->tx_contexts_lock, flags);
        for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
                if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
                        context = &priv->tx_contexts[i];
+
+                       context->echo_index = i;
+                       can_put_echo_skb(skb, netdev, context->echo_index);
+                       ++priv->active_tx_contexts;
+                       if (priv->active_tx_contexts >= MAX_TX_URBS)
+                               netif_stop_queue(netdev);
+
                        break;
                }
        }
+       spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
 
        /* This should never happen; it implies a flow control bug */
        if (!context) {
                netdev_warn(netdev, "cannot find free context\n");
+
+               kfree(buf);
                ret =  NETDEV_TX_BUSY;
-               goto releasebuf;
+               goto freeurb;
        }
 
        context->priv = priv;
-       context->echo_index = i;
        context->dlc = cf->can_dlc;
 
        msg->u.tx_can.tid = context->echo_index;
@@ -1698,18 +1738,17 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                          kvaser_usb_write_bulk_callback, context);
        usb_anchor_urb(urb, &priv->tx_submitted);
 
-       can_put_echo_skb(skb, netdev, context->echo_index);
-
-       atomic_inc(&priv->active_tx_urbs);
-
-       if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
-               netif_stop_queue(netdev);
-
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (unlikely(err)) {
+               spin_lock_irqsave(&priv->tx_contexts_lock, flags);
+
                can_free_echo_skb(netdev, context->echo_index);
+               context->echo_index = MAX_TX_URBS;
+               --priv->active_tx_contexts;
+               netif_wake_queue(netdev);
+
+               spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
 
-               atomic_dec(&priv->active_tx_urbs);
                usb_unanchor_urb(urb);
 
                stats->tx_dropped++;
@@ -1719,16 +1758,12 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                else
                        netdev_warn(netdev, "Failed tx_urb %d\n", err);
 
-               goto releasebuf;
+               goto freeurb;
        }
 
-       usb_free_urb(urb);
-
-       return NETDEV_TX_OK;
+       ret = NETDEV_TX_OK;
 
-releasebuf:
-       kfree(buf);
-nobufmem:
+freeurb:
        usb_free_urb(urb);
        return ret;
 }
@@ -1840,7 +1875,7 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
        struct kvaser_usb *dev = usb_get_intfdata(intf);
        struct net_device *netdev;
        struct kvaser_usb_net_priv *priv;
-       int i, err;
+       int err;
 
        err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, channel);
        if (err)
@@ -1854,19 +1889,17 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
 
        priv = netdev_priv(netdev);
 
+       init_usb_anchor(&priv->tx_submitted);
        init_completion(&priv->start_comp);
        init_completion(&priv->stop_comp);
 
-       init_usb_anchor(&priv->tx_submitted);
-       atomic_set(&priv->active_tx_urbs, 0);
-
-       for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++)
-               priv->tx_contexts[i].echo_index = MAX_TX_URBS;
-
        priv->dev = dev;
        priv->netdev = netdev;
        priv->channel = channel;
 
+       spin_lock_init(&priv->tx_contexts_lock);
+       kvaser_usb_reset_tx_urb_contexts(priv);
+
        priv->can.state = CAN_STATE_STOPPED;
        priv->can.clock.freq = CAN_USB_CLOCK;
        priv->can.bittiming_const = &kvaser_usb_bittiming_const;
index 962c3f027383a7a1e28077b4227b9c40f7542518..0bac0f14edc3cd73727b4a0d9f0776d857c4ba8c 100644 (file)
@@ -879,6 +879,10 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
 
                pdev->usb_if = ppdev->usb_if;
                pdev->cmd_buffer_addr = ppdev->cmd_buffer_addr;
+
+               /* do a copy of the ctrlmode[_supported] too */
+               dev->can.ctrlmode = ppdev->dev.can.ctrlmode;
+               dev->can.ctrlmode_supported = ppdev->dev.can.ctrlmode_supported;
        }
 
        pdev->usb_if->dev[dev->ctrl_idx] = dev;
index ee9f650d50264bb74771783b65e860b2aabb3d46..7b7053d3c5fad20e07a75eb5ea987743b51484ba 100644 (file)
@@ -105,8 +105,8 @@ static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off)  \
 {                                                                      \
        u32 indir, dir;                                                 \
        spin_lock(&priv->indir_lock);                                   \
-       indir = reg_readl(priv, REG_DIR_DATA_READ);                     \
        dir = __raw_readl(priv->name + off);                            \
+       indir = reg_readl(priv, REG_DIR_DATA_READ);                     \
        spin_unlock(&priv->indir_lock);                                 \
        return (u64)indir << 32 | dir;                                  \
 }                                                                      \
index 7769c05543f17fcc8432cac6145ebdd70c4fc5da..ec6eac1f8c95ab79d33209e272a31f71484b0f62 100644 (file)
@@ -484,11 +484,8 @@ static int axnet_open(struct net_device *dev)
     link->open++;
 
     info->link_status = 0x00;
-    init_timer(&info->watchdog);
-    info->watchdog.function = ei_watchdog;
-    info->watchdog.data = (u_long)dev;
-    info->watchdog.expires = jiffies + HZ;
-    add_timer(&info->watchdog);
+    setup_timer(&info->watchdog, ei_watchdog, (u_long)dev);
+    mod_timer(&info->watchdog, jiffies + HZ);
 
     return ax_open(dev);
 } /* axnet_open */
index 9fb7b9d4fd6c6595f7642d859678bc3097998750..2777289a26c0419f855926ef028942074ca62a2f 100644 (file)
@@ -918,11 +918,8 @@ static int pcnet_open(struct net_device *dev)
 
     info->phy_id = info->eth_phy;
     info->link_status = 0x00;
-    init_timer(&info->watchdog);
-    info->watchdog.function = ei_watchdog;
-    info->watchdog.data = (u_long)dev;
-    info->watchdog.expires = jiffies + HZ;
-    add_timer(&info->watchdog);
+    setup_timer(&info->watchdog, ei_watchdog, (u_long)dev);
+    mod_timer(&info->watchdog, jiffies + HZ);
 
     return ei_open(dev);
 } /* pcnet_open */
index 760c72c6e2acd50ba8472e4b4dd77170c2c381d6..6725dc00750bd6da367396bceb33adaac10842d0 100644 (file)
@@ -376,7 +376,8 @@ static int tse_rx(struct altera_tse_private *priv, int limit)
        u16 pktlength;
        u16 pktstatus;
 
-       while ((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) {
+       while (((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) &&
+              (count < limit))  {
                pktstatus = rxstatus >> 16;
                pktlength = rxstatus & 0xffff;
 
@@ -491,28 +492,27 @@ static int tse_poll(struct napi_struct *napi, int budget)
        struct altera_tse_private *priv =
                        container_of(napi, struct altera_tse_private, napi);
        int rxcomplete = 0;
-       int txcomplete = 0;
        unsigned long int flags;
 
-       txcomplete = tse_tx_complete(priv);
+       tse_tx_complete(priv);
 
        rxcomplete = tse_rx(priv, budget);
 
-       if (rxcomplete >= budget || txcomplete > 0)
-               return rxcomplete;
+       if (rxcomplete < budget) {
 
-       napi_gro_flush(napi, false);
-       __napi_complete(napi);
+               napi_gro_flush(napi, false);
+               __napi_complete(napi);
 
-       netdev_dbg(priv->dev,
-                  "NAPI Complete, did %d packets with budget %d\n",
-                  txcomplete+rxcomplete, budget);
+               netdev_dbg(priv->dev,
+                          "NAPI Complete, did %d packets with budget %d\n",
+                          rxcomplete, budget);
 
-       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
-       priv->dmaops->enable_rxirq(priv);
-       priv->dmaops->enable_txirq(priv);
-       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
-       return rxcomplete + txcomplete;
+               spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+               priv->dmaops->enable_rxirq(priv);
+               priv->dmaops->enable_txirq(priv);
+               spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+       }
+       return rxcomplete;
 }
 
 /* DMA TX & RX FIFO interrupt routing
@@ -521,7 +521,6 @@ static irqreturn_t altera_isr(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct altera_tse_private *priv;
-       unsigned long int flags;
 
        if (unlikely(!dev)) {
                pr_err("%s: invalid dev pointer\n", __func__);
@@ -529,20 +528,20 @@ static irqreturn_t altera_isr(int irq, void *dev_id)
        }
        priv = netdev_priv(dev);
 
-       /* turn off desc irqs and enable napi rx */
-       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+       spin_lock(&priv->rxdma_irq_lock);
+       /* reset IRQs */
+       priv->dmaops->clear_rxirq(priv);
+       priv->dmaops->clear_txirq(priv);
+       spin_unlock(&priv->rxdma_irq_lock);
 
        if (likely(napi_schedule_prep(&priv->napi))) {
+               spin_lock(&priv->rxdma_irq_lock);
                priv->dmaops->disable_rxirq(priv);
                priv->dmaops->disable_txirq(priv);
+               spin_unlock(&priv->rxdma_irq_lock);
                __napi_schedule(&priv->napi);
        }
 
-       /* reset IRQs */
-       priv->dmaops->clear_rxirq(priv);
-       priv->dmaops->clear_txirq(priv);
-
-       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
 
        return IRQ_HANDLED;
 }
@@ -1399,7 +1398,7 @@ static int altera_tse_probe(struct platform_device *pdev)
        }
 
        if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
-                                &priv->rx_fifo_depth)) {
+                                &priv->tx_fifo_depth)) {
                dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n");
                ret = -ENXIO;
                goto err_free_netdev;
index 11d6e6561df159c3dc9dff28fc504e945a77f47b..15a8190a6f75f61908f5ba968d37451e2f982897 100644 (file)
@@ -1543,7 +1543,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
 {
        struct pcnet32_private *lp;
        int i, media;
-       int fdx, mii, fset, dxsuflo;
+       int fdx, mii, fset, dxsuflo, sram;
        int chip_version;
        char *chipname;
        struct net_device *dev;
@@ -1580,7 +1580,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
        }
 
        /* initialize variables */
-       fdx = mii = fset = dxsuflo = 0;
+       fdx = mii = fset = dxsuflo = sram = 0;
        chip_version = (chip_version >> 12) & 0xffff;
 
        switch (chip_version) {
@@ -1613,6 +1613,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                chipname = "PCnet/FAST III 79C973";     /* PCI */
                fdx = 1;
                mii = 1;
+               sram = 1;
                break;
        case 0x2626:
                chipname = "PCnet/Home 79C978"; /* PCI */
@@ -1636,6 +1637,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                chipname = "PCnet/FAST III 79C975";     /* PCI */
                fdx = 1;
                mii = 1;
+               sram = 1;
                break;
        case 0x2628:
                chipname = "PCnet/PRO 79C976";
@@ -1664,6 +1666,31 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                dxsuflo = 1;
        }
 
+       /*
+        * The Am79C973/Am79C975 controllers come with 12K of SRAM
+        * which we can use for the Tx/Rx buffers but most importantly,
+        * the use of SRAM allow us to use the BCR18:NOUFLO bit to avoid
+        * Tx fifo underflows.
+        */
+       if (sram) {
+               /*
+                * The SRAM is being configured in two steps. First we
+                * set the SRAM size in the BCR25:SRAM_SIZE bits. According
+                * to the datasheet, each bit corresponds to a 512-byte
+                * page so we can have at most 24 pages. The SRAM_SIZE
+                * holds the value of the upper 8 bits of the 16-bit SRAM size.
+                * The low 8-bits start at 0x00 and end at 0xff. So the
+                * address range is from 0x0000 up to 0x17ff. Therefore,
+                * the SRAM_SIZE is set to 0x17. The next step is to set
+                * the BCR26:SRAM_BND midway through so the Tx and Rx
+                * buffers can share the SRAM equally.
+                */
+               a->write_bcr(ioaddr, 25, 0x17);
+               a->write_bcr(ioaddr, 26, 0xc);
+               /* And finally enable the NOUFLO bit */
+               a->write_bcr(ioaddr, 18, a->read_bcr(ioaddr, 18) | (1 << 11));
+       }
+
        dev = alloc_etherdev(sizeof(*lp));
        if (!dev) {
                ret = -ENOMEM;
index b93d4404d975571f0f4033f06f4de15b576156d3..885b02b5be07f6732fc0540684cb7875aeec1140 100644 (file)
@@ -609,6 +609,68 @@ static void xgbe_napi_disable(struct xgbe_prv_data *pdata, unsigned int del)
        }
 }
 
+static int xgbe_request_irqs(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_channel *channel;
+       struct net_device *netdev = pdata->netdev;
+       unsigned int i;
+       int ret;
+
+       ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0,
+                              netdev->name, pdata);
+       if (ret) {
+               netdev_alert(netdev, "error requesting irq %d\n",
+                            pdata->dev_irq);
+               return ret;
+       }
+
+       if (!pdata->per_channel_irq)
+               return 0;
+
+       channel = pdata->channel;
+       for (i = 0; i < pdata->channel_count; i++, channel++) {
+               snprintf(channel->dma_irq_name,
+                        sizeof(channel->dma_irq_name) - 1,
+                        "%s-TxRx-%u", netdev_name(netdev),
+                        channel->queue_index);
+
+               ret = devm_request_irq(pdata->dev, channel->dma_irq,
+                                      xgbe_dma_isr, 0,
+                                      channel->dma_irq_name, channel);
+               if (ret) {
+                       netdev_alert(netdev, "error requesting irq %d\n",
+                                    channel->dma_irq);
+                       goto err_irq;
+               }
+       }
+
+       return 0;
+
+err_irq:
+       /* Using an unsigned int, 'i' will go to UINT_MAX and exit */
+       for (i--, channel--; i < pdata->channel_count; i--, channel--)
+               devm_free_irq(pdata->dev, channel->dma_irq, channel);
+
+       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
+
+       return ret;
+}
+
+static void xgbe_free_irqs(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_channel *channel;
+       unsigned int i;
+
+       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
+
+       if (!pdata->per_channel_irq)
+               return;
+
+       channel = pdata->channel;
+       for (i = 0; i < pdata->channel_count; i++, channel++)
+               devm_free_irq(pdata->dev, channel->dma_irq, channel);
+}
+
 void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata)
 {
        struct xgbe_hw_if *hw_if = &pdata->hw_if;
@@ -810,20 +872,20 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
                return -EINVAL;
        }
 
-       phy_stop(pdata->phydev);
-
        spin_lock_irqsave(&pdata->lock, flags);
 
        if (caller == XGMAC_DRIVER_CONTEXT)
                netif_device_detach(netdev);
 
        netif_tx_stop_all_queues(netdev);
-       xgbe_napi_disable(pdata, 0);
 
-       /* Powerdown Tx/Rx */
        hw_if->powerdown_tx(pdata);
        hw_if->powerdown_rx(pdata);
 
+       xgbe_napi_disable(pdata, 0);
+
+       phy_stop(pdata->phydev);
+
        pdata->power_down = 1;
 
        spin_unlock_irqrestore(&pdata->lock, flags);
@@ -854,14 +916,14 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
 
        phy_start(pdata->phydev);
 
-       /* Enable Tx/Rx */
+       xgbe_napi_enable(pdata, 0);
+
        hw_if->powerup_tx(pdata);
        hw_if->powerup_rx(pdata);
 
        if (caller == XGMAC_DRIVER_CONTEXT)
                netif_device_attach(netdev);
 
-       xgbe_napi_enable(pdata, 0);
        netif_tx_start_all_queues(netdev);
 
        spin_unlock_irqrestore(&pdata->lock, flags);
@@ -875,6 +937,7 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
 {
        struct xgbe_hw_if *hw_if = &pdata->hw_if;
        struct net_device *netdev = pdata->netdev;
+       int ret;
 
        DBGPR("-->xgbe_start\n");
 
@@ -884,17 +947,31 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
 
        phy_start(pdata->phydev);
 
+       xgbe_napi_enable(pdata, 1);
+
+       ret = xgbe_request_irqs(pdata);
+       if (ret)
+               goto err_napi;
+
        hw_if->enable_tx(pdata);
        hw_if->enable_rx(pdata);
 
        xgbe_init_tx_timers(pdata);
 
-       xgbe_napi_enable(pdata, 1);
        netif_tx_start_all_queues(netdev);
 
        DBGPR("<--xgbe_start\n");
 
        return 0;
+
+err_napi:
+       xgbe_napi_disable(pdata, 1);
+
+       phy_stop(pdata->phydev);
+
+       hw_if->exit(pdata);
+
+       return ret;
 }
 
 static void xgbe_stop(struct xgbe_prv_data *pdata)
@@ -907,16 +984,21 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
 
        DBGPR("-->xgbe_stop\n");
 
-       phy_stop(pdata->phydev);
-
        netif_tx_stop_all_queues(netdev);
-       xgbe_napi_disable(pdata, 1);
 
        xgbe_stop_tx_timers(pdata);
 
        hw_if->disable_tx(pdata);
        hw_if->disable_rx(pdata);
 
+       xgbe_free_irqs(pdata);
+
+       xgbe_napi_disable(pdata, 1);
+
+       phy_stop(pdata->phydev);
+
+       hw_if->exit(pdata);
+
        channel = pdata->channel;
        for (i = 0; i < pdata->channel_count; i++, channel++) {
                if (!channel->tx_ring)
@@ -931,10 +1013,6 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
 
 static void xgbe_restart_dev(struct xgbe_prv_data *pdata)
 {
-       struct xgbe_channel *channel;
-       struct xgbe_hw_if *hw_if = &pdata->hw_if;
-       unsigned int i;
-
        DBGPR("-->xgbe_restart_dev\n");
 
        /* If not running, "restart" will happen on open */
@@ -942,19 +1020,10 @@ static void xgbe_restart_dev(struct xgbe_prv_data *pdata)
                return;
 
        xgbe_stop(pdata);
-       synchronize_irq(pdata->dev_irq);
-       if (pdata->per_channel_irq) {
-               channel = pdata->channel;
-               for (i = 0; i < pdata->channel_count; i++, channel++)
-                       synchronize_irq(channel->dma_irq);
-       }
 
        xgbe_free_tx_data(pdata);
        xgbe_free_rx_data(pdata);
 
-       /* Issue software reset to device */
-       hw_if->exit(pdata);
-
        xgbe_start(pdata);
 
        DBGPR("<--xgbe_restart_dev\n");
@@ -1283,10 +1352,7 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata,
 static int xgbe_open(struct net_device *netdev)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
-       struct xgbe_hw_if *hw_if = &pdata->hw_if;
        struct xgbe_desc_if *desc_if = &pdata->desc_if;
-       struct xgbe_channel *channel = NULL;
-       unsigned int i = 0;
        int ret;
 
        DBGPR("-->xgbe_open\n");
@@ -1329,55 +1395,14 @@ static int xgbe_open(struct net_device *netdev)
        INIT_WORK(&pdata->restart_work, xgbe_restart);
        INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp);
 
-       /* Request interrupts */
-       ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0,
-                              netdev->name, pdata);
-       if (ret) {
-               netdev_alert(netdev, "error requesting irq %d\n",
-                            pdata->dev_irq);
-               goto err_rings;
-       }
-
-       if (pdata->per_channel_irq) {
-               channel = pdata->channel;
-               for (i = 0; i < pdata->channel_count; i++, channel++) {
-                       snprintf(channel->dma_irq_name,
-                                sizeof(channel->dma_irq_name) - 1,
-                                "%s-TxRx-%u", netdev_name(netdev),
-                                channel->queue_index);
-
-                       ret = devm_request_irq(pdata->dev, channel->dma_irq,
-                                              xgbe_dma_isr, 0,
-                                              channel->dma_irq_name, channel);
-                       if (ret) {
-                               netdev_alert(netdev,
-                                            "error requesting irq %d\n",
-                                            channel->dma_irq);
-                               goto err_irq;
-                       }
-               }
-       }
-
        ret = xgbe_start(pdata);
        if (ret)
-               goto err_start;
+               goto err_rings;
 
        DBGPR("<--xgbe_open\n");
 
        return 0;
 
-err_start:
-       hw_if->exit(pdata);
-
-err_irq:
-       if (pdata->per_channel_irq) {
-               /* Using an unsigned int, 'i' will go to UINT_MAX and exit */
-               for (i--, channel--; i < pdata->channel_count; i--, channel--)
-                       devm_free_irq(pdata->dev, channel->dma_irq, channel);
-       }
-
-       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
-
 err_rings:
        desc_if->free_ring_resources(pdata);
 
@@ -1399,30 +1424,16 @@ err_phy_init:
 static int xgbe_close(struct net_device *netdev)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
-       struct xgbe_hw_if *hw_if = &pdata->hw_if;
        struct xgbe_desc_if *desc_if = &pdata->desc_if;
-       struct xgbe_channel *channel;
-       unsigned int i;
 
        DBGPR("-->xgbe_close\n");
 
        /* Stop the device */
        xgbe_stop(pdata);
 
-       /* Issue software reset to device */
-       hw_if->exit(pdata);
-
        /* Free the ring descriptors and buffers */
        desc_if->free_ring_resources(pdata);
 
-       /* Release the interrupts */
-       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
-       if (pdata->per_channel_irq) {
-               channel = pdata->channel;
-               for (i = 0; i < pdata->channel_count; i++, channel++)
-                       devm_free_irq(pdata->dev, channel->dma_irq, channel);
-       }
-
        /* Free the channel and ring structures */
        xgbe_free_channels(pdata);
 
index 869d97fcf7810ff9abb7a2cc6c7ade6e49ceb2df..b927021c6c4030c5f63abd9644aac7169d8b6034 100644 (file)
@@ -593,7 +593,7 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
        if (!xgene_ring_mgr_init(pdata))
                return -ENODEV;
 
-       if (!efi_enabled(EFI_BOOT)) {
+       if (pdata->clk) {
                clk_prepare_enable(pdata->clk);
                clk_disable_unprepare(pdata->clk);
                clk_prepare_enable(pdata->clk);
index 4de62b210c85bab8e3d172234f24381da7a66276..635a83be7e5ec5bec5670ceebca692abd9257260 100644 (file)
@@ -1025,6 +1025,8 @@ static int xgene_enet_remove(struct platform_device *pdev)
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id xgene_enet_acpi_match[] = {
        { "APMC0D05", },
+       { "APMC0D30", },
+       { "APMC0D31", },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
@@ -1033,6 +1035,8 @@ MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
 #ifdef CONFIG_OF
 static struct of_device_id xgene_enet_of_match[] = {
        {.compatible = "apm,xgene-enet",},
+       {.compatible = "apm,xgene1-sgenet",},
+       {.compatible = "apm,xgene1-xgenet",},
        {},
 };
 
index 21206d33b638cf3a76e67abeb0520d71a0310b29..a7f2cc3e485eebfae962fe24cfc1142021a74cde 100644 (file)
@@ -486,7 +486,7 @@ static int bcm_enet_poll(struct napi_struct *napi, int budget)
 {
        struct bcm_enet_priv *priv;
        struct net_device *dev;
-       int tx_work_done, rx_work_done;
+       int rx_work_done;
 
        priv = container_of(napi, struct bcm_enet_priv, napi);
        dev = priv->net_dev;
@@ -498,14 +498,14 @@ static int bcm_enet_poll(struct napi_struct *napi, int budget)
                         ENETDMAC_IR, priv->tx_chan);
 
        /* reclaim sent skb */
-       tx_work_done = bcm_enet_tx_reclaim(dev, 0);
+       bcm_enet_tx_reclaim(dev, 0);
 
        spin_lock(&priv->rx_lock);
        rx_work_done = bcm_enet_receive_queue(dev, budget);
        spin_unlock(&priv->rx_lock);
 
-       if (rx_work_done >= budget || tx_work_done > 0) {
-               /* rx/tx queue is not yet empty/clean */
+       if (rx_work_done >= budget) {
+               /* rx queue is not yet empty/clean */
                return rx_work_done;
        }
 
index 5b308a4a4d0eccc35c641967fcf2459ec736f094..783543ad1fcfa1a4976090e0797f7f15f29a1724 100644 (file)
@@ -274,9 +274,9 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = {
        /* RBUF misc statistics */
        STAT_RBUF("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, RBUF_OVFL_DISC_CNTR),
        STAT_RBUF("rbuf_err_cnt", mib.rbuf_err_cnt, RBUF_ERR_PKT_CNTR),
-       STAT_MIB_RX("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
-       STAT_MIB_RX("rx_dma_failed", mib.rx_dma_failed),
-       STAT_MIB_TX("tx_dma_failed", mib.tx_dma_failed),
+       STAT_MIB_SOFT("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
+       STAT_MIB_SOFT("rx_dma_failed", mib.rx_dma_failed),
+       STAT_MIB_SOFT("tx_dma_failed", mib.tx_dma_failed),
 };
 
 #define BCM_SYSPORT_STATS_LEN  ARRAY_SIZE(bcm_sysport_gstrings_stats)
@@ -345,6 +345,7 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv)
                s = &bcm_sysport_gstrings_stats[i];
                switch (s->type) {
                case BCM_SYSPORT_STAT_NETDEV:
+               case BCM_SYSPORT_STAT_SOFT:
                        continue;
                case BCM_SYSPORT_STAT_MIB_RX:
                case BCM_SYSPORT_STAT_MIB_TX:
index fc19417d82a505dc61c9f25a940f891522763e00..7e3d87a88c76a81e2c36b65559d8b2b0bcf34217 100644 (file)
@@ -570,6 +570,7 @@ enum bcm_sysport_stat_type {
        BCM_SYSPORT_STAT_RUNT,
        BCM_SYSPORT_STAT_RXCHK,
        BCM_SYSPORT_STAT_RBUF,
+       BCM_SYSPORT_STAT_SOFT,
 };
 
 /* Macros to help define ethtool statistics */
@@ -590,6 +591,7 @@ enum bcm_sysport_stat_type {
 #define STAT_MIB_RX(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_MIB_RX)
 #define STAT_MIB_TX(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_MIB_TX)
 #define STAT_RUNT(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_RUNT)
+#define STAT_MIB_SOFT(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_SOFT)
 
 #define STAT_RXCHK(str, m, ofs) { \
        .stat_string = str, \
index 676ffe09318073e33b707d46423bdcf780451750..0469f72c6e7e8e01147446a528d5771a147b5cc6 100644 (file)
@@ -302,9 +302,6 @@ static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
        slot->skb = skb;
        slot->dma_addr = dma_addr;
 
-       if (slot->dma_addr & 0xC0000000)
-               bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
-
        return 0;
 }
 
@@ -505,8 +502,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
                                  ring->mmio_base);
                        goto err_dma_free;
                }
-               if (ring->dma_base & 0xC0000000)
-                       bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
 
                ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
                                                      BGMAC_DMA_RING_TX);
@@ -536,8 +531,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
                        err = -ENOMEM;
                        goto err_dma_free;
                }
-               if (ring->dma_base & 0xC0000000)
-                       bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
 
                ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
                                                      BGMAC_DMA_RING_RX);
index 7155e1d2c208c7253b846ee954086fef5fd574da..996e215fc3246c4fba6f1714ddceb69b88f179be 100644 (file)
@@ -12722,6 +12722,9 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
        pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
                               PCICFG_VENDOR_ID_OFFSET);
 
+       /* Set PCIe reset type to fundamental for EEH recovery */
+       pdev->needs_freset = 1;
+
        /* AER (Advanced Error reporting) configuration */
        rc = pci_enable_pcie_error_reporting(pdev);
        if (!rc)
@@ -12766,7 +12769,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
                NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 |
                NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_GRO |
                NETIF_F_RXHASH | NETIF_F_HW_VLAN_CTAG_TX;
-       if (!CHIP_IS_E1x(bp)) {
+       if (!chip_is_e1x) {
                dev->hw_features |= NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL |
                                    NETIF_F_GSO_IPIP | NETIF_F_GSO_SIT;
                dev->hw_enc_features =
index ff83c46bc38961561441814813f24d9b33da42ac..6befde61c203461a27ac0298d619f4f78b7c366e 100644 (file)
@@ -487,6 +487,7 @@ enum bcmgenet_stat_type {
        BCMGENET_STAT_MIB_TX,
        BCMGENET_STAT_RUNT,
        BCMGENET_STAT_MISC,
+       BCMGENET_STAT_SOFT,
 };
 
 struct bcmgenet_stats {
@@ -515,6 +516,7 @@ struct bcmgenet_stats {
 #define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX)
 #define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX)
 #define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT)
+#define STAT_GENET_SOFT_MIB(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_SOFT)
 
 #define STAT_GENET_MISC(str, m, offset) { \
        .stat_string = str, \
@@ -614,9 +616,9 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = {
                        UMAC_RBUF_OVFL_CNT),
        STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, UMAC_RBUF_ERR_CNT),
        STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT),
-       STAT_GENET_MIB_RX("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
-       STAT_GENET_MIB_RX("rx_dma_failed", mib.rx_dma_failed),
-       STAT_GENET_MIB_TX("tx_dma_failed", mib.tx_dma_failed),
+       STAT_GENET_SOFT_MIB("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
+       STAT_GENET_SOFT_MIB("rx_dma_failed", mib.rx_dma_failed),
+       STAT_GENET_SOFT_MIB("tx_dma_failed", mib.tx_dma_failed),
 };
 
 #define BCMGENET_STATS_LEN     ARRAY_SIZE(bcmgenet_gstrings_stats)
@@ -668,6 +670,7 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
                s = &bcmgenet_gstrings_stats[i];
                switch (s->type) {
                case BCMGENET_STAT_NETDEV:
+               case BCMGENET_STAT_SOFT:
                        continue;
                case BCMGENET_STAT_MIB_RX:
                case BCMGENET_STAT_MIB_TX:
@@ -971,13 +974,14 @@ static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv,
 }
 
 /* Unlocked version of the reclaim routine */
-static void __bcmgenet_tx_reclaim(struct net_device *dev,
-                                 struct bcmgenet_tx_ring *ring)
+static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
+                                         struct bcmgenet_tx_ring *ring)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
        int last_tx_cn, last_c_index, num_tx_bds;
        struct enet_cb *tx_cb_ptr;
        struct netdev_queue *txq;
+       unsigned int pkts_compl = 0;
        unsigned int bds_compl;
        unsigned int c_index;
 
@@ -1005,6 +1009,7 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev,
                tx_cb_ptr = ring->cbs + last_c_index;
                bds_compl = 0;
                if (tx_cb_ptr->skb) {
+                       pkts_compl++;
                        bds_compl = skb_shinfo(tx_cb_ptr->skb)->nr_frags + 1;
                        dev->stats.tx_bytes += tx_cb_ptr->skb->len;
                        dma_unmap_single(&dev->dev,
@@ -1028,23 +1033,45 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev,
                last_c_index &= (num_tx_bds - 1);
        }
 
-       if (ring->free_bds > (MAX_SKB_FRAGS + 1))
-               ring->int_disable(priv, ring);
-
-       if (netif_tx_queue_stopped(txq))
-               netif_tx_wake_queue(txq);
+       if (ring->free_bds > (MAX_SKB_FRAGS + 1)) {
+               if (netif_tx_queue_stopped(txq))
+                       netif_tx_wake_queue(txq);
+       }
 
        ring->c_index = c_index;
+
+       return pkts_compl;
 }
 
-static void bcmgenet_tx_reclaim(struct net_device *dev,
+static unsigned int bcmgenet_tx_reclaim(struct net_device *dev,
                                struct bcmgenet_tx_ring *ring)
 {
+       unsigned int released;
        unsigned long flags;
 
        spin_lock_irqsave(&ring->lock, flags);
-       __bcmgenet_tx_reclaim(dev, ring);
+       released = __bcmgenet_tx_reclaim(dev, ring);
        spin_unlock_irqrestore(&ring->lock, flags);
+
+       return released;
+}
+
+static int bcmgenet_tx_poll(struct napi_struct *napi, int budget)
+{
+       struct bcmgenet_tx_ring *ring =
+               container_of(napi, struct bcmgenet_tx_ring, napi);
+       unsigned int work_done = 0;
+
+       work_done = bcmgenet_tx_reclaim(ring->priv->dev, ring);
+
+       if (work_done == 0) {
+               napi_complete(napi);
+               ring->int_enable(ring->priv, ring);
+
+               return 0;
+       }
+
+       return budget;
 }
 
 static void bcmgenet_tx_reclaim_all(struct net_device *dev)
@@ -1302,10 +1329,8 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
        bcmgenet_tdma_ring_writel(priv, ring->index,
                                  ring->prod_index, TDMA_PROD_INDEX);
 
-       if (ring->free_bds <= (MAX_SKB_FRAGS + 1)) {
+       if (ring->free_bds <= (MAX_SKB_FRAGS + 1))
                netif_tx_stop_queue(txq);
-               ring->int_enable(priv, ring);
-       }
 
 out:
        spin_unlock_irqrestore(&ring->lock, flags);
@@ -1621,6 +1646,7 @@ static int init_umac(struct bcmgenet_priv *priv)
        struct device *kdev = &priv->pdev->dev;
        int ret;
        u32 reg, cpu_mask_clear;
+       int index;
 
        dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n");
 
@@ -1647,7 +1673,7 @@ static int init_umac(struct bcmgenet_priv *priv)
 
        bcmgenet_intr_disable(priv);
 
-       cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE;
+       cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_TXDMA_BDONE;
 
        dev_dbg(kdev, "%s:Enabling RXDMA_BDONE interrupt\n", __func__);
 
@@ -1674,6 +1700,10 @@ static int init_umac(struct bcmgenet_priv *priv)
 
        bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR);
 
+       for (index = 0; index < priv->hw_params->tx_queues; index++)
+               bcmgenet_intrl2_1_writel(priv, (1 << index),
+                                        INTRL2_CPU_MASK_CLEAR);
+
        /* Enable rx/tx engine.*/
        dev_dbg(kdev, "done init umac\n");
 
@@ -1693,6 +1723,8 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
        unsigned int first_bd;
 
        spin_lock_init(&ring->lock);
+       ring->priv = priv;
+       netif_napi_add(priv->dev, &ring->napi, bcmgenet_tx_poll, 64);
        ring->index = index;
        if (index == DESC_INDEX) {
                ring->queue = 0;
@@ -1738,6 +1770,17 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
                                  TDMA_WRITE_PTR);
        bcmgenet_tdma_ring_writel(priv, index, end_ptr * words_per_bd - 1,
                                  DMA_END_ADDR);
+
+       napi_enable(&ring->napi);
+}
+
+static void bcmgenet_fini_tx_ring(struct bcmgenet_priv *priv,
+                                 unsigned int index)
+{
+       struct bcmgenet_tx_ring *ring = &priv->tx_rings[index];
+
+       napi_disable(&ring->napi);
+       netif_napi_del(&ring->napi);
 }
 
 /* Initialize a RDMA ring */
@@ -1907,7 +1950,7 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv)
        return ret;
 }
 
-static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
+static void __bcmgenet_fini_dma(struct bcmgenet_priv *priv)
 {
        int i;
 
@@ -1926,6 +1969,18 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
        kfree(priv->tx_cbs);
 }
 
+static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
+{
+       int i;
+
+       bcmgenet_fini_tx_ring(priv, DESC_INDEX);
+
+       for (i = 0; i < priv->hw_params->tx_queues; i++)
+               bcmgenet_fini_tx_ring(priv, i);
+
+       __bcmgenet_fini_dma(priv);
+}
+
 /* init_edma: Initialize DMA control register */
 static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
 {
@@ -1952,7 +2007,7 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
        priv->tx_cbs = kcalloc(priv->num_tx_bds, sizeof(struct enet_cb),
                               GFP_KERNEL);
        if (!priv->tx_cbs) {
-               bcmgenet_fini_dma(priv);
+               __bcmgenet_fini_dma(priv);
                return -ENOMEM;
        }
 
@@ -1975,9 +2030,6 @@ static int bcmgenet_poll(struct napi_struct *napi, int budget)
                        struct bcmgenet_priv, napi);
        unsigned int work_done;
 
-       /* tx reclaim */
-       bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]);
-
        work_done = bcmgenet_desc_rx(priv, budget);
 
        /* Advancing our consumer index*/
@@ -2022,28 +2074,34 @@ static void bcmgenet_irq_task(struct work_struct *work)
 static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
 {
        struct bcmgenet_priv *priv = dev_id;
+       struct bcmgenet_tx_ring *ring;
        unsigned int index;
 
        /* Save irq status for bottom-half processing. */
        priv->irq1_stat =
                bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
-               ~priv->int1_mask;
+               ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS);
        /* clear interrupts */
        bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
 
        netif_dbg(priv, intr, priv->dev,
                  "%s: IRQ=0x%x\n", __func__, priv->irq1_stat);
+
        /* Check the MBDONE interrupts.
         * packet is done, reclaim descriptors
         */
-       if (priv->irq1_stat & 0x0000ffff) {
-               index = 0;
-               for (index = 0; index < 16; index++) {
-                       if (priv->irq1_stat & (1 << index))
-                               bcmgenet_tx_reclaim(priv->dev,
-                                                   &priv->tx_rings[index]);
+       for (index = 0; index < priv->hw_params->tx_queues; index++) {
+               if (!(priv->irq1_stat & BIT(index)))
+                       continue;
+
+               ring = &priv->tx_rings[index];
+
+               if (likely(napi_schedule_prep(&ring->napi))) {
+                       ring->int_disable(priv, ring);
+                       __napi_schedule(&ring->napi);
                }
        }
+
        return IRQ_HANDLED;
 }
 
@@ -2075,8 +2133,12 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
        }
        if (priv->irq0_stat &
                        (UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE)) {
-               /* Tx reclaim */
-               bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]);
+               struct bcmgenet_tx_ring *ring = &priv->tx_rings[DESC_INDEX];
+
+               if (likely(napi_schedule_prep(&ring->napi))) {
+                       ring->int_disable(priv, ring);
+                       __napi_schedule(&ring->napi);
+               }
        }
        if (priv->irq0_stat & (UMAC_IRQ_PHY_DET_R |
                                UMAC_IRQ_PHY_DET_F |
index b36ddec0cc0a3c5d1c64f9c2818a4b44464c41f8..0d370d168aee0ea24924fbc3afc011f3a8697841 100644 (file)
@@ -520,6 +520,7 @@ struct bcmgenet_hw_params {
 
 struct bcmgenet_tx_ring {
        spinlock_t      lock;           /* ring lock */
+       struct napi_struct napi;        /* NAPI per tx queue */
        unsigned int    index;          /* ring index */
        unsigned int    queue;          /* queue index */
        struct enet_cb  *cbs;           /* tx ring buffer control block*/
@@ -534,6 +535,7 @@ struct bcmgenet_tx_ring {
                           struct bcmgenet_tx_ring *);
        void (*int_disable)(struct bcmgenet_priv *priv,
                            struct bcmgenet_tx_ring *);
+       struct bcmgenet_priv *priv;
 };
 
 /* device context */
index 149a0d70c10883f3f769904ef6ae2ca6b2f66f8e..b97122926d3aa91210a8945d45f268d370c86ee4 100644 (file)
@@ -73,15 +73,17 @@ int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
                return -EINVAL;
 
+       reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
        if (wol->wolopts & WAKE_MAGICSECURE) {
                bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
                                     UMAC_MPD_PW_MS);
                bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
                                     UMAC_MPD_PW_LS);
-               reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
                reg |= MPD_PW_EN;
-               bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+       } else {
+               reg &= ~MPD_PW_EN;
        }
+       bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
        /* Flag the device and relevant IRQ as wakeup capable */
        if (wol->wolopts) {
index ad76b8e35a00e188e39d00f4c5f70d97c3df5363..81d41539fcbab8e015d28e4b7729bc4812f60f0a 100644 (file)
@@ -2113,17 +2113,17 @@ static const struct net_device_ops macb_netdev_ops = {
 };
 
 #if defined(CONFIG_OF)
-static struct macb_config pc302gem_config = {
+static const struct macb_config pc302gem_config = {
        .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
        .dma_burst_length = 16,
 };
 
-static struct macb_config sama5d3_config = {
+static const struct macb_config sama5d3_config = {
        .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
        .dma_burst_length = 16,
 };
 
-static struct macb_config sama5d4_config = {
+static const struct macb_config sama5d4_config = {
        .caps = 0,
        .dma_burst_length = 4,
 };
@@ -2154,7 +2154,7 @@ static void macb_configure_caps(struct macb *bp)
        if (bp->pdev->dev.of_node) {
                match = of_match_node(macb_dt_ids, bp->pdev->dev.of_node);
                if (match && match->data) {
-                       config = (const struct macb_config *)match->data;
+                       config = match->data;
 
                        bp->caps = config->caps;
                        /*
index 31dc080f2437b6b02dde206b1e7c5343100fdde9..ff85619a97325fc0f1fa64a8896cbb8cc417d3cc 100644 (file)
 
 /* Bitfields in MID */
 #define MACB_IDNUM_OFFSET                      16
-#define MACB_IDNUM_SIZE                                16
+#define MACB_IDNUM_SIZE                                12
 #define MACB_REV_OFFSET                                0
 #define MACB_REV_SIZE                          16
 
index 9062a843424688beabaa21e46b3e210387658c81..c308429dd9c7fa0aebf2cee3b951f71f3863d939 100644 (file)
@@ -35,10 +35,10 @@ static inline unsigned int ipv6_clip_hash(struct clip_tbl *d, const u32 *key)
 }
 
 static unsigned int clip_addr_hash(struct clip_tbl *ctbl, const u32 *addr,
-                                  int addr_len)
+                                  u8 v6)
 {
-       return addr_len == 4 ? ipv4_clip_hash(ctbl, addr) :
-                               ipv6_clip_hash(ctbl, addr);
+       return v6 ? ipv6_clip_hash(ctbl, addr) :
+                       ipv4_clip_hash(ctbl, addr);
 }
 
 static int clip6_get_mbox(const struct net_device *dev,
@@ -78,23 +78,22 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
        struct clip_entry *ce, *cte;
        u32 *addr = (u32 *)lip;
        int hash;
-       int addr_len;
-       int ret = 0;
+       int ret = -1;
 
        if (!ctbl)
                return 0;
 
-       if (v6)
-               addr_len = 16;
-       else
-               addr_len = 4;
-
-       hash = clip_addr_hash(ctbl, addr, addr_len);
+       hash = clip_addr_hash(ctbl, addr, v6);
 
        read_lock_bh(&ctbl->lock);
        list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
-               if (addr_len == cte->addr_len &&
-                   memcmp(lip, cte->addr, cte->addr_len) == 0) {
+               if (cte->addr6.sin6_family == AF_INET6 && v6)
+                       ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr,
+                                    sizeof(struct in6_addr));
+               else if (cte->addr.sin_family == AF_INET && !v6)
+                       ret = memcmp(lip, (char *)(&cte->addr.sin_addr),
+                                    sizeof(struct in_addr));
+               if (!ret) {
                        ce = cte;
                        read_unlock_bh(&ctbl->lock);
                        goto found;
@@ -111,15 +110,20 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
                spin_lock_init(&ce->lock);
                atomic_set(&ce->refcnt, 0);
                atomic_dec(&ctbl->nfree);
-               ce->addr_len = addr_len;
-               memcpy(ce->addr, lip, addr_len);
                list_add_tail(&ce->list, &ctbl->hash_list[hash]);
                if (v6) {
+                       ce->addr6.sin6_family = AF_INET6;
+                       memcpy(ce->addr6.sin6_addr.s6_addr,
+                              lip, sizeof(struct in6_addr));
                        ret = clip6_get_mbox(dev, (const struct in6_addr *)lip);
                        if (ret) {
                                write_unlock_bh(&ctbl->lock);
                                return ret;
                        }
+               } else {
+                       ce->addr.sin_family = AF_INET;
+                       memcpy((char *)(&ce->addr.sin_addr), lip,
+                              sizeof(struct in_addr));
                }
        } else {
                write_unlock_bh(&ctbl->lock);
@@ -140,19 +144,19 @@ void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6)
        struct clip_entry *ce, *cte;
        u32 *addr = (u32 *)lip;
        int hash;
-       int addr_len;
-
-       if (v6)
-               addr_len = 16;
-       else
-               addr_len = 4;
+       int ret = -1;
 
-       hash = clip_addr_hash(ctbl, addr, addr_len);
+       hash = clip_addr_hash(ctbl, addr, v6);
 
        read_lock_bh(&ctbl->lock);
        list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
-               if (addr_len == cte->addr_len &&
-                   memcmp(lip, cte->addr, cte->addr_len) == 0) {
+               if (cte->addr6.sin6_family == AF_INET6 && v6)
+                       ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr,
+                                    sizeof(struct in6_addr));
+               else if (cte->addr.sin_family == AF_INET && !v6)
+                       ret = memcmp(lip, (char *)(&cte->addr.sin_addr),
+                                    sizeof(struct in_addr));
+               if (!ret) {
                        ce = cte;
                        read_unlock_bh(&ctbl->lock);
                        goto found;
@@ -249,10 +253,7 @@ int clip_tbl_show(struct seq_file *seq, void *v)
        for (i = 0 ; i < ctbl->clipt_size;  ++i) {
                list_for_each_entry(ce, &ctbl->hash_list[i], list) {
                        ip[0] = '\0';
-                       if (ce->addr_len == 16)
-                               sprintf(ip, "%pI6c", ce->addr);
-                       else
-                               sprintf(ip, "%pI4c", ce->addr);
+                       sprintf(ip, "%pISc", &ce->addr);
                        seq_printf(seq, "%-25s   %u\n", ip,
                                   atomic_read(&ce->refcnt));
                }
index 2eaba0161cf8104eb8cbf9756112174fd1275b38..35eb43c6bcbbe37e5f934a767154bc4f4fe2f5c7 100644 (file)
@@ -14,8 +14,10 @@ struct clip_entry {
        spinlock_t lock;        /* Hold while modifying clip reference */
        atomic_t refcnt;
        struct list_head list;
-       u32 addr[4];
-       int addr_len;
+       union {
+               struct sockaddr_in addr;
+               struct sockaddr_in6 addr6;
+       };
 };
 
 struct clip_tbl {
index d6cda17efe6ef475a5579d8248e01a3158bbc272..97842d03675b327d65f564b351f24d12bf72c18b 100644 (file)
@@ -1103,7 +1103,7 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
 #define T4_MEMORY_WRITE        0
 #define T4_MEMORY_READ 1
 int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, u32 len,
-                __be32 *buf, int dir);
+                void *buf, int dir);
 static inline int t4_memory_write(struct adapter *adap, int mtype, u32 addr,
                                  u32 len, __be32 *buf)
 {
index 4d643b65265e8ee0ad12ed886cbb2b77b9d2557b..1abdfa123c6cf8d42a4788400539b40b05ed84eb 100644 (file)
@@ -449,7 +449,7 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
  *     @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
  *     @addr: address within indicated memory type
  *     @len: amount of memory to transfer
- *     @buf: host memory buffer
+ *     @hbuf: host memory buffer
  *     @dir: direction of transfer T4_MEMORY_READ (1) or T4_MEMORY_WRITE (0)
  *
  *     Reads/writes an [almost] arbitrary memory region in the firmware: the
@@ -460,15 +460,17 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
  *     caller's responsibility to perform appropriate byte order conversions.
  */
 int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
-                u32 len, __be32 *buf, int dir)
+                u32 len, void *hbuf, int dir)
 {
        u32 pos, offset, resid, memoffset;
        u32 edc_size, mc_size, win_pf, mem_reg, mem_aperture, mem_base;
+       u32 *buf;
 
        /* Argument sanity checks ...
         */
-       if (addr & 0x3)
+       if (addr & 0x3 || (uintptr_t)hbuf & 0x3)
                return -EINVAL;
+       buf = (u32 *)hbuf;
 
        /* It's convenient to be able to handle lengths which aren't a
         * multiple of 32-bits because we often end up transferring files to
@@ -532,14 +534,45 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
 
        /* Transfer data to/from the adapter as long as there's an integral
         * number of 32-bit transfers to complete.
+        *
+        * A note on Endianness issues:
+        *
+        * The "register" reads and writes below from/to the PCI-E Memory
+        * Window invoke the standard adapter Big-Endian to PCI-E Link
+        * Little-Endian "swizzel."  As a result, if we have the following
+        * data in adapter memory:
+        *
+        *     Memory:  ... | b0 | b1 | b2 | b3 | ...
+        *     Address:      i+0  i+1  i+2  i+3
+        *
+        * Then a read of the adapter memory via the PCI-E Memory Window
+        * will yield:
+        *
+        *     x = readl(i)
+        *         31                  0
+        *         [ b3 | b2 | b1 | b0 ]
+        *
+        * If this value is stored into local memory on a Little-Endian system
+        * it will show up correctly in local memory as:
+        *
+        *     ( ..., b0, b1, b2, b3, ... )
+        *
+        * But on a Big-Endian system, the store will show up in memory
+        * incorrectly swizzled as:
+        *
+        *     ( ..., b3, b2, b1, b0, ... )
+        *
+        * So we need to account for this in the reads and writes to the
+        * PCI-E Memory Window below by undoing the register read/write
+        * swizzels.
         */
        while (len > 0) {
                if (dir == T4_MEMORY_READ)
-                       *buf++ = (__force __be32) t4_read_reg(adap,
-                                                       mem_base + offset);
+                       *buf++ = le32_to_cpu((__force __le32)t4_read_reg(adap,
+                                               mem_base + offset));
                else
                        t4_write_reg(adap, mem_base + offset,
-                                    (__force u32) *buf++);
+                                    (__force u32)cpu_to_le32(*buf++));
                offset += sizeof(__be32);
                len -= sizeof(__be32);
 
@@ -568,15 +601,16 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
         */
        if (resid) {
                union {
-                       __be32 word;
+                       u32 word;
                        char byte[4];
                } last;
                unsigned char *bp;
                int i;
 
                if (dir == T4_MEMORY_READ) {
-                       last.word = (__force __be32) t4_read_reg(adap,
-                                                       mem_base + offset);
+                       last.word = le32_to_cpu(
+                                       (__force __le32)t4_read_reg(adap,
+                                               mem_base + offset));
                        for (bp = (unsigned char *)buf, i = resid; i < 4; i++)
                                bp[i] = last.byte[i];
                } else {
@@ -584,7 +618,7 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
                        for (i = resid; i < 4; i++)
                                last.byte[i] = 0;
                        t4_write_reg(adap, mem_base + offset,
-                                    (__force u32) last.word);
+                                    (__force u32)cpu_to_le32(last.word));
                }
        }
 
@@ -1086,7 +1120,7 @@ int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info,
                }
 
                /* Installed successfully, update the cached header too. */
-               memcpy(card_fw, fs_fw, sizeof(*card_fw));
+               *card_fw = *fs_fw;
                card_fw_usable = 1;
                *reset = 0;     /* already reset as part of load_fw */
        }
index 9cbe038a388ea62a6f4552e7f088dc5816dc5b5c..a5179bfcdc2c1b6124a92f33f9c5f57363751a02 100644 (file)
@@ -272,8 +272,8 @@ static irqreturn_t enic_isr_legacy(int irq, void *data)
        }
 
        if (ENIC_TEST_INTR(pba, notify_intr)) {
-               vnic_intr_return_all_credits(&enic->intr[notify_intr]);
                enic_notify_check(enic);
+               vnic_intr_return_all_credits(&enic->intr[notify_intr]);
        }
 
        if (ENIC_TEST_INTR(pba, err_intr)) {
@@ -346,8 +346,8 @@ static irqreturn_t enic_isr_msix_notify(int irq, void *data)
        struct enic *enic = data;
        unsigned int intr = enic_msix_notify_intr(enic);
 
-       vnic_intr_return_all_credits(&enic->intr[intr]);
        enic_notify_check(enic);
+       vnic_intr_return_all_credits(&enic->intr[intr]);
 
        return IRQ_HANDLED;
 }
index 3b42556f7f8d66929f1435445df06072c65ae6aa..ed41559bae771b8d58e49f21a46f7a79d9f20cac 100644 (file)
@@ -589,7 +589,7 @@ static void tulip_tx_timeout(struct net_device *dev)
                               (unsigned int)tp->rx_ring[i].buffer1,
                               (unsigned int)tp->rx_ring[i].buffer2,
                               buf[0], buf[1], buf[2]);
-                       for (j = 0; buf[j] != 0xee && j < 1600; j++)
+                       for (j = 0; ((j < 1600) && buf[j] != 0xee); j++)
                                if (j < 100)
                                        pr_cont(" %02x", buf[j]);
                        pr_cont(" j=%d\n", j);
index 27de37aa90afe12b2d564d87c9b13246160d39aa..27b9fe99a9bdfa4eddb70aaa9749eaef6bdd3518 100644 (file)
@@ -354,6 +354,7 @@ struct be_vf_cfg {
        u16 vlan_tag;
        u32 tx_rate;
        u32 plink_tracking;
+       u32 privileges;
 };
 
 enum vf_state {
@@ -423,6 +424,7 @@ struct be_adapter {
 
        u8 __iomem *csr;        /* CSR BAR used only for BE2/3 */
        u8 __iomem *db;         /* Door Bell */
+       u8 __iomem *pcicfg;     /* On SH,BEx only. Shadow of PCI config space */
 
        struct mutex mbox_lock; /* For serializing mbox cmds to BE card */
        struct be_dma_mem mbox_mem;
index 36916cfa70f9a7d31f36b7d80135e61f854a499a..7f05f309e93596778851fb280fa4c8bd068828c3 100644 (file)
@@ -1902,15 +1902,11 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,
 {
        int num_eqs, i = 0;
 
-       if (lancer_chip(adapter) && num > 8) {
-               while (num) {
-                       num_eqs = min(num, 8);
-                       __be_cmd_modify_eqd(adapter, &set_eqd[i], num_eqs);
-                       i += num_eqs;
-                       num -= num_eqs;
-               }
-       } else {
-               __be_cmd_modify_eqd(adapter, set_eqd, num);
+       while (num) {
+               num_eqs = min(num, 8);
+               __be_cmd_modify_eqd(adapter, &set_eqd[i], num_eqs);
+               i += num_eqs;
+               num -= num_eqs;
        }
 
        return 0;
@@ -1918,7 +1914,7 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,
 
 /* Uses sycnhronous mcc */
 int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
-                      u32 num)
+                      u32 num, u32 domain)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_vlan_config *req;
@@ -1936,6 +1932,7 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
        be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                               OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req),
                               wrb, NULL);
+       req->hdr.domain = domain;
 
        req->interface_id = if_id;
        req->untagged = BE_IF_FLAGS_UNTAGGED & be_if_cap_flags(adapter) ? 1 : 0;
index db761e8e42a3224486ced01238f9fb6b61ad3579..a7634a3f052ac02786baa7e63e764d86262720a9 100644 (file)
@@ -2256,7 +2256,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
 int be_cmd_get_fw_ver(struct be_adapter *adapter);
 int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *, int num);
 int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
-                      u32 num);
+                      u32 num, u32 domain);
 int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status);
 int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc);
 int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc);
index 0a816859aca507c3e762aeebbf6d0601e3529aec..e6b790f0d9dc1ebfe6103a1549e84cf058522027 100644 (file)
@@ -1171,7 +1171,7 @@ static int be_vid_config(struct be_adapter *adapter)
        for_each_set_bit(i, adapter->vids, VLAN_N_VID)
                vids[num++] = cpu_to_le16(i);
 
-       status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num);
+       status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num, 0);
        if (status) {
                dev_err(dev, "Setting HW VLAN filtering failed\n");
                /* Set to VLAN promisc mode as setting VLAN filter failed */
@@ -1380,11 +1380,67 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
        return 0;
 }
 
+static int be_set_vf_tvt(struct be_adapter *adapter, int vf, u16 vlan)
+{
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
+       u16 vids[BE_NUM_VLANS_SUPPORTED];
+       int vf_if_id = vf_cfg->if_handle;
+       int status;
+
+       /* Enable Transparent VLAN Tagging */
+       status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, vf_if_id, 0);
+       if (status)
+               return status;
+
+       /* Clear pre-programmed VLAN filters on VF if any, if TVT is enabled */
+       vids[0] = 0;
+       status = be_cmd_vlan_config(adapter, vf_if_id, vids, 1, vf + 1);
+       if (!status)
+               dev_info(&adapter->pdev->dev,
+                        "Cleared guest VLANs on VF%d", vf);
+
+       /* After TVT is enabled, disallow VFs to program VLAN filters */
+       if (vf_cfg->privileges & BE_PRIV_FILTMGMT) {
+               status = be_cmd_set_fn_privileges(adapter, vf_cfg->privileges &
+                                                 ~BE_PRIV_FILTMGMT, vf + 1);
+               if (!status)
+                       vf_cfg->privileges &= ~BE_PRIV_FILTMGMT;
+       }
+       return 0;
+}
+
+static int be_clear_vf_tvt(struct be_adapter *adapter, int vf)
+{
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
+       struct device *dev = &adapter->pdev->dev;
+       int status;
+
+       /* Reset Transparent VLAN Tagging. */
+       status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID, vf + 1,
+                                      vf_cfg->if_handle, 0);
+       if (status)
+               return status;
+
+       /* Allow VFs to program VLAN filtering */
+       if (!(vf_cfg->privileges & BE_PRIV_FILTMGMT)) {
+               status = be_cmd_set_fn_privileges(adapter, vf_cfg->privileges |
+                                                 BE_PRIV_FILTMGMT, vf + 1);
+               if (!status) {
+                       vf_cfg->privileges |= BE_PRIV_FILTMGMT;
+                       dev_info(dev, "VF%d: FILTMGMT priv enabled", vf);
+               }
+       }
+
+       dev_info(dev,
+                "Disable/re-enable i/f in VM to clear Transparent VLAN tag");
+       return 0;
+}
+
 static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
        struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
-       int status = 0;
+       int status;
 
        if (!sriov_enabled(adapter))
                return -EPERM;
@@ -1394,24 +1450,19 @@ static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
 
        if (vlan || qos) {
                vlan |= qos << VLAN_PRIO_SHIFT;
-               if (vf_cfg->vlan_tag != vlan)
-                       status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
-                                                      vf_cfg->if_handle, 0);
+               status = be_set_vf_tvt(adapter, vf, vlan);
        } else {
-               /* Reset Transparent Vlan Tagging. */
-               status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
-                                              vf + 1, vf_cfg->if_handle, 0);
+               status = be_clear_vf_tvt(adapter, vf);
        }
 
        if (status) {
                dev_err(&adapter->pdev->dev,
-                       "VLAN %d config on VF %d failed : %#x\n", vlan,
-                       vf, status);
+                       "VLAN %d config on VF %d failed : %#x\n", vlan, vf,
+                       status);
                return be_cmd_status(status);
        }
 
        vf_cfg->vlan_tag = vlan;
-
        return 0;
 }
 
@@ -2772,14 +2823,12 @@ void be_detect_error(struct be_adapter *adapter)
                        }
                }
        } else {
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_LOW, &ue_lo);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_HIGH, &ue_hi);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_LOW_MASK, &ue_lo_mask);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_HI_MASK, &ue_hi_mask);
+               ue_lo = ioread32(adapter->pcicfg + PCICFG_UE_STATUS_LOW);
+               ue_hi = ioread32(adapter->pcicfg + PCICFG_UE_STATUS_HIGH);
+               ue_lo_mask = ioread32(adapter->pcicfg +
+                                     PCICFG_UE_STATUS_LOW_MASK);
+               ue_hi_mask = ioread32(adapter->pcicfg +
+                                     PCICFG_UE_STATUS_HI_MASK);
 
                ue_lo = (ue_lo & ~ue_lo_mask);
                ue_hi = (ue_hi & ~ue_hi_mask);
@@ -3339,7 +3388,6 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
                        u32 cap_flags, u32 vf)
 {
        u32 en_flags;
-       int status;
 
        en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                   BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
@@ -3347,10 +3395,7 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
 
        en_flags &= cap_flags;
 
-       status = be_cmd_if_create(adapter, cap_flags, en_flags,
-                                 if_handle, vf);
-
-       return status;
+       return be_cmd_if_create(adapter, cap_flags, en_flags, if_handle, vf);
 }
 
 static int be_vfs_if_create(struct be_adapter *adapter)
@@ -3368,8 +3413,13 @@ static int be_vfs_if_create(struct be_adapter *adapter)
                if (!BE3_chip(adapter)) {
                        status = be_cmd_get_profile_config(adapter, &res,
                                                           vf + 1);
-                       if (!status)
+                       if (!status) {
                                cap_flags = res.if_cap_flags;
+                               /* Prevent VFs from enabling VLAN promiscuous
+                                * mode
+                                */
+                               cap_flags &= ~BE_IF_FLAGS_VLAN_PROMISCUOUS;
+                       }
                }
 
                status = be_if_create(adapter, &vf_cfg->if_handle,
@@ -3403,7 +3453,6 @@ static int be_vf_setup(struct be_adapter *adapter)
        struct device *dev = &adapter->pdev->dev;
        struct be_vf_cfg *vf_cfg;
        int status, old_vfs, vf;
-       u32 privileges;
 
        old_vfs = pci_num_vf(adapter->pdev);
 
@@ -3433,15 +3482,18 @@ static int be_vf_setup(struct be_adapter *adapter)
 
        for_all_vfs(adapter, vf_cfg, vf) {
                /* Allow VFs to programs MAC/VLAN filters */
-               status = be_cmd_get_fn_privileges(adapter, &privileges, vf + 1);
-               if (!status && !(privileges & BE_PRIV_FILTMGMT)) {
+               status = be_cmd_get_fn_privileges(adapter, &vf_cfg->privileges,
+                                                 vf + 1);
+               if (!status && !(vf_cfg->privileges & BE_PRIV_FILTMGMT)) {
                        status = be_cmd_set_fn_privileges(adapter,
-                                                         privileges |
+                                                         vf_cfg->privileges |
                                                          BE_PRIV_FILTMGMT,
                                                          vf + 1);
-                       if (!status)
+                       if (!status) {
+                               vf_cfg->privileges |= BE_PRIV_FILTMGMT;
                                dev_info(dev, "VF%d has FILTMGMT privilege\n",
                                         vf);
+                       }
                }
 
                /* Allow full available bandwidth */
@@ -4820,24 +4872,37 @@ static int be_roce_map_pci_bars(struct be_adapter *adapter)
 
 static int be_map_pci_bars(struct be_adapter *adapter)
 {
+       struct pci_dev *pdev = adapter->pdev;
        u8 __iomem *addr;
 
        if (BEx_chip(adapter) && be_physfn(adapter)) {
-               adapter->csr = pci_iomap(adapter->pdev, 2, 0);
+               adapter->csr = pci_iomap(pdev, 2, 0);
                if (!adapter->csr)
                        return -ENOMEM;
        }
 
-       addr = pci_iomap(adapter->pdev, db_bar(adapter), 0);
+       addr = pci_iomap(pdev, db_bar(adapter), 0);
        if (!addr)
                goto pci_map_err;
        adapter->db = addr;
 
+       if (skyhawk_chip(adapter) || BEx_chip(adapter)) {
+               if (be_physfn(adapter)) {
+                       /* PCICFG is the 2nd BAR in BE2 */
+                       addr = pci_iomap(pdev, BE2_chip(adapter) ? 1 : 0, 0);
+                       if (!addr)
+                               goto pci_map_err;
+                       adapter->pcicfg = addr;
+               } else {
+                       adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
+               }
+       }
+
        be_roce_map_pci_bars(adapter);
        return 0;
 
 pci_map_err:
-       dev_err(&adapter->pdev->dev, "Error in mapping PCI BARs\n");
+       dev_err(&pdev->dev, "Error in mapping PCI BARs\n");
        be_unmap_pci_bars(adapter);
        return -ENOMEM;
 }
index 9bb6220663b21a505f2332f028ce3a1e13b77f86..78e1ce09b1ab1deadad177472593e020a8f9d3c2 100644 (file)
@@ -1189,13 +1189,12 @@ static void
 fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
 {
        struct  fec_enet_private *fep;
-       struct bufdesc *bdp, *bdp_t;
+       struct bufdesc *bdp;
        unsigned short status;
        struct  sk_buff *skb;
        struct fec_enet_priv_tx_q *txq;
        struct netdev_queue *nq;
        int     index = 0;
-       int     i, bdnum;
        int     entries_free;
 
        fep = netdev_priv(ndev);
@@ -1216,29 +1215,18 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
                if (bdp == txq->cur_tx)
                        break;
 
-               bdp_t = bdp;
-               bdnum = 1;
-               index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep);
-               skb = txq->tx_skbuff[index];
-               while (!skb) {
-                       bdp_t = fec_enet_get_nextdesc(bdp_t, fep, queue_id);
-                       index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep);
-                       skb = txq->tx_skbuff[index];
-                       bdnum++;
-               }
-               if (skb_shinfo(skb)->nr_frags &&
-                   (status = bdp_t->cbd_sc) & BD_ENET_TX_READY)
-                       break;
+               index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 
-               for (i = 0; i < bdnum; i++) {
-                       if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
-                               dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
-                                                bdp->cbd_datlen, DMA_TO_DEVICE);
-                       bdp->cbd_bufaddr = 0;
-                       if (i < bdnum - 1)
-                               bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
-               }
+               skb = txq->tx_skbuff[index];
                txq->tx_skbuff[index] = NULL;
+               if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
+                       dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
+                                       bdp->cbd_datlen, DMA_TO_DEVICE);
+               bdp->cbd_bufaddr = 0;
+               if (!skb) {
+                       bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
+                       continue;
+               }
 
                /* Check for errors. */
                if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
@@ -1479,8 +1467,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 
                        vlan_packet_rcvd = true;
 
-                       skb_copy_to_linear_data_offset(skb, VLAN_HLEN,
-                                                      data, (2 * ETH_ALEN));
+                       memmove(skb->data + VLAN_HLEN, data, ETH_ALEN * 2);
                        skb_pull(skb, VLAN_HLEN);
                }
 
@@ -1597,7 +1584,7 @@ fec_enet_interrupt(int irq, void *dev_id)
        writel(int_events, fep->hwp + FEC_IEVENT);
        fec_enet_collect_events(fep, int_events);
 
-       if (fep->work_tx || fep->work_rx) {
+       if ((fep->work_tx || fep->work_rx) && fep->link) {
                ret = IRQ_HANDLED;
 
                if (napi_schedule_prep(&fep->napi)) {
@@ -3383,7 +3370,6 @@ fec_drv_remove(struct platform_device *pdev)
                regulator_disable(fep->reg_phy);
        if (fep->ptp_clock)
                ptp_clock_unregister(fep->ptp_clock);
-       fec_enet_clk_enable(ndev, false);
        of_node_put(fep->phy_node);
        free_netdev(ndev);
 
index 43df78882e484e065706bd04c322fa8276d4c424..7bf3682cdf478b1597cf04e071b525eed31adb69 100644 (file)
@@ -747,6 +747,18 @@ static int gfar_parse_group(struct device_node *np,
        return 0;
 }
 
+static int gfar_of_group_count(struct device_node *np)
+{
+       struct device_node *child;
+       int num = 0;
+
+       for_each_available_child_of_node(np, child)
+               if (!of_node_cmp(child->name, "queue-group"))
+                       num++;
+
+       return num;
+}
+
 static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 {
        const char *model;
@@ -784,7 +796,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
                num_rx_qs = 1;
        } else { /* MQ_MG_MODE */
                /* get the actual number of supported groups */
-               unsigned int num_grps = of_get_available_child_count(np);
+               unsigned int num_grps = gfar_of_group_count(np);
 
                if (num_grps == 0 || num_grps > MAXGROUPS) {
                        dev_err(&ofdev->dev, "Invalid # of int groups(%d)\n",
@@ -851,7 +863,10 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 
        /* Parse and initialize group specific information */
        if (priv->mode == MQ_MG_MODE) {
-               for_each_child_of_node(np, child) {
+               for_each_available_child_of_node(np, child) {
+                       if (of_node_cmp(child->name, "queue-group"))
+                               continue;
+
                        err = gfar_parse_group(child, priv, model);
                        if (err)
                                goto err_grp_init;
@@ -3162,8 +3177,8 @@ static void adjust_link(struct net_device *dev)
        struct phy_device *phydev = priv->phydev;
 
        if (unlikely(phydev->link != priv->oldlink ||
-                    phydev->duplex != priv->oldduplex ||
-                    phydev->speed != priv->oldspeed))
+                    (phydev->link && (phydev->duplex != priv->oldduplex ||
+                                      phydev->speed != priv->oldspeed))))
                gfar_update_link_state(priv);
 }
 
index e8a1adb7a96255bf8da1baa87b29514527c2764d..c05e50759621137fa3f9749a55c347381d54ed55 100644 (file)
@@ -3262,6 +3262,139 @@ static void ehea_remove_device_sysfs(struct platform_device *dev)
        device_remove_file(&dev->dev, &dev_attr_remove_port);
 }
 
+static int ehea_reboot_notifier(struct notifier_block *nb,
+                               unsigned long action, void *unused)
+{
+       if (action == SYS_RESTART) {
+               pr_info("Reboot: freeing all eHEA resources\n");
+               ibmebus_unregister_driver(&ehea_driver);
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block ehea_reboot_nb = {
+       .notifier_call = ehea_reboot_notifier,
+};
+
+static int ehea_mem_notifier(struct notifier_block *nb,
+                            unsigned long action, void *data)
+{
+       int ret = NOTIFY_BAD;
+       struct memory_notify *arg = data;
+
+       mutex_lock(&dlpar_mem_lock);
+
+       switch (action) {
+       case MEM_CANCEL_OFFLINE:
+               pr_info("memory offlining canceled");
+               /* Fall through: re-add canceled memory block */
+
+       case MEM_ONLINE:
+               pr_info("memory is going online");
+               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
+               if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
+                       goto out_unlock;
+               ehea_rereg_mrs();
+               break;
+
+       case MEM_GOING_OFFLINE:
+               pr_info("memory is going offline");
+               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
+               if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
+                       goto out_unlock;
+               ehea_rereg_mrs();
+               break;
+
+       default:
+               break;
+       }
+
+       ehea_update_firmware_handles();
+       ret = NOTIFY_OK;
+
+out_unlock:
+       mutex_unlock(&dlpar_mem_lock);
+       return ret;
+}
+
+static struct notifier_block ehea_mem_nb = {
+       .notifier_call = ehea_mem_notifier,
+};
+
+static void ehea_crash_handler(void)
+{
+       int i;
+
+       if (ehea_fw_handles.arr)
+               for (i = 0; i < ehea_fw_handles.num_entries; i++)
+                       ehea_h_free_resource(ehea_fw_handles.arr[i].adh,
+                                            ehea_fw_handles.arr[i].fwh,
+                                            FORCE_FREE);
+
+       if (ehea_bcmc_regs.arr)
+               for (i = 0; i < ehea_bcmc_regs.num_entries; i++)
+                       ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh,
+                                             ehea_bcmc_regs.arr[i].port_id,
+                                             ehea_bcmc_regs.arr[i].reg_type,
+                                             ehea_bcmc_regs.arr[i].macaddr,
+                                             0, H_DEREG_BCMC);
+}
+
+static atomic_t ehea_memory_hooks_registered;
+
+/* Register memory hooks on probe of first adapter */
+static int ehea_register_memory_hooks(void)
+{
+       int ret = 0;
+
+       if (atomic_inc_and_test(&ehea_memory_hooks_registered))
+               return 0;
+
+       ret = ehea_create_busmap();
+       if (ret) {
+               pr_info("ehea_create_busmap failed\n");
+               goto out;
+       }
+
+       ret = register_reboot_notifier(&ehea_reboot_nb);
+       if (ret) {
+               pr_info("register_reboot_notifier failed\n");
+               goto out;
+       }
+
+       ret = register_memory_notifier(&ehea_mem_nb);
+       if (ret) {
+               pr_info("register_memory_notifier failed\n");
+               goto out2;
+       }
+
+       ret = crash_shutdown_register(ehea_crash_handler);
+       if (ret) {
+               pr_info("crash_shutdown_register failed\n");
+               goto out3;
+       }
+
+       return 0;
+
+out3:
+       unregister_memory_notifier(&ehea_mem_nb);
+out2:
+       unregister_reboot_notifier(&ehea_reboot_nb);
+out:
+       return ret;
+}
+
+static void ehea_unregister_memory_hooks(void)
+{
+       if (atomic_read(&ehea_memory_hooks_registered))
+               return;
+
+       unregister_reboot_notifier(&ehea_reboot_nb);
+       if (crash_shutdown_unregister(ehea_crash_handler))
+               pr_info("failed unregistering crash handler\n");
+       unregister_memory_notifier(&ehea_mem_nb);
+}
+
 static int ehea_probe_adapter(struct platform_device *dev)
 {
        struct ehea_adapter *adapter;
@@ -3269,6 +3402,10 @@ static int ehea_probe_adapter(struct platform_device *dev)
        int ret;
        int i;
 
+       ret = ehea_register_memory_hooks();
+       if (ret)
+               return ret;
+
        if (!dev || !dev->dev.of_node) {
                pr_err("Invalid ibmebus device probed\n");
                return -EINVAL;
@@ -3392,81 +3529,6 @@ static int ehea_remove(struct platform_device *dev)
        return 0;
 }
 
-static void ehea_crash_handler(void)
-{
-       int i;
-
-       if (ehea_fw_handles.arr)
-               for (i = 0; i < ehea_fw_handles.num_entries; i++)
-                       ehea_h_free_resource(ehea_fw_handles.arr[i].adh,
-                                            ehea_fw_handles.arr[i].fwh,
-                                            FORCE_FREE);
-
-       if (ehea_bcmc_regs.arr)
-               for (i = 0; i < ehea_bcmc_regs.num_entries; i++)
-                       ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh,
-                                             ehea_bcmc_regs.arr[i].port_id,
-                                             ehea_bcmc_regs.arr[i].reg_type,
-                                             ehea_bcmc_regs.arr[i].macaddr,
-                                             0, H_DEREG_BCMC);
-}
-
-static int ehea_mem_notifier(struct notifier_block *nb,
-                             unsigned long action, void *data)
-{
-       int ret = NOTIFY_BAD;
-       struct memory_notify *arg = data;
-
-       mutex_lock(&dlpar_mem_lock);
-
-       switch (action) {
-       case MEM_CANCEL_OFFLINE:
-               pr_info("memory offlining canceled");
-               /* Readd canceled memory block */
-       case MEM_ONLINE:
-               pr_info("memory is going online");
-               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
-               if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
-                       goto out_unlock;
-               ehea_rereg_mrs();
-               break;
-       case MEM_GOING_OFFLINE:
-               pr_info("memory is going offline");
-               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
-               if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
-                       goto out_unlock;
-               ehea_rereg_mrs();
-               break;
-       default:
-               break;
-       }
-
-       ehea_update_firmware_handles();
-       ret = NOTIFY_OK;
-
-out_unlock:
-       mutex_unlock(&dlpar_mem_lock);
-       return ret;
-}
-
-static struct notifier_block ehea_mem_nb = {
-       .notifier_call = ehea_mem_notifier,
-};
-
-static int ehea_reboot_notifier(struct notifier_block *nb,
-                               unsigned long action, void *unused)
-{
-       if (action == SYS_RESTART) {
-               pr_info("Reboot: freeing all eHEA resources\n");
-               ibmebus_unregister_driver(&ehea_driver);
-       }
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block ehea_reboot_nb = {
-       .notifier_call = ehea_reboot_notifier,
-};
-
 static int check_module_parm(void)
 {
        int ret = 0;
@@ -3520,26 +3582,10 @@ static int __init ehea_module_init(void)
        if (ret)
                goto out;
 
-       ret = ehea_create_busmap();
-       if (ret)
-               goto out;
-
-       ret = register_reboot_notifier(&ehea_reboot_nb);
-       if (ret)
-               pr_info("failed registering reboot notifier\n");
-
-       ret = register_memory_notifier(&ehea_mem_nb);
-       if (ret)
-               pr_info("failed registering memory remove notifier\n");
-
-       ret = crash_shutdown_register(ehea_crash_handler);
-       if (ret)
-               pr_info("failed registering crash handler\n");
-
        ret = ibmebus_register_driver(&ehea_driver);
        if (ret) {
                pr_err("failed registering eHEA device driver on ebus\n");
-               goto out2;
+               goto out;
        }
 
        ret = driver_create_file(&ehea_driver.driver,
@@ -3547,32 +3593,22 @@ static int __init ehea_module_init(void)
        if (ret) {
                pr_err("failed to register capabilities attribute, ret=%d\n",
                       ret);
-               goto out3;
+               goto out2;
        }
 
        return ret;
 
-out3:
-       ibmebus_unregister_driver(&ehea_driver);
 out2:
-       unregister_memory_notifier(&ehea_mem_nb);
-       unregister_reboot_notifier(&ehea_reboot_nb);
-       crash_shutdown_unregister(ehea_crash_handler);
+       ibmebus_unregister_driver(&ehea_driver);
 out:
        return ret;
 }
 
 static void __exit ehea_module_exit(void)
 {
-       int ret;
-
        driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
        ibmebus_unregister_driver(&ehea_driver);
-       unregister_reboot_notifier(&ehea_reboot_nb);
-       ret = crash_shutdown_unregister(ehea_crash_handler);
-       if (ret)
-               pr_info("failed unregistering crash handler\n");
-       unregister_memory_notifier(&ehea_mem_nb);
+       ehea_unregister_memory_hooks();
        kfree(ehea_fw_handles.arr);
        kfree(ehea_bcmc_regs.arr);
        ehea_destroy_busmap();
index 21978cc019e7c86dab83968ba994c0e9051c8e33..cd7675ac5bf9ed8b8658996d2d27190c6b20245f 100644 (file)
@@ -1136,6 +1136,8 @@ restart_poll:
        ibmveth_replenish_task(adapter);
 
        if (frames_processed < budget) {
+               napi_complete(napi);
+
                /* We think we are done - reenable interrupts,
                 * then check once more to make sure we are done.
                 */
@@ -1144,8 +1146,6 @@ restart_poll:
 
                BUG_ON(lpar_rc != H_SUCCESS);
 
-               napi_complete(napi);
-
                if (ibmveth_rxq_pending_buffer(adapter) &&
                    napi_reschedule(napi)) {
                        lpar_rc = h_vio_signal(adapter->vdev->unit_address,
@@ -1327,6 +1327,28 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
        return ret;
 }
 
+static int ibmveth_set_mac_addr(struct net_device *dev, void *p)
+{
+       struct ibmveth_adapter *adapter = netdev_priv(dev);
+       struct sockaddr *addr = p;
+       u64 mac_address;
+       int rc;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       mac_address = ibmveth_encode_mac_addr(addr->sa_data);
+       rc = h_change_logical_lan_mac(adapter->vdev->unit_address, mac_address);
+       if (rc) {
+               netdev_err(adapter->netdev, "h_change_logical_lan_mac failed with rc=%d\n", rc);
+               return rc;
+       }
+
+       ether_addr_copy(dev->dev_addr, addr->sa_data);
+
+       return 0;
+}
+
 static const struct net_device_ops ibmveth_netdev_ops = {
        .ndo_open               = ibmveth_open,
        .ndo_stop               = ibmveth_close,
@@ -1337,7 +1359,7 @@ static const struct net_device_ops ibmveth_netdev_ops = {
        .ndo_fix_features       = ibmveth_fix_features,
        .ndo_set_features       = ibmveth_set_features,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = ibmveth_set_mac_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = ibmveth_poll_controller,
 #endif
index 11a9ffebf8d88acdfd5b738baab62bd2b34aa30a..6aea65dae5ed654b5da2e7a8885a02a92c75710d 100644 (file)
@@ -868,8 +868,9 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw)
         * The grst delay value is in 100ms units, and we'll wait a
         * couple counts longer to be sure we don't just miss the end.
         */
-       grst_del = rd32(hw, I40E_GLGEN_RSTCTL) & I40E_GLGEN_RSTCTL_GRSTDEL_MASK
-                       >> I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
+       grst_del = (rd32(hw, I40E_GLGEN_RSTCTL) &
+                   I40E_GLGEN_RSTCTL_GRSTDEL_MASK) >>
+                   I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
        for (cnt = 0; cnt < grst_del + 2; cnt++) {
                reg = rd32(hw, I40E_GLGEN_RSTAT);
                if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK))
@@ -2846,7 +2847,7 @@ i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
 
        status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
 
-       if (!status)
+       if (!status && filter_index)
                *filter_index = resp->index;
 
        return status;
index 183dcb63ce98e14e5b504bed9874911b35ae18d3..a11c70ca5a2811c84cc094ac425b93ec0b840d5d 100644 (file)
@@ -40,7 +40,7 @@ static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay)
        u32 val;
 
        val = rd32(hw, I40E_PRTDCB_GENC);
-       *delay = (u16)(val & I40E_PRTDCB_GENC_PFCLDA_MASK >>
+       *delay = (u16)((val & I40E_PRTDCB_GENC_PFCLDA_MASK) >>
                       I40E_PRTDCB_GENC_PFCLDA_SHIFT);
 }
 
index 61236f983971a1d55955586cd5a6ee288f5c60e7..c17ee77100d3651e254265ae192bd4d3e54c3659 100644 (file)
@@ -989,8 +989,10 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
        if (!cmd_buf)
                return count;
        bytes_not_copied = copy_from_user(cmd_buf, buffer, count);
-       if (bytes_not_copied < 0)
+       if (bytes_not_copied < 0) {
+               kfree(cmd_buf);
                return bytes_not_copied;
+       }
        if (bytes_not_copied > 0)
                count -= bytes_not_copied;
        cmd_buf[count] = '\0';
index cbe281be1c9f0c1956c4e7d2467b42474fad70c2..dadda3c5d658b950cf64d21c838f5ffd5176f0f6 100644 (file)
@@ -1512,7 +1512,12 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
        vsi->tc_config.numtc = numtc;
        vsi->tc_config.enabled_tc = enabled_tc ? enabled_tc : 1;
        /* Number of queues per enabled TC */
-       num_tc_qps = vsi->alloc_queue_pairs/numtc;
+       /* In MFP case we can have a much lower count of MSIx
+        * vectors available and so we need to lower the used
+        * q count.
+        */
+       qcount = min_t(int, vsi->alloc_queue_pairs, pf->num_lan_msix);
+       num_tc_qps = qcount / numtc;
        num_tc_qps = min_t(int, num_tc_qps, I40E_MAX_QUEUES_PER_TC);
 
        /* Setup queue offset/count for all TCs for given VSI */
@@ -2684,8 +2689,15 @@ static void i40e_vsi_config_dcb_rings(struct i40e_vsi *vsi)
        u16 qoffset, qcount;
        int i, n;
 
-       if (!(vsi->back->flags & I40E_FLAG_DCB_ENABLED))
-               return;
+       if (!(vsi->back->flags & I40E_FLAG_DCB_ENABLED)) {
+               /* Reset the TC information */
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       rx_ring = vsi->rx_rings[i];
+                       tx_ring = vsi->tx_rings[i];
+                       rx_ring->dcb_tc = 0;
+                       tx_ring->dcb_tc = 0;
+               }
+       }
 
        for (n = 0; n < I40E_MAX_TRAFFIC_CLASS; n++) {
                if (!(vsi->tc_config.enabled_tc & (1 << n)))
@@ -3830,6 +3842,12 @@ static void i40e_clear_interrupt_scheme(struct i40e_pf *pf)
 {
        int i;
 
+       i40e_stop_misc_vector(pf);
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               synchronize_irq(pf->msix_entries[0].vector);
+               free_irq(pf->msix_entries[0].vector, pf);
+       }
+
        i40e_put_lump(pf->irq_pile, 0, I40E_PILE_VALID_BIT-1);
        for (i = 0; i < pf->num_alloc_vsi; i++)
                if (pf->vsi[i])
@@ -5254,8 +5272,14 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
 
        /* Wait for the PF's Tx queues to be disabled */
        ret = i40e_pf_wait_txq_disabled(pf);
-       if (!ret)
+       if (ret) {
+               /* Schedule PF reset to recover */
+               set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
+               i40e_service_event_schedule(pf);
+       } else {
                i40e_pf_unquiesce_all_vsi(pf);
+       }
+
 exit:
        return ret;
 }
@@ -5587,7 +5611,8 @@ static void i40e_check_hang_subtask(struct i40e_pf *pf)
        int i, v;
 
        /* If we're down or resetting, just bail */
-       if (test_bit(__I40E_CONFIG_BUSY, &pf->state))
+       if (test_bit(__I40E_DOWN, &pf->state) ||
+           test_bit(__I40E_CONFIG_BUSY, &pf->state))
                return;
 
        /* for each VSI/netdev
@@ -9533,6 +9558,7 @@ static void i40e_remove(struct pci_dev *pdev)
        set_bit(__I40E_DOWN, &pf->state);
        del_timer_sync(&pf->service_timer);
        cancel_work_sync(&pf->service_task);
+       i40e_fdir_teardown(pf);
 
        if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
                i40e_free_vfs(pf);
@@ -9559,12 +9585,6 @@ static void i40e_remove(struct pci_dev *pdev)
        if (pf->vsi[pf->lan_vsi])
                i40e_vsi_release(pf->vsi[pf->lan_vsi]);
 
-       i40e_stop_misc_vector(pf);
-       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
-               synchronize_irq(pf->msix_entries[0].vector);
-               free_irq(pf->msix_entries[0].vector, pf);
-       }
-
        /* shutdown and destroy the HMC */
        if (pf->hw.hmc.hmc_obj) {
                ret_code = i40e_shutdown_lan_hmc(&pf->hw);
@@ -9718,6 +9738,8 @@ static void i40e_shutdown(struct pci_dev *pdev)
        wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
        wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
 
+       i40e_clear_interrupt_scheme(pf);
+
        if (system_state == SYSTEM_POWER_OFF) {
                pci_wake_from_d3(pdev, pf->wol_en);
                pci_set_power_state(pdev, PCI_D3hot);
index 3e70f2e45a4768986a0a90ee21bdf98790db9b53..5defe0d635141ed5c886cb1086995f2b2d3d31a1 100644 (file)
@@ -679,9 +679,11 @@ static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,
 {
        i40e_status status;
        enum i40e_nvmupd_cmd upd_cmd;
+       bool retry_attempt = false;
 
        upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
 
+retry:
        switch (upd_cmd) {
        case I40E_NVMUPD_WRITE_CON:
                status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
@@ -725,6 +727,39 @@ static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,
                *errno = -ESRCH;
                break;
        }
+
+       /* In some circumstances, a multi-write transaction takes longer
+        * than the default 3 minute timeout on the write semaphore.  If
+        * the write failed with an EBUSY status, this is likely the problem,
+        * so here we try to reacquire the semaphore then retry the write.
+        * We only do one retry, then give up.
+        */
+       if (status && (hw->aq.asq_last_status == I40E_AQ_RC_EBUSY) &&
+           !retry_attempt) {
+               i40e_status old_status = status;
+               u32 old_asq_status = hw->aq.asq_last_status;
+               u32 gtime;
+
+               gtime = rd32(hw, I40E_GLVFGEN_TIMER);
+               if (gtime >= hw->nvm.hw_semaphore_timeout) {
+                       i40e_debug(hw, I40E_DEBUG_ALL,
+                                  "NVMUPD: write semaphore expired (%d >= %lld), retrying\n",
+                                  gtime, hw->nvm.hw_semaphore_timeout);
+                       i40e_release_nvm(hw);
+                       status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
+                       if (status) {
+                               i40e_debug(hw, I40E_DEBUG_ALL,
+                                          "NVMUPD: write semaphore reacquire failed aq_err = %d\n",
+                                          hw->aq.asq_last_status);
+                               status = old_status;
+                               hw->aq.asq_last_status = old_asq_status;
+                       } else {
+                               retry_attempt = true;
+                               goto retry;
+                       }
+               }
+       }
+
        return status;
 }
 
index 2206d2d36f0fdf2e9f249c7624e156f8c1b17118..bbf1b1247ac471bb712ed1397956db83cf80e4f3 100644 (file)
@@ -585,6 +585,20 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
        }
 }
 
+/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring:  tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+       return le32_to_cpu(*(volatile __le32 *)head);
+}
+
 /**
  * i40e_get_tx_pending - how many tx descriptors not processed
  * @tx_ring: the ring of descriptors
@@ -594,10 +608,16 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
  **/
 static u32 i40e_get_tx_pending(struct i40e_ring *ring)
 {
-       u32 ntu = ((ring->next_to_clean <= ring->next_to_use)
-                       ? ring->next_to_use
-                       : ring->next_to_use + ring->count);
-       return ntu - ring->next_to_clean;
+       u32 head, tail;
+
+       head = i40e_get_head(ring);
+       tail = readl(ring->tail);
+
+       if (head != tail)
+               return (head < tail) ?
+                       tail - head : (tail + ring->count - head);
+
+       return 0;
 }
 
 /**
@@ -606,6 +626,8 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring)
  **/
 static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
 {
+       u32 tx_done = tx_ring->stats.packets;
+       u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
        u32 tx_pending = i40e_get_tx_pending(tx_ring);
        struct i40e_pf *pf = tx_ring->vsi->back;
        bool ret = false;
@@ -623,41 +645,25 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
         * run the check_tx_hang logic with a transmit completion
         * pending but without time to complete it yet.
         */
-       if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-           (tx_pending >= I40E_MIN_DESC_PENDING)) {
+       if ((tx_done_old == tx_done) && tx_pending) {
                /* make sure it is true for two checks in a row */
                ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
                                       &tx_ring->state);
-       } else if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-                  (tx_pending < I40E_MIN_DESC_PENDING) &&
-                  (tx_pending > 0)) {
+       } else if (tx_done_old == tx_done &&
+                  (tx_pending < I40E_MIN_DESC_PENDING) && (tx_pending > 0)) {
                if (I40E_DEBUG_FLOW & pf->hw.debug_mask)
                        dev_info(tx_ring->dev, "HW needs some more descs to do a cacheline flush. tx_pending %d, queue %d",
                                 tx_pending, tx_ring->queue_index);
                pf->tx_sluggish_count++;
        } else {
                /* update completed stats and disarm the hang check */
-               tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
+               tx_ring->tx_stats.tx_done_old = tx_done;
                clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
        }
 
        return ret;
 }
 
-/**
- * i40e_get_head - Retrieve head from head writeback
- * @tx_ring:  tx ring to fetch head of
- *
- * Returns value of Tx ring head based on value stored
- * in head write-back location
- **/
-static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
-{
-       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
-
-       return le32_to_cpu(*(volatile __le32 *)head);
-}
-
 #define WB_STRIDE 0x3
 
 /**
@@ -2139,6 +2145,67 @@ static int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
        return __i40e_maybe_stop_tx(tx_ring, size);
 }
 
+/**
+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * @skb:      send buffer
+ * @tx_flags: collected send information
+ * @hdr_len:  size of the packet header
+ *
+ * Note: Our HW can't scatter-gather more than 8 fragments to build
+ * a packet on the wire and so we need to figure out the cases where we
+ * need to linearize the skb.
+ **/
+static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
+                              const u8 hdr_len)
+{
+       struct skb_frag_struct *frag;
+       bool linearize = false;
+       unsigned int size = 0;
+       u16 num_frags;
+       u16 gso_segs;
+
+       num_frags = skb_shinfo(skb)->nr_frags;
+       gso_segs = skb_shinfo(skb)->gso_segs;
+
+       if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
+               u16 j = 1;
+
+               if (num_frags < (I40E_MAX_BUFFER_TXD))
+                       goto linearize_chk_done;
+               /* try the simple math, if we have too many frags per segment */
+               if (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >
+                   I40E_MAX_BUFFER_TXD) {
+                       linearize = true;
+                       goto linearize_chk_done;
+               }
+               frag = &skb_shinfo(skb)->frags[0];
+               size = hdr_len;
+               /* we might still have more fragments per segment */
+               do {
+                       size += skb_frag_size(frag);
+                       frag++; j++;
+                       if (j == I40E_MAX_BUFFER_TXD) {
+                               if (size < skb_shinfo(skb)->gso_size) {
+                                       linearize = true;
+                                       break;
+                               }
+                               j = 1;
+                               size -= skb_shinfo(skb)->gso_size;
+                               if (size)
+                                       j++;
+                               size += hdr_len;
+                       }
+                       num_frags--;
+               } while (num_frags);
+       } else {
+               if (num_frags >= I40E_MAX_BUFFER_TXD)
+                       linearize = true;
+       }
+
+linearize_chk_done:
+       return linearize;
+}
+
 /**
  * i40e_tx_map - Build the Tx descriptor
  * @tx_ring:  ring to send buffer on
@@ -2396,6 +2463,10 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        if (tsyn)
                tx_flags |= I40E_TX_FLAGS_TSYN;
 
+       if (i40e_chk_linearize(skb, tx_flags, hdr_len))
+               if (skb_linearize(skb))
+                       goto out_drop;
+
        skb_tx_timestamp(skb);
 
        /* always enable CRC insertion offload */
index 18b00231d2f117d714e7e1399aecba0061ead41a..dff0baeb1ecc092e53ef22ea373be46e79df13a2 100644 (file)
@@ -112,6 +112,7 @@ enum i40e_dyn_idx_t {
 
 #define i40e_rx_desc i40e_32byte_rx_desc
 
+#define I40E_MAX_BUFFER_TXD    8
 #define I40E_MIN_TX_LEN                17
 #define I40E_MAX_DATA_PER_TXD  8192
 
index 29004382f462ce717fd27b5b004139f5ef0efd1a..708891571dae328299e2b31e83cbf40b42726473 100644 (file)
@@ -125,6 +125,20 @@ void i40evf_free_tx_resources(struct i40e_ring *tx_ring)
        }
 }
 
+/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring:  tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+       return le32_to_cpu(*(volatile __le32 *)head);
+}
+
 /**
  * i40e_get_tx_pending - how many tx descriptors not processed
  * @tx_ring: the ring of descriptors
@@ -134,10 +148,16 @@ void i40evf_free_tx_resources(struct i40e_ring *tx_ring)
  **/
 static u32 i40e_get_tx_pending(struct i40e_ring *ring)
 {
-       u32 ntu = ((ring->next_to_clean <= ring->next_to_use)
-                       ? ring->next_to_use
-                       : ring->next_to_use + ring->count);
-       return ntu - ring->next_to_clean;
+       u32 head, tail;
+
+       head = i40e_get_head(ring);
+       tail = readl(ring->tail);
+
+       if (head != tail)
+               return (head < tail) ?
+                       tail - head : (tail + ring->count - head);
+
+       return 0;
 }
 
 /**
@@ -146,6 +166,8 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring)
  **/
 static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
 {
+       u32 tx_done = tx_ring->stats.packets;
+       u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
        u32 tx_pending = i40e_get_tx_pending(tx_ring);
        bool ret = false;
 
@@ -162,36 +184,20 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
         * run the check_tx_hang logic with a transmit completion
         * pending but without time to complete it yet.
         */
-       if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-           (tx_pending >= I40E_MIN_DESC_PENDING)) {
+       if ((tx_done_old == tx_done) && tx_pending) {
                /* make sure it is true for two checks in a row */
                ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
                                       &tx_ring->state);
-       } else if (!(tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) ||
-                  !(tx_pending < I40E_MIN_DESC_PENDING) ||
-                  !(tx_pending > 0)) {
+       } else if (tx_done_old == tx_done &&
+                  (tx_pending < I40E_MIN_DESC_PENDING) && (tx_pending > 0)) {
                /* update completed stats and disarm the hang check */
-               tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
+               tx_ring->tx_stats.tx_done_old = tx_done;
                clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
        }
 
        return ret;
 }
 
-/**
- * i40e_get_head - Retrieve head from head writeback
- * @tx_ring:  tx ring to fetch head of
- *
- * Returns value of Tx ring head based on value stored
- * in head write-back location
- **/
-static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
-{
-       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
-
-       return le32_to_cpu(*(volatile __le32 *)head);
-}
-
 #define WB_STRIDE 0x3
 
 /**
@@ -1206,17 +1212,16 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       if (protocol == htons(ETH_P_IP)) {
-               iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
+       iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
+       ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
+
+       if (iph->version == 4) {
                tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
                iph->tot_len = 0;
                iph->check = 0;
                tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
                                                 0, IPPROTO_TCP, 0);
-       } else if (skb_is_gso_v6(skb)) {
-
-               ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb)
-                                          : ipv6_hdr(skb);
+       } else if (ipv6h->version == 6) {
                tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
                ipv6h->payload_len = 0;
                tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
@@ -1274,13 +1279,9 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
                                         I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
                        }
                } else if (tx_flags & I40E_TX_FLAGS_IPV6) {
-                       if (tx_flags & I40E_TX_FLAGS_TSO) {
-                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                       *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                       if (tx_flags & I40E_TX_FLAGS_TSO)
                                ip_hdr(skb)->check = 0;
-                       } else {
-                               *cd_tunneling |=
-                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
-                       }
                }
 
                /* Now set the ctx descriptor fields */
@@ -1290,6 +1291,11 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
                                   ((skb_inner_network_offset(skb) -
                                        skb_transport_offset(skb)) >> 1) <<
                                   I40E_TXD_CTX_QW0_NATLEN_SHIFT;
+               if (this_ip_hdr->version == 6) {
+                       tx_flags &= ~I40E_TX_FLAGS_IPV4;
+                       tx_flags |= I40E_TX_FLAGS_IPV6;
+               }
+
 
        } else {
                network_hdr_len = skb_network_header_len(skb);
@@ -1380,6 +1386,67 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
        context_desc->type_cmd_tso_mss = cpu_to_le64(cd_type_cmd_tso_mss);
 }
 
+ /**
+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * @skb:      send buffer
+ * @tx_flags: collected send information
+ * @hdr_len:  size of the packet header
+ *
+ * Note: Our HW can't scatter-gather more than 8 fragments to build
+ * a packet on the wire and so we need to figure out the cases where we
+ * need to linearize the skb.
+ **/
+static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
+                              const u8 hdr_len)
+{
+       struct skb_frag_struct *frag;
+       bool linearize = false;
+       unsigned int size = 0;
+       u16 num_frags;
+       u16 gso_segs;
+
+       num_frags = skb_shinfo(skb)->nr_frags;
+       gso_segs = skb_shinfo(skb)->gso_segs;
+
+       if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
+               u16 j = 1;
+
+               if (num_frags < (I40E_MAX_BUFFER_TXD))
+                       goto linearize_chk_done;
+               /* try the simple math, if we have too many frags per segment */
+               if (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >
+                   I40E_MAX_BUFFER_TXD) {
+                       linearize = true;
+                       goto linearize_chk_done;
+               }
+               frag = &skb_shinfo(skb)->frags[0];
+               size = hdr_len;
+               /* we might still have more fragments per segment */
+               do {
+                       size += skb_frag_size(frag);
+                       frag++; j++;
+                       if (j == I40E_MAX_BUFFER_TXD) {
+                               if (size < skb_shinfo(skb)->gso_size) {
+                                       linearize = true;
+                                       break;
+                               }
+                               j = 1;
+                               size -= skb_shinfo(skb)->gso_size;
+                               if (size)
+                                       j++;
+                               size += hdr_len;
+                       }
+                       num_frags--;
+               } while (num_frags);
+       } else {
+               if (num_frags >= I40E_MAX_BUFFER_TXD)
+                       linearize = true;
+       }
+
+linearize_chk_done:
+       return linearize;
+}
+
 /**
  * i40e_tx_map - Build the Tx descriptor
  * @tx_ring:  ring to send buffer on
@@ -1654,6 +1721,10 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        else if (tso)
                tx_flags |= I40E_TX_FLAGS_TSO;
 
+       if (i40e_chk_linearize(skb, tx_flags, hdr_len))
+               if (skb_linearize(skb))
+                       goto out_drop;
+
        skb_tx_timestamp(skb);
 
        /* always enable CRC insertion offload */
index 4e15903b2b6ded2a054981999f71e2406b1e80a2..c950a038237c2c63dc66b9bf7be887556b80a5de 100644 (file)
@@ -112,6 +112,7 @@ enum i40e_dyn_idx_t {
 
 #define i40e_rx_desc i40e_32byte_rx_desc
 
+#define I40E_MAX_BUFFER_TXD    8
 #define I40E_MIN_TX_LEN                17
 #define I40E_MAX_DATA_PER_TXD  8192
 
index 2a210c4efb895728ec6ad12eaef9ec8f9ff7fd08..ebce5bb24df98b77eec38a1fc6c720987768934b 100644 (file)
@@ -1698,8 +1698,6 @@ int mlx4_en_start_port(struct net_device *dev)
        /* Schedule multicast task to populate multicast list */
        queue_work(mdev->workqueue, &priv->rx_mode_task);
 
-       mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
-
 #ifdef CONFIG_MLX4_EN_VXLAN
        if (priv->mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
                vxlan_get_rx_port(dev);
@@ -2853,6 +2851,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
                queue_delayed_work(mdev->workqueue, &priv->service_task,
                                   SERVICE_TASK_DELAY);
 
+       mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
+
        return 0;
 
 out:
index 2d8ee66138e8ad48cb72daa773a67c1f421e4cac..a61009f4b2df728e05a4e54def4bb1336949f03e 100644 (file)
@@ -81,12 +81,14 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
 {
        u32 loopback_ok = 0;
        int i;
-
+       bool gro_enabled;
 
         priv->loopback_ok = 0;
        priv->validate_loopback = 1;
+       gro_enabled = priv->dev->features & NETIF_F_GRO;
 
        mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+       priv->dev->features &= ~NETIF_F_GRO;
 
        /* xmit */
        if (mlx4_en_test_loopback_xmit(priv)) {
@@ -108,6 +110,10 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
 mlx4_en_test_loopback_exit:
 
        priv->validate_loopback = 0;
+
+       if (gro_enabled)
+               priv->dev->features |= NETIF_F_GRO;
+
        mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
        return !loopback_ok;
 }
index 2a8268e6be15d0b8682b8ad47bb4bb4ac071b243..ebbe244e80dde55068d924905e08d1d631821811 100644 (file)
@@ -453,7 +453,7 @@ struct mlx4_en_port_stats {
        unsigned long rx_chksum_none;
        unsigned long rx_chksum_complete;
        unsigned long tx_chksum_offload;
-#define NUM_PORT_STATS         9
+#define NUM_PORT_STATS         10
 };
 
 struct mlx4_en_perf_stats {
index 2bb8553bd9054b25456ec694ee25696e93ebde25..eda29dbbfcd259824f0a0fbec3876975f215d2e2 100644 (file)
@@ -412,7 +412,6 @@ err_icm:
 
 EXPORT_SYMBOL_GPL(mlx4_qp_alloc);
 
-#define MLX4_UPDATE_QP_SUPPORTED_ATTRS MLX4_UPDATE_QP_SMAC
 int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn,
                   enum mlx4_update_qp_attr attr,
                   struct mlx4_update_qp_params *params)
index 486e3d26cd4a9ef4bb6a23995b85ac50cd413776..d97ca88c55b59e039af66991e4ad413f82984158 100644 (file)
@@ -713,7 +713,7 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
        struct mlx4_vport_oper_state *vp_oper;
        struct mlx4_priv *priv;
        u32 qp_type;
-       int port;
+       int port, err = 0;
 
        port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
        priv = mlx4_priv(dev);
@@ -738,7 +738,9 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
                        } else {
                                struct mlx4_update_qp_params params = {.flags = 0};
 
-                               mlx4_update_qp(dev, qpn, MLX4_UPDATE_QP_VSD, &params);
+                               err = mlx4_update_qp(dev, qpn, MLX4_UPDATE_QP_VSD, &params);
+                               if (err)
+                                       goto out;
                        }
                }
 
@@ -773,7 +775,8 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
                qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC;
                qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx;
        }
-       return 0;
+out:
+       return err;
 }
 
 static int mpt_mask(struct mlx4_dev *dev)
index 44e8d7d255474d30bf48577723caf9032af43854..57a6e6cd74fc3c9c99708530b431cd0e5b768f8c 100644 (file)
@@ -1239,11 +1239,9 @@ static int pasemi_mac_open(struct net_device *dev)
        if (mac->phydev)
                phy_start(mac->phydev);
 
-       init_timer(&mac->tx->clean_timer);
-       mac->tx->clean_timer.function = pasemi_mac_tx_timer;
-       mac->tx->clean_timer.data = (unsigned long)mac->tx;
-       mac->tx->clean_timer.expires = jiffies+HZ;
-       add_timer(&mac->tx->clean_timer);
+       setup_timer(&mac->tx->clean_timer, pasemi_mac_tx_timer,
+                   (unsigned long)mac->tx);
+       mod_timer(&mac->tx->clean_timer, jiffies + HZ);
 
        return 0;
 
index 6e426ae9469228ed55586bca15a8eef1dcb5e5c4..0a5e204a0179a35c15f52a3dea58729c30c2c31f 100644 (file)
@@ -354,7 +354,7 @@ struct cmd_desc_type0 {
 
 } __attribute__ ((aligned(64)));
 
-/* Note: sizeof(rcv_desc) should always be a mutliple of 2 */
+/* Note: sizeof(rcv_desc) should always be a multiple of 2 */
 struct rcv_desc {
        __le16 reference_handle;
        __le16 reserved;
@@ -499,7 +499,7 @@ struct uni_data_desc{
 #define NETXEN_IMAGE_START     0x43000 /* compressed image */
 #define NETXEN_SECONDARY_START 0x200000        /* backup images */
 #define NETXEN_PXE_START       0x3E0000        /* PXE boot rom */
-#define NETXEN_USER_START      0x3E8000        /* Firmare info */
+#define NETXEN_USER_START      0x3E8000        /* Firmware info */
 #define NETXEN_FIXED_START     0x3F0000        /* backup of crbinit */
 #define NETXEN_USER_START_OLD  NETXEN_PXE_START /* very old flash */
 
index fa4317611fd63fe81df2e23e47fa307b8c5c5348..f221126a5c4e6789cb2630a07dc58b02f0676239 100644 (file)
@@ -314,7 +314,7 @@ struct qlcnic_fdt {
 #define QLCNIC_BRDCFG_START    0x4000          /* board config */
 #define QLCNIC_BOOTLD_START    0x10000         /* bootld */
 #define QLCNIC_IMAGE_START     0x43000         /* compressed image */
-#define QLCNIC_USER_START      0x3E8000        /* Firmare info */
+#define QLCNIC_USER_START      0x3E8000        /* Firmware info */
 
 #define QLCNIC_FW_VERSION_OFFSET       (QLCNIC_USER_START+0x408)
 #define QLCNIC_FW_SIZE_OFFSET          (QLCNIC_USER_START+0x40c)
index ad0020af2193da8749534c25242047212cccc1a4..c70ab40d86989974d54c9161bf7acd8558d93c74 100644 (file)
@@ -2561,7 +2561,7 @@ static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
        int rc = -EINVAL;
 
        if (!rtl_fw_format_ok(tp, rtl_fw)) {
-               netif_err(tp, ifup, dev, "invalid firwmare\n");
+               netif_err(tp, ifup, dev, "invalid firmware\n");
                goto out;
        }
 
@@ -5067,8 +5067,6 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
        RTL_W8(ChipCmd, CmdReset);
 
        rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
-
-       netdev_reset_queue(tp->dev);
 }
 
 static void rtl_request_uncached_firmware(struct rtl8169_private *tp)
@@ -7049,7 +7047,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
        u32 status, len;
        u32 opts[2];
        int frags;
-       bool stop_queue;
 
        if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
                netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
@@ -7090,8 +7087,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
 
        txd->opts2 = cpu_to_le32(opts[1]);
 
-       netdev_sent_queue(dev, skb->len);
-
        skb_tx_timestamp(skb);
 
        /* Force memory writes to complete before releasing descriptor */
@@ -7106,16 +7101,11 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
 
        tp->cur_tx += frags + 1;
 
-       stop_queue = !TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS);
+       RTL_W8(TxPoll, NPQ);
 
-       if (!skb->xmit_more || stop_queue ||
-           netif_xmit_stopped(netdev_get_tx_queue(dev, 0))) {
-               RTL_W8(TxPoll, NPQ);
-
-               mmiowb();
-       }
+       mmiowb();
 
-       if (stop_queue) {
+       if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
                /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
                 * not miss a ring update when it notices a stopped queue.
                 */
@@ -7198,7 +7188,6 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
 static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
 {
        unsigned int dirty_tx, tx_left;
-       unsigned int bytes_compl = 0, pkts_compl = 0;
 
        dirty_tx = tp->dirty_tx;
        smp_rmb();
@@ -7222,8 +7211,10 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
                rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
                                     tp->TxDescArray + entry);
                if (status & LastFrag) {
-                       pkts_compl++;
-                       bytes_compl += tx_skb->skb->len;
+                       u64_stats_update_begin(&tp->tx_stats.syncp);
+                       tp->tx_stats.packets++;
+                       tp->tx_stats.bytes += tx_skb->skb->len;
+                       u64_stats_update_end(&tp->tx_stats.syncp);
                        dev_kfree_skb_any(tx_skb->skb);
                        tx_skb->skb = NULL;
                }
@@ -7232,13 +7223,6 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
        }
 
        if (tp->dirty_tx != dirty_tx) {
-               netdev_completed_queue(tp->dev, pkts_compl, bytes_compl);
-
-               u64_stats_update_begin(&tp->tx_stats.syncp);
-               tp->tx_stats.packets += pkts_compl;
-               tp->tx_stats.bytes += bytes_compl;
-               u64_stats_update_end(&tp->tx_stats.syncp);
-
                tp->dirty_tx = dirty_tx;
                /* Sync with rtl8169_start_xmit:
                 * - publish dirty_tx ring index (write barrier)
index 4da8bd263997a17baf89b5fe7a3d2198f186827b..736d5d1624a142e902d6023cf3ee801c5169fa14 100644 (file)
@@ -508,7 +508,6 @@ static struct sh_eth_cpu_data r8a779x_data = {
        .tpauser        = 1,
        .hw_swap        = 1,
        .rmiimode       = 1,
-       .shift_rd0      = 1,
 };
 
 static void sh_eth_set_rate_sh7724(struct net_device *ndev)
@@ -1392,6 +1391,9 @@ static void sh_eth_dev_exit(struct net_device *ndev)
        msleep(2); /* max frame time at 10 Mbps < 1250 us */
        sh_eth_get_stats(ndev);
        sh_eth_reset(ndev);
+
+       /* Set MAC address again */
+       update_mac_address(ndev);
 }
 
 /* free Tx skb function */
@@ -1407,6 +1409,8 @@ static int sh_eth_txfree(struct net_device *ndev)
                txdesc = &mdp->tx_ring[entry];
                if (txdesc->status & cpu_to_edmac(mdp, TD_TACT))
                        break;
+               /* TACT bit must be checked before all the following reads */
+               rmb();
                /* Free the original skb. */
                if (mdp->tx_skbuff[entry]) {
                        dma_unmap_single(&ndev->dev, txdesc->addr,
@@ -1444,6 +1448,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
        limit = boguscnt;
        rxdesc = &mdp->rx_ring[entry];
        while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) {
+               /* RACT bit must be checked before all the following reads */
+               rmb();
                desc_status = edmac_to_cpu(mdp, rxdesc->status);
                pkt_len = rxdesc->frame_length;
 
@@ -1455,8 +1461,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
 
                /* In case of almost all GETHER/ETHERs, the Receive Frame State
                 * (RFS) bits in the Receive Descriptor 0 are from bit 9 to
-                * bit 0. However, in case of the R8A7740, R8A779x, and
-                * R7S72100 the RFS bits are from bit 25 to bit 16. So, the
+                * bit 0. However, in case of the R8A7740 and R7S72100
+                * the RFS bits are from bit 25 to bit 16. So, the
                 * driver needs right shifting by 16.
                 */
                if (mdp->cd->shift_rd0)
@@ -1523,6 +1529,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                        skb_checksum_none_assert(skb);
                        rxdesc->addr = dma_addr;
                }
+               wmb(); /* RACT bit must be set after all the above writes */
                if (entry >= mdp->num_rx_ring - 1)
                        rxdesc->status |=
                                cpu_to_edmac(mdp, RD_RACT | RD_RFP | RD_RDEL);
@@ -1535,7 +1542,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
        /* If we don't need to check status, don't. -KDU */
        if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) {
                /* fix the values for the next receiving if RDE is set */
-               if (intr_status & EESR_RDE) {
+               if (intr_status & EESR_RDE && mdp->reg_offset[RDFAR] != 0) {
                        u32 count = (sh_eth_read(ndev, RDFAR) -
                                     sh_eth_read(ndev, RDLAR)) >> 4;
 
@@ -2174,7 +2181,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
        spin_unlock_irqrestore(&mdp->lock, flags);
 
-       if (skb_padto(skb, ETH_ZLEN))
+       if (skb_put_padto(skb, ETH_ZLEN))
                return NETDEV_TX_OK;
 
        entry = mdp->cur_tx % mdp->num_tx_ring;
@@ -2192,6 +2199,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
        txdesc->buffer_length = skb->len;
 
+       wmb(); /* TACT bit must be set after all the above writes */
        if (entry >= mdp->num_tx_ring - 1)
                txdesc->status |= cpu_to_edmac(mdp, TD_TACT | TD_TDLE);
        else
index 34389b6aa67cbd26263366ca1bff769f1b27c68a..9fb6948e14c64ef424c032811364aaefc608d4cb 100644 (file)
@@ -1257,9 +1257,9 @@ static void rocker_port_set_enable(struct rocker_port *rocker_port, bool enable)
        u64 val = rocker_read64(rocker_port->rocker, PORT_PHYS_ENABLE);
 
        if (enable)
-               val |= 1 << rocker_port->lport;
+               val |= 1ULL << rocker_port->lport;
        else
-               val &= ~(1 << rocker_port->lport);
+               val &= ~(1ULL << rocker_port->lport);
        rocker_write64(rocker_port->rocker, PORT_PHYS_ENABLE, val);
 }
 
@@ -4201,6 +4201,8 @@ static int rocker_probe_ports(struct rocker *rocker)
 
        alloc_size = sizeof(struct rocker_port *) * rocker->port_count;
        rocker->ports = kmalloc(alloc_size, GFP_KERNEL);
+       if (!rocker->ports)
+               return -ENOMEM;
        for (i = 0; i < rocker->port_count; i++) {
                err = rocker_probe_port(rocker, i);
                if (err)
index 6b33127ab352a43ed6a787af7eedde554241e1b3..3449893aea8d402fb2fc56582df92a04aa157c10 100644 (file)
@@ -1070,11 +1070,8 @@ static int smc_open(struct net_device *dev)
     smc->packets_waiting = 0;
 
     smc_reset(dev);
-    init_timer(&smc->media);
-    smc->media.function = media_check;
-    smc->media.data = (u_long) dev;
-    smc->media.expires = jiffies + HZ;
-    add_timer(&smc->media);
+    setup_timer(&smc->media, media_check, (u_long)dev);
+    mod_timer(&smc->media, jiffies + HZ);
 
     return 0;
 } /* smc_open */
index 88a55f95fe09bc544b0acf0e28bae507086788f8..8678e39aba08cfe0d5b3b0578348b258812ec4ec 100644 (file)
@@ -91,6 +91,11 @@ static const char version[] =
 
 #include "smc91x.h"
 
+#if defined(CONFIG_ASSABET_NEPONSET)
+#include <mach/assabet.h>
+#include <mach/neponset.h>
+#endif
+
 #ifndef SMC_NOWAIT
 # define SMC_NOWAIT            0
 #endif
@@ -2243,10 +2248,9 @@ static int smc_drv_probe(struct platform_device *pdev)
        const struct of_device_id *match = NULL;
        struct smc_local *lp;
        struct net_device *ndev;
-       struct resource *res;
+       struct resource *res, *ires;
        unsigned int __iomem *addr;
        unsigned long irq_flags = SMC_IRQ_FLAGS;
-       unsigned long irq_resflags;
        int ret;
 
        ndev = alloc_etherdev(sizeof(struct smc_local));
@@ -2338,25 +2342,23 @@ static int smc_drv_probe(struct platform_device *pdev)
                goto out_free_netdev;
        }
 
-       ndev->irq = platform_get_irq(pdev, 0);
-       if (ndev->irq <= 0) {
+       ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!ires) {
                ret = -ENODEV;
                goto out_release_io;
        }
-       /*
-        * If this platform does not specify any special irqflags, or if
-        * the resource supplies a trigger, override the irqflags with
-        * the trigger flags from the resource.
-        */
-       irq_resflags = irqd_get_trigger_type(irq_get_irq_data(ndev->irq));
-       if (irq_flags == -1 || irq_resflags & IRQF_TRIGGER_MASK)
-               irq_flags = irq_resflags & IRQF_TRIGGER_MASK;
+
+       ndev->irq = ires->start;
+
+       if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK)
+               irq_flags = ires->flags & IRQF_TRIGGER_MASK;
 
        ret = smc_request_attrib(pdev, ndev);
        if (ret)
                goto out_release_io;
-#if defined(CONFIG_SA1100_ASSABET)
-       neponset_ncr_set(NCR_ENET_OSC_EN);
+#if defined(CONFIG_ASSABET_NEPONSET)
+       if (machine_is_assabet() && machine_has_neponset())
+               neponset_ncr_set(NCR_ENET_OSC_EN);
 #endif
        platform_set_drvdata(pdev, ndev);
        ret = smc_enable_device(pdev);
index be67baf5f6778d08df4eaa06216914b77ab8f2b5..3a18501d1068c36816554f953e367ff1439c2a36 100644 (file)
  * Define your architecture specific bus configuration parameters here.
  */
 
-#if defined(CONFIG_ARCH_LUBBOCK) ||\
-    defined(CONFIG_MACH_MAINSTONE) ||\
-    defined(CONFIG_MACH_ZYLONITE) ||\
-    defined(CONFIG_MACH_LITTLETON) ||\
-    defined(CONFIG_MACH_ZYLONITE2) ||\
-    defined(CONFIG_ARCH_VIPER) ||\
-    defined(CONFIG_MACH_STARGATE2) ||\
-    defined(CONFIG_ARCH_VERSATILE)
+#if defined(CONFIG_ARM)
 
 #include <asm/mach-types.h>
 
 /* We actually can't write halfwords properly if not word aligned */
 static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 {
-       if ((machine_is_mainstone() || machine_is_stargate2()) && reg & 2) {
-               unsigned int v = val << 16;
-               v |= readl(ioaddr + (reg & ~2)) & 0xffff;
-               writel(v, ioaddr + (reg & ~2));
-       } else {
-               writew(val, ioaddr + reg);
-       }
-}
-
-#elif defined(CONFIG_SA1100_PLEB)
-/* We can only do 16-bit reads and writes in the static memory space. */
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, (l))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          (-1)
-
-#elif defined(CONFIG_SA1100_ASSABET)
-
-#include <mach/neponset.h>
-
-/* We can only do 8-bit reads and writes in the static memory space. */
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      0
-#define SMC_CAN_USE_32BIT      0
-#define SMC_NOWAIT             1
-
-/* The first two address lines aren't connected... */
-#define SMC_IO_SHIFT           2
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, (l))
-#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
-#define SMC_IRQ_FLAGS          (-1)    /* from resource */
-
-#elif  defined(CONFIG_MACH_LOGICPD_PXA270) ||  \
-       defined(CONFIG_MACH_NOMADIK_8815NHK)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#elif  defined(CONFIG_ARCH_INNOKOM) || \
-       defined(CONFIG_ARCH_PXA_IDP) || \
-       defined(CONFIG_ARCH_RAMSES) || \
-       defined(CONFIG_ARCH_PCM027)
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-#define SMC_USE_PXA_DMA                1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-#define SMC_IRQ_FLAGS          (-1)    /* from resource */
-
-/* We actually can't write halfwords properly if not word aligned */
-static inline void
-SMC_outw(u16 val, void __iomem *ioaddr, int reg)
-{
-       if (reg & 2) {
+       if ((machine_is_mainstone() || machine_is_stargate2() ||
+            machine_is_pxa_idp()) && reg & 2) {
                unsigned int v = val << 16;
                v |= readl(ioaddr + (reg & ~2)) & 0xffff;
                writel(v, ioaddr + (reg & ~2));
@@ -237,20 +143,6 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #define RPC_LSA_DEFAULT         RPC_LED_100_10
 #define RPC_LSB_DEFAULT         RPC_LED_TX_RX
 
-#elif defined(CONFIG_ARCH_MSM)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_NOWAIT             1
-
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          IRQF_TRIGGER_HIGH
-
 #elif defined(CONFIG_COLDFIRE)
 
 #define SMC_CAN_USE_8BIT       0
index 55e89b3838f1cb60df3f2f751ba254eddbef8fa2..a0ea84fe6519badffb8b5cabf0e9892d135ea081 100644 (file)
@@ -310,11 +310,11 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
                spin_lock_irqsave(&priv->lock, flags);
                if (!priv->eee_active) {
                        priv->eee_active = 1;
-                       init_timer(&priv->eee_ctrl_timer);
-                       priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer;
-                       priv->eee_ctrl_timer.data = (unsigned long)priv;
-                       priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer);
-                       add_timer(&priv->eee_ctrl_timer);
+                       setup_timer(&priv->eee_ctrl_timer,
+                                   stmmac_eee_ctrl_timer,
+                                   (unsigned long)priv);
+                       mod_timer(&priv->eee_ctrl_timer,
+                                 STMMAC_LPI_T(eee_timer));
 
                        priv->hw->mac->set_eee_timer(priv->hw,
                                                     STMMAC_DEFAULT_LIT_LS,
index fb846ebba1d9b0860acf920356aedfaf9d967f27..f9b42f11950f74dd38c41a9c535a14f94c51318b 100644 (file)
@@ -272,6 +272,37 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
        struct stmmac_priv *priv = NULL;
        struct plat_stmmacenet_data *plat_dat = NULL;
        const char *mac = NULL;
+       int irq, wol_irq, lpi_irq;
+
+       /* Get IRQ information early to have an ability to ask for deferred
+        * probe if needed before we went too far with resource allocation.
+        */
+       irq = platform_get_irq_byname(pdev, "macirq");
+       if (irq < 0) {
+               if (irq != -EPROBE_DEFER) {
+                       dev_err(dev,
+                               "MAC IRQ configuration information not found\n");
+               }
+               return irq;
+       }
+
+       /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
+        * The external wake up irq can be passed through the platform code
+        * named as "eth_wake_irq"
+        *
+        * In case the wake up interrupt is not passed from the platform
+        * so the driver will continue to use the mac irq (ndev->irq)
+        */
+       wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
+       if (wol_irq < 0) {
+               if (wol_irq == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+               wol_irq = irq;
+       }
+
+       lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
+       if (lpi_irq == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        addr = devm_ioremap_resource(dev, res);
@@ -323,39 +354,15 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
                return PTR_ERR(priv);
        }
 
+       /* Copy IRQ values to priv structure which is now avaialble */
+       priv->dev->irq = irq;
+       priv->wol_irq = wol_irq;
+       priv->lpi_irq = lpi_irq;
+
        /* Get MAC address if available (DT) */
        if (mac)
                memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
 
-       /* Get the MAC information */
-       priv->dev->irq = platform_get_irq_byname(pdev, "macirq");
-       if (priv->dev->irq < 0) {
-               if (priv->dev->irq != -EPROBE_DEFER) {
-                       netdev_err(priv->dev,
-                                  "MAC IRQ configuration information not found\n");
-               }
-               return priv->dev->irq;
-       }
-
-       /*
-        * On some platforms e.g. SPEAr the wake up irq differs from the mac irq
-        * The external wake up irq can be passed through the platform code
-        * named as "eth_wake_irq"
-        *
-        * In case the wake up interrupt is not passed from the platform
-        * so the driver will continue to use the mac irq (ndev->irq)
-        */
-       priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
-       if (priv->wol_irq < 0) {
-               if (priv->wol_irq == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-               priv->wol_irq = priv->dev->irq;
-       }
-
-       priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
-       if (priv->lpi_irq == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
-
        platform_set_drvdata(pdev, priv->dev);
 
        pr_debug("STMMAC platform driver registration completed");
index 4b51f903fb733cba9b9b8a3fe9539fe3bc811c84..0c5842aeb807014c632a2d713b366133d7021f56 100644 (file)
@@ -6989,10 +6989,10 @@ static int niu_class_to_ethflow(u64 class, int *flow_type)
                *flow_type = IP_USER_FLOW;
                break;
        default:
-               return 0;
+               return -EINVAL;
        }
 
-       return 1;
+       return 0;
 }
 
 static int niu_ethflow_to_class(int flow_type, u64 *class)
@@ -7198,11 +7198,9 @@ static int niu_get_ethtool_tcam_entry(struct niu *np,
        class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >>
                TCAM_V4KEY0_CLASS_CODE_SHIFT;
        ret = niu_class_to_ethflow(class, &fsp->flow_type);
-
        if (ret < 0) {
                netdev_info(np->dev, "niu%d: niu_class_to_ethflow failed\n",
                            parent->index);
-               ret = -EINVAL;
                goto out;
        }
 
index 7d8dd0d2182ef9f8d94d1e84b3c7a45f3364347c..a1bbaf6352ba379d209c7fc5cac33c8bfcbcb347 100644 (file)
@@ -1103,7 +1103,7 @@ static inline void cpsw_add_dual_emac_def_ale_entries(
        cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
                           port_mask, ALE_VLAN, slave->port_vlan, 0);
        cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
-               priv->host_port, ALE_VLAN, slave->port_vlan);
+               priv->host_port, ALE_VLAN | ALE_SECURE, slave->port_vlan);
 }
 
 static void soft_reset_slave(struct cpsw_slave *slave)
@@ -2466,6 +2466,7 @@ static int cpsw_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int cpsw_suspend(struct device *dev)
 {
        struct platform_device  *pdev = to_platform_device(dev);
@@ -2518,11 +2519,9 @@ static int cpsw_resume(struct device *dev)
        }
        return 0;
 }
+#endif
 
-static const struct dev_pm_ops cpsw_pm_ops = {
-       .suspend        = cpsw_suspend,
-       .resume         = cpsw_resume,
-};
+static SIMPLE_DEV_PM_OPS(cpsw_pm_ops, cpsw_suspend, cpsw_resume);
 
 static const struct of_device_id cpsw_of_mtable[] = {
        { .compatible = "ti,cpsw", },
index 98655b44b97e2d7690ef2fa28156730697098d2b..c00084d689f3ba99fe846c2e50f5b21daec73189 100644 (file)
@@ -423,6 +423,7 @@ static int davinci_mdio_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int davinci_mdio_suspend(struct device *dev)
 {
        struct davinci_mdio_data *data = dev_get_drvdata(dev);
@@ -464,10 +465,10 @@ static int davinci_mdio_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 static const struct dev_pm_ops davinci_mdio_pm_ops = {
-       .suspend_late   = davinci_mdio_suspend,
-       .resume_early   = davinci_mdio_resume,
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(davinci_mdio_suspend, davinci_mdio_resume)
 };
 
 #if IS_ENABLED(CONFIG_OF)
index a495931a66a1f217216cdb90a6b6989881039f32..0e0fbb5842b3d25e0d18ebaedfaeff60b006c1b7 100644 (file)
@@ -498,9 +498,9 @@ static int w5100_napi_poll(struct napi_struct *napi, int budget)
        }
 
        if (rx_count < budget) {
+               napi_complete(napi);
                w5100_write(priv, W5100_IMR, IR_S0);
                mmiowb();
-               napi_complete(napi);
        }
 
        return rx_count;
index 09322d9db5785ccb622a3ee3ec854442576bd537..4b310002258d0742031f4bcb36d395dd992d0a3d 100644 (file)
@@ -418,9 +418,9 @@ static int w5300_napi_poll(struct napi_struct *napi, int budget)
        }
 
        if (rx_count < budget) {
+               napi_complete(napi);
                w5300_write(priv, W5300_IMR, IR_S0);
                mmiowb();
-               napi_complete(napi);
        }
 
        return rx_count;
index f7e0f0f7c2e27dd19b2cbc674644cd4678074c2c..9e16a2819d4850938389c924e18f56184fedd946 100644 (file)
@@ -938,7 +938,7 @@ static void eth_set_mcast_list(struct net_device *dev)
        int i;
        static const u8 allmulti[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
-       if (dev->flags & IFF_ALLMULTI) {
+       if ((dev->flags & IFF_ALLMULTI) && !(dev->flags & IFF_PROMISC)) {
                for (i = 0; i < ETH_ALEN; i++) {
                        __raw_writel(allmulti[i], &port->regs->mcast_addr[i]);
                        __raw_writel(allmulti[i], &port->regs->mcast_mask[i]);
index e40fdfccc9c10df4ea8676a1dd59275d5d9c6b88..27ecc5c4fa2665cd42ac1ca81717255f85507113 100644 (file)
@@ -654,11 +654,14 @@ static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q,
        } /* else everything is zero */
 }
 
+/* Neighbour code has some assumptions on HH_DATA_MOD alignment */
+#define MACVTAP_RESERVE HH_DATA_OFF(ETH_HLEN)
+
 /* Get packet from user space buffer */
 static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                                struct iov_iter *from, int noblock)
 {
-       int good_linear = SKB_MAX_HEAD(NET_IP_ALIGN);
+       int good_linear = SKB_MAX_HEAD(MACVTAP_RESERVE);
        struct sk_buff *skb;
        struct macvlan_dev *vlan;
        unsigned long total_len = iov_iter_count(from);
@@ -722,7 +725,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                        linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
        }
 
-       skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, copylen,
+       skb = macvtap_alloc_skb(&q->sk, MACVTAP_RESERVE, copylen,
                                linear, noblock, &err);
        if (!skb)
                goto err;
index 9e3af54c90102a2c113596d326d893670b7e6c24..32efbd48f32642ddabb21126384b0c21e160a403 100644 (file)
@@ -92,6 +92,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define XGBE_PHY_CDR_RATE_PROPERTY     "amd,serdes-cdr-rate"
 #define XGBE_PHY_PQ_SKEW_PROPERTY      "amd,serdes-pq-skew"
 #define XGBE_PHY_TX_AMP_PROPERTY       "amd,serdes-tx-amp"
+#define XGBE_PHY_DFE_CFG_PROPERTY      "amd,serdes-dfe-tap-config"
+#define XGBE_PHY_DFE_ENA_PROPERTY      "amd,serdes-dfe-tap-enable"
 
 #define XGBE_PHY_SPEEDS                        3
 #define XGBE_PHY_SPEED_1000            0
@@ -177,10 +179,12 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_10000_BLWC               0
 #define SPEED_10000_CDR                        0x7
 #define SPEED_10000_PLL                        0x1
-#define SPEED_10000_PQ                 0x1e
+#define SPEED_10000_PQ                 0x12
 #define SPEED_10000_RATE               0x0
 #define SPEED_10000_TXAMP              0xa
 #define SPEED_10000_WORD               0x7
+#define SPEED_10000_DFE_TAP_CONFIG     0x1
+#define SPEED_10000_DFE_TAP_ENABLE     0x7f
 
 #define SPEED_2500_BLWC                        1
 #define SPEED_2500_CDR                 0x2
@@ -189,6 +193,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_2500_RATE                        0x1
 #define SPEED_2500_TXAMP               0xf
 #define SPEED_2500_WORD                        0x1
+#define SPEED_2500_DFE_TAP_CONFIG      0x3
+#define SPEED_2500_DFE_TAP_ENABLE      0x0
 
 #define SPEED_1000_BLWC                        1
 #define SPEED_1000_CDR                 0x2
@@ -197,16 +203,25 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_1000_RATE                        0x3
 #define SPEED_1000_TXAMP               0xf
 #define SPEED_1000_WORD                        0x1
+#define SPEED_1000_DFE_TAP_CONFIG      0x3
+#define SPEED_1000_DFE_TAP_ENABLE      0x0
 
 /* SerDes RxTx register offsets */
+#define RXTX_REG6                      0x0018
 #define RXTX_REG20                     0x0050
+#define RXTX_REG22                     0x0058
 #define RXTX_REG114                    0x01c8
+#define RXTX_REG129                    0x0204
 
 /* SerDes RxTx register entry bit positions and sizes */
+#define RXTX_REG6_RESETB_RXD_INDEX     8
+#define RXTX_REG6_RESETB_RXD_WIDTH     1
 #define RXTX_REG20_BLWC_ENA_INDEX      2
 #define RXTX_REG20_BLWC_ENA_WIDTH      1
 #define RXTX_REG114_PQ_REG_INDEX       9
 #define RXTX_REG114_PQ_REG_WIDTH       7
+#define RXTX_REG129_RXDFE_CONFIG_INDEX 14
+#define RXTX_REG129_RXDFE_CONFIG_WIDTH 2
 
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
@@ -333,6 +348,18 @@ static const u32 amd_xgbe_phy_serdes_tx_amp[] = {
        SPEED_10000_TXAMP,
 };
 
+static const u32 amd_xgbe_phy_serdes_dfe_tap_cfg[] = {
+       SPEED_1000_DFE_TAP_CONFIG,
+       SPEED_2500_DFE_TAP_CONFIG,
+       SPEED_10000_DFE_TAP_CONFIG,
+};
+
+static const u32 amd_xgbe_phy_serdes_dfe_tap_ena[] = {
+       SPEED_1000_DFE_TAP_ENABLE,
+       SPEED_2500_DFE_TAP_ENABLE,
+       SPEED_10000_DFE_TAP_ENABLE,
+};
+
 enum amd_xgbe_phy_an {
        AMD_XGBE_AN_READY = 0,
        AMD_XGBE_AN_PAGE_RECEIVED,
@@ -393,6 +420,8 @@ struct amd_xgbe_phy_priv {
        u32 serdes_cdr_rate[XGBE_PHY_SPEEDS];
        u32 serdes_pq_skew[XGBE_PHY_SPEEDS];
        u32 serdes_tx_amp[XGBE_PHY_SPEEDS];
+       u32 serdes_dfe_tap_cfg[XGBE_PHY_SPEEDS];
+       u32 serdes_dfe_tap_ena[XGBE_PHY_SPEEDS];
 
        /* Auto-negotiation state machine support */
        struct mutex an_mutex;
@@ -481,11 +510,16 @@ static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev)
                status = XSIR0_IOREAD(priv, SIR0_STATUS);
                if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) &&
                    XSIR_GET_BITS(status, SIR0_STATUS, TX_READY))
-                       return;
+                       goto rx_reset;
        }
 
        netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n",
                   status);
+
+rx_reset:
+       /* Perform Rx reset for the DFE changes */
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 0);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 1);
 }
 
 static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
@@ -534,6 +568,10 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
                           priv->serdes_blwc[XGBE_PHY_SPEED_10000]);
        XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
                           priv->serdes_pq_skew[XGBE_PHY_SPEED_10000]);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
+                          priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_10000]);
+       XRXTX_IOWRITE(priv, RXTX_REG22,
+                     priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_10000]);
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
@@ -586,6 +624,10 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev)
                           priv->serdes_blwc[XGBE_PHY_SPEED_2500]);
        XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
                           priv->serdes_pq_skew[XGBE_PHY_SPEED_2500]);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
+                          priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_2500]);
+       XRXTX_IOWRITE(priv, RXTX_REG22,
+                     priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_2500]);
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
@@ -638,6 +680,10 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev)
                           priv->serdes_blwc[XGBE_PHY_SPEED_1000]);
        XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
                           priv->serdes_pq_skew[XGBE_PHY_SPEED_1000]);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
+                          priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_1000]);
+       XRXTX_IOWRITE(priv, RXTX_REG22,
+                     priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_1000]);
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
@@ -1668,6 +1714,38 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev)
                       sizeof(priv->serdes_tx_amp));
        }
 
+       if (device_property_present(phy_dev, XGBE_PHY_DFE_CFG_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_PHY_DFE_CFG_PROPERTY,
+                                                    priv->serdes_dfe_tap_cfg,
+                                                    XGBE_PHY_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_PHY_DFE_CFG_PROPERTY);
+                       goto err_sir1;
+               }
+       } else {
+               memcpy(priv->serdes_dfe_tap_cfg,
+                      amd_xgbe_phy_serdes_dfe_tap_cfg,
+                      sizeof(priv->serdes_dfe_tap_cfg));
+       }
+
+       if (device_property_present(phy_dev, XGBE_PHY_DFE_ENA_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_PHY_DFE_ENA_PROPERTY,
+                                                    priv->serdes_dfe_tap_ena,
+                                                    XGBE_PHY_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_PHY_DFE_ENA_PROPERTY);
+                       goto err_sir1;
+               }
+       } else {
+               memcpy(priv->serdes_dfe_tap_ena,
+                      amd_xgbe_phy_serdes_dfe_tap_ena,
+                      sizeof(priv->serdes_dfe_tap_ena));
+       }
+
        phydev->priv = priv;
 
        if (!priv->adev || acpi_disabled)
index cdcac6aa4260b32927d7c903e024b42e5d17861e..52cd8db2c57daad2767dec72149f4cdabbcf6917 100644 (file)
@@ -235,6 +235,25 @@ static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
        return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
 }
 
+/**
+ * phy_check_valid - check if there is a valid PHY setting which matches
+ *                  speed, duplex, and feature mask
+ * @speed: speed to match
+ * @duplex: duplex to match
+ * @features: A mask of the valid settings
+ *
+ * Description: Returns true if there is a valid setting, false otherwise.
+ */
+static inline bool phy_check_valid(int speed, int duplex, u32 features)
+{
+       unsigned int idx;
+
+       idx = phy_find_valid(phy_find_setting(speed, duplex), features);
+
+       return settings[idx].speed == speed && settings[idx].duplex == duplex &&
+               (settings[idx].setting & features);
+}
+
 /**
  * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex
  * @phydev: the target phy_device struct
@@ -1045,7 +1064,6 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
                int eee_lp, eee_cap, eee_adv;
                u32 lp, cap, adv;
                int status;
-               unsigned int idx;
 
                /* Read phy status to properly get the right settings */
                status = phy_read_status(phydev);
@@ -1077,8 +1095,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
 
                adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
                lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
-               idx = phy_find_setting(phydev->speed, phydev->duplex);
-               if (!(lp & adv & settings[idx].setting))
+               if (!phy_check_valid(phydev->speed, phydev->duplex, lp & adv))
                        goto eee_exit_err;
 
                if (clk_stop_enable) {
index 0e62274e884a89de170d668795b40c3620d41046..7d394846afc214900f9e85baa2130f6f6121ac33 100644 (file)
@@ -43,9 +43,7 @@
 
 static struct team_port *team_port_get_rcu(const struct net_device *dev)
 {
-       struct team_port *port = rcu_dereference(dev->rx_handler_data);
-
-       return team_port_exists(dev) ? port : NULL;
+       return rcu_dereference(dev->rx_handler_data);
 }
 
 static struct team_port *team_port_get_rtnl(const struct net_device *dev)
@@ -1732,11 +1730,11 @@ static int team_set_mac_address(struct net_device *dev, void *p)
        if (dev->type == ARPHRD_ETHER && !is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       rcu_read_lock();
-       list_for_each_entry_rcu(port, &team->port_list, list)
+       mutex_lock(&team->lock);
+       list_for_each_entry(port, &team->port_list, list)
                if (team->ops.port_change_dev_addr)
                        team->ops.port_change_dev_addr(team, port);
-       rcu_read_unlock();
+       mutex_unlock(&team->lock);
        return 0;
 }
 
index 3bd9678315ad651beccd96ca1b5d74bcd1e68c1e..7ba8d0885f120156c47f44884212a2fd73f604b9 100644 (file)
@@ -161,6 +161,7 @@ config USB_NET_AX8817X
            * Linksys USB200M
            * Netgear FA120
            * Sitecom LN-029
+           * Sitecom LN-028
            * Intellinet USB 2.0 Ethernet
            * ST Lab USB 2.0 Ethernet
            * TrendNet TU2-ET100
index bf49792062a2b40c2f1bd2f5a06e6eff8954ab90..1173a24feda38c3af236c84acaf8982f39c0e0b1 100644 (file)
@@ -978,6 +978,10 @@ static const struct usb_device_id  products [] = {
        // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter"
        USB_DEVICE (0x0df6, 0x0056),
        .driver_info =  (unsigned long) &ax88178_info,
+}, {
+       // Sitecom LN-028 "USB 2.0 10/100/1000 Ethernet adapter"
+       USB_DEVICE (0x0df6, 0x061c),
+       .driver_info =  (unsigned long) &ax88178_info,
 }, {
        // corega FEther USB2-TX
        USB_DEVICE (0x07aa, 0x0017),
index 3eed708a6182e761fb79d197eadfbcbc028e5afc..1762ad3910b2e75b55db894afee887f055977b22 100644 (file)
@@ -46,8 +46,7 @@ enum cx82310_status {
 };
 
 #define CMD_PACKET_SIZE        64
-/* first command after power on can take around 8 seconds */
-#define CMD_TIMEOUT    15000
+#define CMD_TIMEOUT    100
 #define CMD_REPLY_RETRY 5
 
 #define CX82310_MTU    1514
@@ -78,8 +77,9 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
        ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf,
                           CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT);
        if (ret < 0) {
-               dev_err(&dev->udev->dev, "send command %#x: error %d\n",
-                       cmd, ret);
+               if (cmd != CMD_GET_LINK_STATUS)
+                       dev_err(&dev->udev->dev, "send command %#x: error %d\n",
+                               cmd, ret);
                goto end;
        }
 
@@ -90,8 +90,10 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
                                           buf, CMD_PACKET_SIZE, &actual_len,
                                           CMD_TIMEOUT);
                        if (ret < 0) {
-                               dev_err(&dev->udev->dev,
-                                       "reply receive error %d\n", ret);
+                               if (cmd != CMD_GET_LINK_STATUS)
+                                       dev_err(&dev->udev->dev,
+                                               "reply receive error %d\n",
+                                               ret);
                                goto end;
                        }
                        if (actual_len > 0)
@@ -134,6 +136,8 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
        int ret;
        char buf[15];
        struct usb_device *udev = dev->udev;
+       u8 link[3];
+       int timeout = 50;
 
        /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */
        if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0
@@ -160,6 +164,20 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
        if (!dev->partial_data)
                return -ENOMEM;
 
+       /* wait for firmware to become ready (indicated by the link being up) */
+       while (--timeout) {
+               ret = cx82310_cmd(dev, CMD_GET_LINK_STATUS, true, NULL, 0,
+                                 link, sizeof(link));
+               /* the command can time out during boot - it's not an error */
+               if (!ret && link[0] == 1 && link[2] == 1)
+                       break;
+               msleep(500);
+       };
+       if (!timeout) {
+               dev_err(&udev->dev, "firmware not ready in time\n");
+               return -ETIMEDOUT;
+       }
+
        /* enable ethernet mode (?) */
        ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0);
        if (ret) {
@@ -300,9 +318,18 @@ static const struct driver_info    cx82310_info = {
        .tx_fixup       = cx82310_tx_fixup,
 };
 
+#define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+                      USB_DEVICE_ID_MATCH_DEV_INFO, \
+       .idVendor = (vend), \
+       .idProduct = (prod), \
+       .bDeviceClass = (cl), \
+       .bDeviceSubClass = (sc), \
+       .bDeviceProtocol = (pr)
+
 static const struct usb_device_id products[] = {
        {
-               USB_DEVICE_AND_INTERFACE_INFO(0x0572, 0xcb01, 0xff, 0, 0),
+               USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0),
                .driver_info = (unsigned long) &cx82310_info
        },
        { },
index 9cdfb3fe9c156ba775d41a9d6d343ddbb5fc9b60..778e91531fac7f35480208ba35f6ae3e6c9ad5b2 100644 (file)
@@ -1594,7 +1594,7 @@ hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
                }
                cprev = cnow;
        }
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        remove_wait_queue(&tiocmget->waitq, &wait);
 
        return ret;
index 3d18bb0eee8528ece6509ec3848c3044ff5804ce..1bfe0fcaccf5ba31bf125f898ec6c624f506206e 100644 (file)
@@ -134,6 +134,11 @@ static const struct usb_device_id  products [] = {
 }, {
        USB_DEVICE(0x050d, 0x258a),     /* Belkin F5U258/F5U279 (PL-25A1) */
        .driver_info =  (unsigned long) &prolific_info,
+}, {
+       USB_DEVICE(0x3923, 0x7825),     /* National Instruments USB
+                                        * Host-to-Host Cable
+                                        */
+       .driver_info =  (unsigned long) &prolific_info,
 },
 
        { },            // END
index f1ff3666f090d886e6b8ecc99bc6ac09d8687ef6..59b0e9754ae39cbc38812d407688f66f5e79b539 100644 (file)
@@ -1448,8 +1448,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
 {
        int i;
 
-       for (i = 0; i < vi->max_queue_pairs; i++)
+       for (i = 0; i < vi->max_queue_pairs; i++) {
+               napi_hash_del(&vi->rq[i].napi);
                netif_napi_del(&vi->rq[i].napi);
+       }
 
        kfree(vi->rq);
        kfree(vi->sq);
@@ -1948,11 +1950,8 @@ static int virtnet_freeze(struct virtio_device *vdev)
        cancel_delayed_work_sync(&vi->refill);
 
        if (netif_running(vi->dev)) {
-               for (i = 0; i < vi->max_queue_pairs; i++) {
+               for (i = 0; i < vi->max_queue_pairs; i++)
                        napi_disable(&vi->rq[i].napi);
-                       napi_hash_del(&vi->rq[i].napi);
-                       netif_napi_del(&vi->rq[i].napi);
-               }
        }
 
        remove_vq_common(vi);
index 1e0a775ea882995d88127e4d3c2a8f3f0afb8d60..f8528a4cf54f2b0bc78b78bd705a82577530bdeb 100644 (file)
@@ -1218,7 +1218,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                        goto drop;
 
                flags &= ~VXLAN_HF_RCO;
-               vni &= VXLAN_VID_MASK;
+               vni &= VXLAN_VNI_MASK;
        }
 
        /* For backwards compatibility, only allow reserved fields to be
@@ -1239,7 +1239,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                flags &= ~VXLAN_GBP_USED_BITS;
        }
 
-       if (flags || (vni & ~VXLAN_VID_MASK)) {
+       if (flags || vni & ~VXLAN_VNI_MASK) {
                /* If there are any unprocessed flags remaining treat
                 * this as a malformed packet. This behavior diverges from
                 * VXLAN RFC (RFC7348) which stipulates that bits in reserved
index 83c39e2858bf70a1673cf2c6d9813a92f25ce4d3..88d121d43c08bedf2efc3265964188cf2b7f94a7 100644 (file)
@@ -806,21 +806,21 @@ static ssize_t cosa_read(struct file *file,
        spin_lock_irqsave(&cosa->lock, flags);
        add_wait_queue(&chan->rxwaitq, &wait);
        while (!chan->rx_status) {
-               current->state = TASK_INTERRUPTIBLE;
+               set_current_state(TASK_INTERRUPTIBLE);
                spin_unlock_irqrestore(&cosa->lock, flags);
                schedule();
                spin_lock_irqsave(&cosa->lock, flags);
                if (signal_pending(current) && chan->rx_status == 0) {
                        chan->rx_status = 1;
                        remove_wait_queue(&chan->rxwaitq, &wait);
-                       current->state = TASK_RUNNING;
+                       __set_current_state(TASK_RUNNING);
                        spin_unlock_irqrestore(&cosa->lock, flags);
                        mutex_unlock(&chan->rlock);
                        return -ERESTARTSYS;
                }
        }
        remove_wait_queue(&chan->rxwaitq, &wait);
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        kbuf = chan->rxdata;
        count = chan->rxsize;
        spin_unlock_irqrestore(&cosa->lock, flags);
@@ -890,14 +890,14 @@ static ssize_t cosa_write(struct file *file,
        spin_lock_irqsave(&cosa->lock, flags);
        add_wait_queue(&chan->txwaitq, &wait);
        while (!chan->tx_status) {
-               current->state = TASK_INTERRUPTIBLE;
+               set_current_state(TASK_INTERRUPTIBLE);
                spin_unlock_irqrestore(&cosa->lock, flags);
                schedule();
                spin_lock_irqsave(&cosa->lock, flags);
                if (signal_pending(current) && chan->tx_status == 0) {
                        chan->tx_status = 1;
                        remove_wait_queue(&chan->txwaitq, &wait);
-                       current->state = TASK_RUNNING;
+                       __set_current_state(TASK_RUNNING);
                        chan->tx_status = 1;
                        spin_unlock_irqrestore(&cosa->lock, flags);
                        up(&chan->wsem);
@@ -905,7 +905,7 @@ static ssize_t cosa_write(struct file *file,
                }
        }
        remove_wait_queue(&chan->txwaitq, &wait);
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        up(&chan->wsem);
        spin_unlock_irqrestore(&cosa->lock, flags);
        kfree(kbuf);
index ccbdb05b28cd7e2dc457afe9443e35ac2ca3fc21..75345c1e8c3487468a23611a3072d525cdc8b8ca 100644 (file)
@@ -5370,6 +5370,7 @@ static void b43_supported_bands(struct b43_wldev *dev, bool *have_2ghz_phy,
        case 0x432a: /* BCM4321 */
        case 0x432d: /* BCM4322 */
        case 0x4352: /* BCM43222 */
+       case 0x435a: /* BCM43228 */
        case 0x4333: /* BCM4331 */
        case 0x43a2: /* BCM4360 */
        case 0x43b3: /* BCM4352 */
index 50cdf7090198b3662b83488ff52e3868162401c5..8eff2753abadeb2704f87f88f7c5eabd75bf091b 100644 (file)
@@ -39,13 +39,22 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
        void *dcmd_buf = NULL, *wr_pointer;
        u16 msglen, maxmsglen = PAGE_SIZE - 0x100;
 
-       brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set,
-                 cmdhdr->len);
+       if (len < sizeof(*cmdhdr)) {
+               brcmf_err("vendor command too short: %d\n", len);
+               return -EINVAL;
+       }
 
        vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
        ifp = vif->ifp;
 
-       len -= sizeof(struct brcmf_vndr_dcmd_hdr);
+       brcmf_dbg(TRACE, "ifidx=%d, cmd=%d\n", ifp->ifidx, cmdhdr->cmd);
+
+       if (cmdhdr->offset > len) {
+               brcmf_err("bad buffer offset %d > %d\n", cmdhdr->offset, len);
+               return -EINVAL;
+       }
+
+       len -= cmdhdr->offset;
        ret_len = cmdhdr->len;
        if (ret_len > 0 || len > 0) {
                if (len > BRCMF_DCMD_MAXLEN) {
index c3817fae16c04207136e5d45e8cc65bd3a125429..06f6cc08f451cadc7696c5b1810735288a85b1a9 100644 (file)
@@ -95,7 +95,8 @@ static const struct iwl_eeprom_params iwl1000_eeprom_params = {
        .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION,  \
        .base_params = &iwl1000_base_params,                    \
        .eeprom_params = &iwl1000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl1000_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
@@ -121,7 +122,8 @@ const struct iwl_cfg iwl1000_bg_cfg = {
        .base_params = &iwl1000_base_params,                    \
        .eeprom_params = &iwl1000_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl100_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
index 21e5d0843a62a84a0f21ff337d1b674750fa3999..890b95f497d6eca97949a5e3989926d5b4d17d38 100644 (file)
@@ -123,7 +123,9 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
        .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,          \
        .base_params = &iwl2000_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
+
 
 const struct iwl_cfg iwl2000_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
@@ -149,7 +151,8 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
        .base_params = &iwl2030_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl2030_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
@@ -170,7 +173,8 @@ const struct iwl_cfg iwl2030_2bgn_cfg = {
        .base_params = &iwl2000_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl105_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
@@ -197,7 +201,8 @@ const struct iwl_cfg iwl105_bgn_d_cfg = {
        .base_params = &iwl2030_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl135_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
index 332bbede39e5b0fc6bb25b7ab30bbbd22c929b8b..724194e234141e707dac6eb8ec57563435957aae 100644 (file)
@@ -93,7 +93,8 @@ static const struct iwl_eeprom_params iwl5000_eeprom_params = {
        .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION,  \
        .base_params = &iwl5000_base_params,                    \
        .eeprom_params = &iwl5000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl5300_agn_cfg = {
        .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
@@ -158,7 +159,8 @@ const struct iwl_cfg iwl5350_agn_cfg = {
        .base_params = &iwl5000_base_params,                    \
        .eeprom_params = &iwl5000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl5150_agn_cfg = {
        .name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
index 8f2c3c8c6b843f78f346225d371ee3ad3df54f23..21b2630763dc933db72f54fd7fadba9244d6b449 100644 (file)
@@ -145,7 +145,8 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = {
        .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6005_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
@@ -199,7 +200,8 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
        .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6030_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
@@ -235,7 +237,8 @@ const struct iwl_cfg iwl6030_2bg_cfg = {
        .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6035_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
@@ -290,7 +293,8 @@ const struct iwl_cfg iwl130_bg_cfg = {
        .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION,  \
        .base_params = &iwl6000_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6000i_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
@@ -322,7 +326,8 @@ const struct iwl_cfg iwl6000i_2bg_cfg = {
        .base_params = &iwl6050_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6050_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
@@ -347,7 +352,8 @@ const struct iwl_cfg iwl6050_2abg_cfg = {
        .base_params = &iwl6050_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6150_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
index 1ec4d55155f7d72fecdbe19db62dd36546bb05e0..7810c41cf9a7300e0d3b9bc16bca22a44188b463 100644 (file)
@@ -793,7 +793,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
-       if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
+       if (mvmvif->phy_ctxt &&
+           IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
                               mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
index d530ef3da1071e5a421db3f4c072504b3571d8e3..542ee74f290aec1a3f356b3c69718b5029c4e708 100644 (file)
@@ -832,7 +832,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
-       if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
+       if (mvmvif->phy_ctxt &&
+           data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
        IWL_DEBUG_COEX(data->mvm,
index 1ff7ec08532d113aa5be85cb59eed8100e3f7eed..09654e73a533f7733c2a5b1e47bf6251d6267585 100644 (file)
@@ -405,7 +405,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
                        &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
 
-               if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER)
+               if ((mvm->fw->ucode_capa.capa[0] &
+                    IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
+                   (mvm->fw->ucode_capa.api[0] &
+                    IWL_UCODE_TLV_API_LQ_SS_PARAMS))
                        hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |=
                                IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
        }
@@ -2215,7 +2218,19 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
 
        mutex_lock(&mvm->mutex);
 
-       iwl_mvm_cancel_scan(mvm);
+       /* Due to a race condition, it's possible that mac80211 asks
+        * us to stop a hw_scan when it's already stopped.  This can
+        * happen, for instance, if we stopped the scan ourselves,
+        * called ieee80211_scan_completed() and the userspace called
+        * cancel scan scan before ieee80211_scan_work() could run.
+        * To handle that, simply return if the scan is not running.
+       */
+       /* FIXME: for now, we ignore this race for UMAC scans, since
+        * they don't set the scan_status.
+        */
+       if ((mvm->scan_status == IWL_MVM_SCAN_OS) ||
+           (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+               iwl_mvm_cancel_scan(mvm);
 
        mutex_unlock(&mvm->mutex);
 }
@@ -2559,12 +2574,29 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
        int ret;
 
        mutex_lock(&mvm->mutex);
+
+       /* Due to a race condition, it's possible that mac80211 asks
+        * us to stop a sched_scan when it's already stopped.  This
+        * can happen, for instance, if we stopped the scan ourselves,
+        * called ieee80211_sched_scan_stopped() and the userspace called
+        * stop sched scan scan before ieee80211_sched_scan_stopped_work()
+        * could run.  To handle this, simply return if the scan is
+        * not running.
+       */
+       /* FIXME: for now, we ignore this race for UMAC scans, since
+        * they don't set the scan_status.
+        */
+       if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
+           !(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+               mutex_unlock(&mvm->mutex);
+               return 0;
+       }
+
        ret = iwl_mvm_scan_offload_stop(mvm, false);
        mutex_unlock(&mvm->mutex);
        iwl_mvm_wait_for_async_handlers(mvm);
 
        return ret;
-
 }
 
 static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
index 194bd1f939ca3c6a42e9c4a9d6cc7eb843c2d256..efa9688a4cf11150f6d1e92c71e0a367d90fea87 100644 (file)
@@ -134,9 +134,12 @@ enum rs_column_mode {
 #define MAX_NEXT_COLUMNS 7
 #define MAX_COLUMN_CHECKS 3
 
+struct rs_tx_column;
+
 typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm,
                                     struct ieee80211_sta *sta,
-                                    struct iwl_scale_tbl_info *tbl);
+                                    struct iwl_scale_tbl_info *tbl,
+                                    const struct rs_tx_column *next_col);
 
 struct rs_tx_column {
        enum rs_column_mode mode;
@@ -147,13 +150,15 @@ struct rs_tx_column {
 };
 
 static bool rs_ant_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                        struct iwl_scale_tbl_info *tbl)
+                        struct iwl_scale_tbl_info *tbl,
+                        const struct rs_tx_column *next_col)
 {
-       return iwl_mvm_bt_coex_is_ant_avail(mvm, tbl->rate.ant);
+       return iwl_mvm_bt_coex_is_ant_avail(mvm, next_col->ant);
 }
 
 static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                         struct iwl_scale_tbl_info *tbl)
+                         struct iwl_scale_tbl_info *tbl,
+                         const struct rs_tx_column *next_col)
 {
        if (!sta->ht_cap.ht_supported)
                return false;
@@ -171,7 +176,8 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 }
 
 static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                         struct iwl_scale_tbl_info *tbl)
+                         struct iwl_scale_tbl_info *tbl,
+                         const struct rs_tx_column *next_col)
 {
        if (!sta->ht_cap.ht_supported)
                return false;
@@ -180,7 +186,8 @@ static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 }
 
 static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                        struct iwl_scale_tbl_info *tbl)
+                        struct iwl_scale_tbl_info *tbl,
+                        const struct rs_tx_column *next_col)
 {
        struct rs_rate *rate = &tbl->rate;
        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
@@ -1590,7 +1597,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
 
                for (j = 0; j < MAX_COLUMN_CHECKS; j++) {
                        allow_func = next_col->checks[j];
-                       if (allow_func && !allow_func(mvm, sta, tbl))
+                       if (allow_func && !allow_func(mvm, sta, tbl, next_col))
                                break;
                }
 
index 7e9aa3cb325401fcf4105e278294b11657a90df1..c47c8051da7770f2a2a89c9b33868151c62f0ff6 100644 (file)
@@ -1128,8 +1128,10 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        if (mvm->scan_status == IWL_MVM_SCAN_NONE)
                return 0;
 
-       if (iwl_mvm_is_radio_killed(mvm))
+       if (iwl_mvm_is_radio_killed(mvm)) {
+               ret = 0;
                goto out;
+       }
 
        if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
            (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
@@ -1148,16 +1150,14 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
                IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n",
                               sched ? "offloaded " : "", ret);
                iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
-               return ret;
+               goto out;
        }
 
        IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
                       sched ? "offloaded " : "");
 
        ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
-       if (ret)
-               return ret;
-
+out:
        /*
         * Clear the scan status so the next scan requests will succeed. This
         * also ensures the Rx handler doesn't do anything, as the scan was
@@ -1167,7 +1167,6 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        if (mvm->scan_status == IWL_MVM_SCAN_OS)
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
 
-out:
        mvm->scan_status = IWL_MVM_SCAN_NONE;
 
        if (notify) {
@@ -1177,7 +1176,7 @@ out:
                        ieee80211_scan_completed(mvm->hw, true);
        }
 
-       return 0;
+       return ret;
 }
 
 static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm,
index 54fafbf9a711fb9bacb3149fcb9f8ce1826c4b90..f8d6f306dd76d276b82056c9fb1a74956e78ac3c 100644 (file)
@@ -750,8 +750,7 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
         * request
         */
        list_for_each_entry(te_data, &mvm->time_event_list, list) {
-               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE &&
-                   te_data->running) {
+               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
                        mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
                        is_p2p = true;
                        goto remove_te;
@@ -766,10 +765,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
         * request
         */
        list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {
-               if (te_data->running) {
-                       mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
-                       goto remove_te;
-               }
+               mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+               goto remove_te;
        }
 
 remove_te:
index 4a4c6586a8d2dcda2b6f49a5b767bcc48304e138..8908be6dbc48233db9183247e1928bfab6eaa491 100644 (file)
@@ -946,7 +946,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
                goto nla_put_failure;
 
        genlmsg_end(skb, msg_head);
-       genlmsg_unicast(&init_net, skb, dst_portid);
+       if (genlmsg_unicast(&init_net, skb, dst_portid))
+               goto err_free_txskb;
 
        /* Enqueue the packet */
        skb_queue_tail(&data->pending, my_skb);
@@ -955,6 +956,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
        return;
 
 nla_put_failure:
+       nlmsg_free(skb);
+err_free_txskb:
        printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
        ieee80211_free_txskb(hw, my_skb);
        data->tx_failed++;
index 1d46774607116af89f96c6e835cb84775ddaa8ca..074f716020aae4e28d3e8340da846514065a94db 100644 (file)
@@ -1386,8 +1386,11 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
                }
 
                return true;
-       } else if (0x86DD == ether_type) {
-               return true;
+       } else if (ETH_P_IPV6 == ether_type) {
+               /* TODO: Handle any IPv6 cases that need special handling.
+                * For now, always return false
+                */
+               goto end;
        }
 
 end:
index f38227afe0998a668c40e2194def6128895bb077..3aa8648080c8dee1133b9faf0b6ac0c2ad538a9b 100644 (file)
@@ -340,12 +340,11 @@ static void xenvif_get_ethtool_stats(struct net_device *dev,
        unsigned int num_queues = vif->num_queues;
        int i;
        unsigned int queue_index;
-       struct xenvif_stats *vif_stats;
 
        for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++) {
                unsigned long accum = 0;
                for (queue_index = 0; queue_index < num_queues; ++queue_index) {
-                       vif_stats = &vif->queues[queue_index].stats;
+                       void *vif_stats = &vif->queues[queue_index].stats;
                        accum += *(unsigned long *)(vif_stats + xenvif_stats[i].offset);
                }
                data[i] = accum;
index f7a31d2cb3f1819fdf7ebdeb40e0f6bf44aabe0a..997cf0901ac2dc50d92f26ea2c5c4e51511b8362 100644 (file)
@@ -96,6 +96,7 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
 static void make_tx_response(struct xenvif_queue *queue,
                             struct xen_netif_tx_request *txp,
                             s8       st);
+static void push_tx_responses(struct xenvif_queue *queue);
 
 static inline int tx_work_todo(struct xenvif_queue *queue);
 
@@ -657,6 +658,7 @@ static void xenvif_tx_err(struct xenvif_queue *queue,
        do {
                spin_lock_irqsave(&queue->response_lock, flags);
                make_tx_response(queue, txp, XEN_NETIF_RSP_ERROR);
+               push_tx_responses(queue);
                spin_unlock_irqrestore(&queue->response_lock, flags);
                if (cons == end)
                        break;
@@ -1343,7 +1345,7 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s
 {
        unsigned int offset = skb_headlen(skb);
        skb_frag_t frags[MAX_SKB_FRAGS];
-       int i;
+       int i, f;
        struct ubuf_info *uarg;
        struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
 
@@ -1383,23 +1385,25 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s
                frags[i].page_offset = 0;
                skb_frag_size_set(&frags[i], len);
        }
-       /* swap out with old one */
-       memcpy(skb_shinfo(skb)->frags,
-              frags,
-              i * sizeof(skb_frag_t));
-       skb_shinfo(skb)->nr_frags = i;
-       skb->truesize += i * PAGE_SIZE;
 
-       /* remove traces of mapped pages and frag_list */
+       /* Copied all the bits from the frag list -- free it. */
        skb_frag_list_init(skb);
+       xenvif_skb_zerocopy_prepare(queue, nskb);
+       kfree_skb(nskb);
+
+       /* Release all the original (foreign) frags. */
+       for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+               skb_frag_unref(skb, f);
        uarg = skb_shinfo(skb)->destructor_arg;
        /* increase inflight counter to offset decrement in callback */
        atomic_inc(&queue->inflight_packets);
        uarg->callback(uarg, true);
        skb_shinfo(skb)->destructor_arg = NULL;
 
-       xenvif_skb_zerocopy_prepare(queue, nskb);
-       kfree_skb(nskb);
+       /* Fill the skb with the new (local) frags. */
+       memcpy(skb_shinfo(skb)->frags, frags, i * sizeof(skb_frag_t));
+       skb_shinfo(skb)->nr_frags = i;
+       skb->truesize += i * PAGE_SIZE;
 
        return 0;
 }
@@ -1652,13 +1656,20 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
        unsigned long flags;
 
        pending_tx_info = &queue->pending_tx_info[pending_idx];
+
        spin_lock_irqsave(&queue->response_lock, flags);
+
        make_tx_response(queue, &pending_tx_info->req, status);
-       index = pending_index(queue->pending_prod);
+
+       /* Release the pending index before pusing the Tx response so
+        * its available before a new Tx request is pushed by the
+        * frontend.
+        */
+       index = pending_index(queue->pending_prod++);
        queue->pending_ring[index] = pending_idx;
-       /* TX shouldn't use the index before we give it back here */
-       mb();
-       queue->pending_prod++;
+
+       push_tx_responses(queue);
+
        spin_unlock_irqrestore(&queue->response_lock, flags);
 }
 
@@ -1669,7 +1680,6 @@ static void make_tx_response(struct xenvif_queue *queue,
 {
        RING_IDX i = queue->tx.rsp_prod_pvt;
        struct xen_netif_tx_response *resp;
-       int notify;
 
        resp = RING_GET_RESPONSE(&queue->tx, i);
        resp->id     = txp->id;
@@ -1679,6 +1689,12 @@ static void make_tx_response(struct xenvif_queue *queue,
                RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL;
 
        queue->tx.rsp_prod_pvt = ++i;
+}
+
+static void push_tx_responses(struct xenvif_queue *queue)
+{
+       int notify;
+
        RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
        if (notify)
                notify_remote_via_irq(queue->tx_irq);
index 38d1c51f58b108dbee2b2a2c83f970f60471c569..7bcaeec876c0c3a5ea80a01d13b13b186bb2227f 100644 (file)
@@ -84,8 +84,7 @@ config OF_RESOLVE
        bool
 
 config OF_OVERLAY
-       bool
-       depends on OF
+       bool "Device Tree overlays"
        select OF_DYNAMIC
        select OF_RESOLVE
 
index 0a8aeb8523fe7d54a66207f25eb145e88addb90d..8f165b112e03a285899655984491b000f0020e17 100644 (file)
@@ -714,16 +714,12 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent,
                                                const char *path)
 {
        struct device_node *child;
-       int len = strchrnul(path, '/') - path;
-       int term;
+       int len;
 
+       len = strcspn(path, "/:");
        if (!len)
                return NULL;
 
-       term = strchrnul(path, ':') - path;
-       if (term < len)
-               len = term;
-
        __for_each_child_of_node(parent, child) {
                const char *name = strrchr(child->full_name, '/');
                if (WARN(!name, "malformed device_node %s\n", child->full_name))
@@ -768,8 +764,12 @@ struct device_node *of_find_node_opts_by_path(const char *path, const char **opt
 
        /* The path could begin with an alias */
        if (*path != '/') {
-               char *p = strchrnul(path, '/');
-               int len = separator ? separator - path : p - path;
+               int len;
+               const char *p = separator;
+
+               if (!p)
+                       p = strchrnul(path, '/');
+               len = p - path;
 
                /* of_aliases must not be NULL */
                if (!of_aliases)
@@ -794,6 +794,8 @@ struct device_node *of_find_node_opts_by_path(const char *path, const char **opt
                path++; /* Increment past '/' delimiter */
                np = __of_find_node_by_path(np, path);
                path = strchrnul(path, '/');
+               if (separator && separator < path)
+                       break;
        }
        raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
index 0d7765807f4940c1aa892665a78e0b32c4128528..1a7980692f254c6917371dec5a11f77f448723cf 100644 (file)
@@ -290,7 +290,7 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
        struct device_node *p;
        const __be32 *intspec, *tmp, *addr;
        u32 intsize, intlen;
-       int i, res = -EINVAL;
+       int i, res;
 
        pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
 
@@ -323,15 +323,19 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
 
        /* Get size of interrupt specifier */
        tmp = of_get_property(p, "#interrupt-cells", NULL);
-       if (tmp == NULL)
+       if (tmp == NULL) {
+               res = -EINVAL;
                goto out;
+       }
        intsize = be32_to_cpu(*tmp);
 
        pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
 
        /* Check index */
-       if ((index + 1) * intsize > intlen)
+       if ((index + 1) * intsize > intlen) {
+               res = -EINVAL;
                goto out;
+       }
 
        /* Copy intspec into irq structure */
        intspec += index * intsize;
index 352b4f28f82cd729fb842a210e7460ff9f123833..dee9270ba5471e730518b0ddc647469c8a52776f 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/idr.h>
 
 #include "of_private.h"
 
@@ -85,7 +86,7 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
                struct device_node *target, struct device_node *child)
 {
        const char *cname;
-       struct device_node *tchild, *grandchild;
+       struct device_node *tchild;
        int ret = 0;
 
        cname = kbasename(child->full_name);
index 0cf9a236d438a78c63e0949f9f010f4ba2f199f7..52c45c7df07ff6623c7fb7656961f8bdcf804da3 100644 (file)
@@ -92,6 +92,16 @@ static void __init of_selftest_find_node_by_name(void)
                 "option path test failed\n");
        of_node_put(np);
 
+       np = of_find_node_opts_by_path("/testcase-data:test/option", &options);
+       selftest(np && !strcmp("test/option", options),
+                "option path test, subcase #1 failed\n");
+       of_node_put(np);
+
+       np = of_find_node_opts_by_path("/testcase-data/testcase-device1:test/option", &options);
+       selftest(np && !strcmp("test/option", options),
+                "option path test, subcase #2 failed\n");
+       of_node_put(np);
+
        np = of_find_node_opts_by_path("/testcase-data:testoption", NULL);
        selftest(np, "NULL option path test failed\n");
        of_node_put(np);
@@ -102,6 +112,12 @@ static void __init of_selftest_find_node_by_name(void)
                 "option alias path test failed\n");
        of_node_put(np);
 
+       np = of_find_node_opts_by_path("testcase-alias:test/alias/option",
+                                      &options);
+       selftest(np && !strcmp("test/alias/option", options),
+                "option alias path test, subcase #1 failed\n");
+       of_node_put(np);
+
        np = of_find_node_opts_by_path("testcase-alias:testaliasoption", NULL);
        selftest(np, "NULL option alias path test failed\n");
        of_node_put(np);
@@ -378,9 +394,9 @@ static void __init of_selftest_property_string(void)
        rc = of_property_match_string(np, "phandle-list-names", "first");
        selftest(rc == 0, "first expected:0 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "second");
-       selftest(rc == 1, "second expected:0 got:%i\n", rc);
+       selftest(rc == 1, "second expected:1 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "third");
-       selftest(rc == 2, "third expected:0 got:%i\n", rc);
+       selftest(rc == 2, "third expected:2 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "fourth");
        selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc);
        rc = of_property_match_string(np, "missing-property", "blah");
@@ -478,7 +494,6 @@ static void __init of_selftest_changeset(void)
        struct device_node *n1, *n2, *n21, *nremove, *parent, *np;
        struct of_changeset chgset;
 
-       of_changeset_init(&chgset);
        n1 = __of_node_dup(NULL, "/testcase-data/changeset/n1");
        selftest(n1, "testcase setup failure\n");
        n2 = __of_node_dup(NULL, "/testcase-data/changeset/n2");
@@ -979,7 +994,7 @@ static int of_path_platform_device_exists(const char *path)
        return pdev != NULL;
 }
 
-#if IS_ENABLED(CONFIG_I2C)
+#if IS_BUILTIN(CONFIG_I2C)
 
 /* get the i2c client device instantiated at the path */
 static struct i2c_client *of_path_to_i2c_client(const char *path)
@@ -1445,7 +1460,7 @@ static void of_selftest_overlay_11(void)
                return;
 }
 
-#if IS_ENABLED(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY)
+#if IS_BUILTIN(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY)
 
 struct selftest_i2c_bus_data {
        struct platform_device  *pdev;
@@ -1584,7 +1599,7 @@ static struct i2c_driver selftest_i2c_dev_driver = {
        .id_table = selftest_i2c_dev_id,
 };
 
-#if IS_ENABLED(CONFIG_I2C_MUX)
+#if IS_BUILTIN(CONFIG_I2C_MUX)
 
 struct selftest_i2c_mux_data {
        int nchans;
@@ -1695,7 +1710,7 @@ static int of_selftest_overlay_i2c_init(void)
                        "could not register selftest i2c bus driver\n"))
                return ret;
 
-#if IS_ENABLED(CONFIG_I2C_MUX)
+#if IS_BUILTIN(CONFIG_I2C_MUX)
        ret = i2c_add_driver(&selftest_i2c_mux_driver);
        if (selftest(ret == 0,
                        "could not register selftest i2c mux driver\n"))
@@ -1707,7 +1722,7 @@ static int of_selftest_overlay_i2c_init(void)
 
 static void of_selftest_overlay_i2c_cleanup(void)
 {
-#if IS_ENABLED(CONFIG_I2C_MUX)
+#if IS_BUILTIN(CONFIG_I2C_MUX)
        i2c_del_driver(&selftest_i2c_mux_driver);
 #endif
        platform_driver_unregister(&selftest_i2c_bus_driver);
@@ -1814,7 +1829,7 @@ static void __init of_selftest_overlay(void)
        of_selftest_overlay_10();
        of_selftest_overlay_11();
 
-#if IS_ENABLED(CONFIG_I2C)
+#if IS_BUILTIN(CONFIG_I2C)
        if (selftest(of_selftest_overlay_i2c_init() == 0, "i2c init failed\n"))
                goto out;
 
index 1ec694a52379ea4c753cc1b397c931bc940bb1cc..464bf492ee2ae375e8fe92e0a5446dbdf0461f9d 100644 (file)
@@ -80,7 +80,7 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
        if (err)
                return err;
 
-       resource_list_for_each_entry(win, res, list) {
+       resource_list_for_each_entry(win, res) {
                struct resource *parent, *res = win->res;
 
                switch (resource_type(res)) {
index aab55474dd0d6a4bd661ccbb160f1c2e8dc3c69c..ee082c0366ecca0d9978f9b23589646a0999a174 100644 (file)
@@ -127,7 +127,7 @@ static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset)
        return false;
 }
 
-static int xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
+static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
                              int offset)
 {
        struct xgene_pcie_port *port = bus->sysdata;
@@ -137,7 +137,7 @@ static int xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
                return NULL;
 
        xgene_pcie_set_rtdid_reg(bus, devfn);
-       return xgene_pcie_get_cfg_base(bus);
+       return xgene_pcie_get_cfg_base(bus) + offset;
 }
 
 static struct pci_ops xgene_pcie_ops = {
index aa012fb3834b48dbc0001565d453b2dc267009c1..312f23a8429cd9331b45afaf72a278e84bd41d83 100644 (file)
@@ -521,7 +521,8 @@ static ssize_t driver_override_store(struct device *dev,
        struct pci_dev *pdev = to_pci_dev(dev);
        char *driver_override, *old = pdev->driver_override, *cp;
 
-       if (count > PATH_MAX)
+       /* We need to keep extra room for a newline */
+       if (count >= (PAGE_SIZE - 1))
                return -EINVAL;
 
        driver_override = kstrndup(buf, count, GFP_KERNEL);
@@ -549,7 +550,7 @@ static ssize_t driver_override_show(struct device *dev,
 {
        struct pci_dev *pdev = to_pci_dev(dev);
 
-       return sprintf(buf, "%s\n", pdev->driver_override);
+       return snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override);
 }
 static DEVICE_ATTR_RW(driver_override);
 
index 3bb49252a098b0b3d4c72b0895044c538d2af17d..45f67c63d38539a091fde716bb0c5aa8a18b2b8b 100644 (file)
@@ -69,8 +69,7 @@ config YENTA
        tristate "CardBus yenta-compatible bridge support"
        depends on PCI
        select CARDBUS if !EXPERT
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC if PCMCIA != n
        ---help---
          This option enables support for CardBus host bridges.  Virtually
          all modern PCMCIA bridges are CardBus compatible.  A "bridge" is
@@ -110,8 +109,7 @@ config YENTA_TOSHIBA
 config PD6729
        tristate "Cirrus PD6729 compatible bridge support"
        depends on PCMCIA && PCI
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC
        help
          This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge
          device, found in some older laptops and PCMCIA card readers.
@@ -119,8 +117,7 @@ config PD6729
 config I82092
        tristate "i82092 compatible bridge support"
        depends on PCMCIA && PCI
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC
        help
          This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
          found in some older laptops and more commonly in evaluation boards for the
@@ -291,9 +288,6 @@ config ELECTRA_CF
          Say Y here to support the CompactFlash controller on the
          PA Semi Electra eval board.
 
-config PCCARD_PCI
-       bool
-
 config PCCARD_NONSTATIC
        bool
 
index f1a7ca04d89e9b743fc3f82e545c52521fedef81..27e94b30cf9625b8da99d67b74308651b8077dc6 100644 (file)
@@ -12,7 +12,6 @@ obj-$(CONFIG_PCMCIA)                          += pcmcia.o
 pcmcia_rsrc-y                                  += rsrc_mgr.o
 pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC)         += rsrc_nonstatic.o
 pcmcia_rsrc-$(CONFIG_PCCARD_IODYN)             += rsrc_iodyn.o
-pcmcia_rsrc-$(CONFIG_PCCARD_PCI)               += rsrc_pci.o
 obj-$(CONFIG_PCCARD)                           += pcmcia_rsrc.o
 
 
diff --git a/drivers/pcmcia/rsrc_pci.c b/drivers/pcmcia/rsrc_pci.c
deleted file mode 100644 (file)
index 1f67b3b..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-
-#include <pcmcia/ss.h>
-#include <pcmcia/cistpl.h>
-#include "cs_internal.h"
-
-
-struct pcmcia_align_data {
-       unsigned long   mask;
-       unsigned long   offset;
-};
-
-static resource_size_t pcmcia_align(void *align_data,
-                               const struct resource *res,
-                               resource_size_t size, resource_size_t align)
-{
-       struct pcmcia_align_data *data = align_data;
-       resource_size_t start;
-
-       start = (res->start & ~data->mask) + data->offset;
-       if (start < res->start)
-               start += data->mask + 1;
-       return start;
-}
-
-static struct resource *find_io_region(struct pcmcia_socket *s,
-                                       unsigned long base, int num,
-                                       unsigned long align)
-{
-       struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
-                                               dev_name(&s->dev));
-       struct pcmcia_align_data data;
-       int ret;
-
-       data.mask = align - 1;
-       data.offset = base & data.mask;
-
-       ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
-                                            base, 0, pcmcia_align, &data);
-       if (ret != 0) {
-               kfree(res);
-               res = NULL;
-       }
-       return res;
-}
-
-static int res_pci_find_io(struct pcmcia_socket *s, unsigned int attr,
-                       unsigned int *base, unsigned int num,
-                       unsigned int align, struct resource **parent)
-{
-       int i, ret = 0;
-
-       /* Check for an already-allocated window that must conflict with
-        * what was asked for.  It is a hack because it does not catch all
-        * potential conflicts, just the most obvious ones.
-        */
-       for (i = 0; i < MAX_IO_WIN; i++) {
-               if (!s->io[i].res)
-                       continue;
-
-               if (!*base)
-                       continue;
-
-               if ((s->io[i].res->start & (align-1)) == *base)
-                       return -EBUSY;
-       }
-
-       for (i = 0; i < MAX_IO_WIN; i++) {
-               struct resource *res = s->io[i].res;
-               unsigned int try;
-
-               if (res && (res->flags & IORESOURCE_BITS) !=
-                       (attr & IORESOURCE_BITS))
-                       continue;
-
-               if (!res) {
-                       if (align == 0)
-                               align = 0x10000;
-
-                       res = s->io[i].res = find_io_region(s, *base, num,
-                                                               align);
-                       if (!res)
-                               return -EINVAL;
-
-                       *base = res->start;
-                       s->io[i].res->flags =
-                               ((res->flags & ~IORESOURCE_BITS) |
-                                       (attr & IORESOURCE_BITS));
-                       s->io[i].InUse = num;
-                       *parent = res;
-                       return 0;
-               }
-
-               /* Try to extend top of window */
-               try = res->end + 1;
-               if ((*base == 0) || (*base == try)) {
-                       ret = adjust_resource(s->io[i].res, res->start,
-                                             resource_size(res) + num);
-                       if (ret)
-                               continue;
-                       *base = try;
-                       s->io[i].InUse += num;
-                       *parent = res;
-                       return 0;
-               }
-
-               /* Try to extend bottom of window */
-               try = res->start - num;
-               if ((*base == 0) || (*base == try)) {
-                       ret = adjust_resource(s->io[i].res,
-                                             res->start - num,
-                                             resource_size(res) + num);
-                       if (ret)
-                               continue;
-                       *base = try;
-                       s->io[i].InUse += num;
-                       *parent = res;
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static struct resource *res_pci_find_mem(u_long base, u_long num,
-               u_long align, int low, struct pcmcia_socket *s)
-{
-       struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
-                                               dev_name(&s->dev));
-       struct pcmcia_align_data data;
-       unsigned long min;
-       int ret;
-
-       if (align < 0x20000)
-               align = 0x20000;
-       data.mask = align - 1;
-       data.offset = base & data.mask;
-
-       min = 0;
-       if (!low)
-               min = 0x100000UL;
-
-       ret = pci_bus_alloc_resource(s->cb_dev->bus,
-                       res, num, 1, min, 0,
-                       pcmcia_align, &data);
-
-       if (ret != 0) {
-               kfree(res);
-               res = NULL;
-       }
-       return res;
-}
-
-
-static int res_pci_init(struct pcmcia_socket *s)
-{
-       if (!s->cb_dev || !(s->features & SS_CAP_PAGE_REGS)) {
-               dev_err(&s->dev, "not supported by res_pci\n");
-               return -EOPNOTSUPP;
-       }
-       return 0;
-}
-
-struct pccard_resource_ops pccard_nonstatic_ops = {
-       .validate_mem = NULL,
-       .find_io = res_pci_find_io,
-       .find_mem = res_pci_find_mem,
-       .init = res_pci_init,
-       .exit = NULL,
-};
-EXPORT_SYMBOL(pccard_nonstatic_ops);
index 7c99ca256f059f79d4b288140da3feef5e0a67f8..8ccc3952c13dca6287b04a6b62fe50d1ceb076d6 100644 (file)
@@ -37,7 +37,7 @@ static int armada375_usb_phy_init(struct phy *phy)
        struct armada375_cluster_phy *cluster_phy;
        u32 reg;
 
-       cluster_phy = dev_get_drvdata(phy->dev.parent);
+       cluster_phy = phy_get_drvdata(phy);
        if (!cluster_phy)
                return -ENODEV;
 
@@ -131,6 +131,7 @@ static int armada375_usb_phy_probe(struct platform_device *pdev)
        cluster_phy->reg = usb_cluster_base;
 
        dev_set_drvdata(dev, cluster_phy);
+       phy_set_drvdata(phy, cluster_phy);
 
        phy_provider = devm_of_phy_provider_register(&pdev->dev,
                                                     armada375_usb_phy_xlate);
index a12d35338313bd4f4a67117f3c5c3f76030e53fd..3791838f4bd4b14e145dd5718a3030c4b89d9f3b 100644 (file)
@@ -52,7 +52,9 @@ static void devm_phy_consume(struct device *dev, void *res)
 
 static int devm_phy_match(struct device *dev, void *res, void *match_data)
 {
-       return res == match_data;
+       struct phy **phy = res;
+
+       return *phy == match_data;
 }
 
 /**
@@ -223,6 +225,7 @@ int phy_init(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->init_count == 0 && phy->ops->init) {
@@ -231,8 +234,6 @@ int phy_init(struct phy *phy)
                        dev_err(&phy->dev, "phy init failed --> %d\n", ret);
                        goto out;
                }
-       } else {
-               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->init_count;
 
@@ -253,6 +254,7 @@ int phy_exit(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->init_count == 1 && phy->ops->exit) {
@@ -287,6 +289,7 @@ int phy_power_on(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->power_count == 0 && phy->ops->power_on) {
@@ -295,8 +298,6 @@ int phy_power_on(struct phy *phy)
                        dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
                        goto out;
                }
-       } else {
-               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->power_count;
        mutex_unlock(&phy->mutex);
index f86cbe68ddaf30fd1a5a377c2f7d9dfb1c259c8f..179cbf9451aacf1aca440e46eb05493f41037e48 100644 (file)
@@ -30,28 +30,13 @@ struct exynos_dp_video_phy {
        const struct exynos_dp_video_phy_drvdata *drvdata;
 };
 
-static void exynos_dp_video_phy_pwr_isol(struct exynos_dp_video_phy *state,
-                                                       unsigned int on)
-{
-       unsigned int val;
-
-       if (IS_ERR(state->regs))
-               return;
-
-       val = on ? 0 : EXYNOS5_PHY_ENABLE;
-
-       regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
-                          EXYNOS5_PHY_ENABLE, val);
-}
-
 static int exynos_dp_video_phy_power_on(struct phy *phy)
 {
        struct exynos_dp_video_phy *state = phy_get_drvdata(phy);
 
        /* Disable power isolation on DP-PHY */
-       exynos_dp_video_phy_pwr_isol(state, 0);
-
-       return 0;
+       return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
+                                 EXYNOS5_PHY_ENABLE, EXYNOS5_PHY_ENABLE);
 }
 
 static int exynos_dp_video_phy_power_off(struct phy *phy)
@@ -59,9 +44,8 @@ static int exynos_dp_video_phy_power_off(struct phy *phy)
        struct exynos_dp_video_phy *state = phy_get_drvdata(phy);
 
        /* Enable power isolation on DP-PHY */
-       exynos_dp_video_phy_pwr_isol(state, 1);
-
-       return 0;
+       return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
+                                 EXYNOS5_PHY_ENABLE, 0);
 }
 
 static struct phy_ops exynos_dp_video_phy_ops = {
index f017b2f2a54ecb18c8aa7b0fed3c375f790e48d4..df7519a39ba0b15fd9181a3c3c9bcba17fcd34e9 100644 (file)
@@ -43,7 +43,6 @@ struct exynos_mipi_video_phy {
        } phys[EXYNOS_MIPI_PHYS_NUM];
        spinlock_t slock;
        void __iomem *regs;
-       struct mutex mutex;
        struct regmap *regmap;
 };
 
@@ -59,8 +58,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
        else
                reset = EXYNOS4_MIPI_PHY_SRESETN;
 
-       if (state->regmap) {
-               mutex_lock(&state->mutex);
+       spin_lock(&state->slock);
+
+       if (!IS_ERR(state->regmap)) {
                regmap_read(state->regmap, offset, &val);
                if (on)
                        val |= reset;
@@ -72,11 +72,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
                else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
                        val &= ~EXYNOS4_MIPI_PHY_ENABLE;
                regmap_write(state->regmap, offset, val);
-               mutex_unlock(&state->mutex);
        } else {
                addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
 
-               spin_lock(&state->slock);
                val = readl(addr);
                if (on)
                        val |= reset;
@@ -90,9 +88,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
                        val &= ~EXYNOS4_MIPI_PHY_ENABLE;
 
                writel(val, addr);
-               spin_unlock(&state->slock);
        }
 
+       spin_unlock(&state->slock);
        return 0;
 }
 
@@ -158,7 +156,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
 
        dev_set_drvdata(dev, state);
        spin_lock_init(&state->slock);
-       mutex_init(&state->mutex);
 
        for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
                struct phy *phy = devm_phy_create(dev, NULL,
index 236a52ad94eb705a6be6ea9813838ded256f76e1..f30bbb0fb3b2652e897c1922a7f51e48b3dc270f 100644 (file)
@@ -250,7 +250,6 @@ static const struct samsung_usb2_common_phy exynos4210_phys[] = {
                .power_on       = exynos4210_power_on,
                .power_off      = exynos4210_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
index 0b9de88579b13264a0eae49c4e159bad70aac3b1..765da90a536f057f9e3ccfc4bfe24868a388a63f 100644 (file)
@@ -361,7 +361,6 @@ static const struct samsung_usb2_common_phy exynos4x12_phys[] = {
                .power_on       = exynos4x12_power_on,
                .power_off      = exynos4x12_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos3250_usb2_phy_config = {
index 04374018425f9ab488dea49dd797f68aa5b339c1..e2a0be750ad962d82e2666e5005a8b8daf97f381 100644 (file)
@@ -531,7 +531,7 @@ static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev,
 {
        struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev);
 
-       if (WARN_ON(args->args[0] > EXYNOS5_DRDPHYS_NUM))
+       if (WARN_ON(args->args[0] >= EXYNOS5_DRDPHYS_NUM))
                return ERR_PTR(-ENODEV);
 
        return phy_drd->phys[args->args[0]].phy;
index 1c139aa0d074324e74a5f95bb06e83cea2818abf..2ed1735a076a1f8a50898de3d3de28bc7dfa235d 100644 (file)
@@ -391,7 +391,6 @@ static const struct samsung_usb2_common_phy exynos5250_phys[] = {
                .power_on       = exynos5250_power_on,
                .power_off      = exynos5250_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
index 34915b4202f18c5249a059dd42aa914fee2e7f2d..d6b22659cac11cfb4187cf9347ac86774f79de5e 100644 (file)
@@ -147,6 +147,9 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
        priv->base = devm_ioremap(dev, res->start, resource_size(res));
        if (!priv->base)
                return -ENOMEM;
index 9b2848e6115d44d050d7858ac75d01df60f71da3..933435214acce1db8895b95cc739138288b3de4b 100644 (file)
@@ -228,6 +228,7 @@ struct miphy28lp_dev {
        struct regmap *regmap;
        struct mutex miphy_mutex;
        struct miphy28lp_phy **phys;
+       int nphys;
 };
 
 struct miphy_initval {
@@ -1116,7 +1117,7 @@ static struct phy *miphy28lp_xlate(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       for (index = 0; index < of_get_child_count(dev->of_node); index++)
+       for (index = 0; index < miphy_dev->nphys; index++)
                if (phynode == miphy_dev->phys[index]->phy->dev.of_node) {
                        miphy_phy = miphy_dev->phys[index];
                        break;
@@ -1138,6 +1139,7 @@ static struct phy *miphy28lp_xlate(struct device *dev,
 
 static struct phy_ops miphy28lp_ops = {
        .init = miphy28lp_init,
+       .owner = THIS_MODULE,
 };
 
 static int miphy28lp_probe_resets(struct device_node *node,
@@ -1200,16 +1202,15 @@ static int miphy28lp_probe(struct platform_device *pdev)
        struct miphy28lp_dev *miphy_dev;
        struct phy_provider *provider;
        struct phy *phy;
-       int chancount, port = 0;
-       int ret;
+       int ret, port = 0;
 
        miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
        if (!miphy_dev)
                return -ENOMEM;
 
-       chancount = of_get_child_count(np);
-       miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount,
-                                      GFP_KERNEL);
+       miphy_dev->nphys = of_get_child_count(np);
+       miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys,
+                                      sizeof(*miphy_dev->phys), GFP_KERNEL);
        if (!miphy_dev->phys)
                return -ENOMEM;
 
index 6c80154e8bffb23253e03d546edd68a11ad3e0b0..51b459db9137417bb26fa971df92e6d8e86121ed 100644 (file)
@@ -150,6 +150,7 @@ struct miphy365x_dev {
        struct regmap *regmap;
        struct mutex miphy_mutex;
        struct miphy365x_phy **phys;
+       int nphys;
 };
 
 /*
@@ -485,7 +486,7 @@ static struct phy *miphy365x_xlate(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       for (index = 0; index < of_get_child_count(dev->of_node); index++)
+       for (index = 0; index < miphy_dev->nphys; index++)
                if (phynode == miphy_dev->phys[index]->phy->dev.of_node) {
                        miphy_phy = miphy_dev->phys[index];
                        break;
@@ -541,16 +542,15 @@ static int miphy365x_probe(struct platform_device *pdev)
        struct miphy365x_dev *miphy_dev;
        struct phy_provider *provider;
        struct phy *phy;
-       int chancount, port = 0;
-       int ret;
+       int ret, port = 0;
 
        miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
        if (!miphy_dev)
                return -ENOMEM;
 
-       chancount = of_get_child_count(np);
-       miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount,
-                                      GFP_KERNEL);
+       miphy_dev->nphys = of_get_child_count(np);
+       miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys,
+                                      sizeof(*miphy_dev->phys), GFP_KERNEL);
        if (!miphy_dev->phys)
                return -ENOMEM;
 
index efe724f97e02fbf9eba84c215628993fa3ea1274..93252e053a31ca752fe54bd0fc71760d318f2579 100644 (file)
@@ -360,7 +360,7 @@ static void __exit omap_control_phy_exit(void)
 }
 module_exit(omap_control_phy_exit);
 
-MODULE_ALIAS("platform: omap_control_phy");
+MODULE_ALIAS("platform:omap_control_phy");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("OMAP Control Module PHY Driver");
 MODULE_LICENSE("GPL v2");
index 6f4aef3db2481de0dc03df70521242a9be5d7fa5..4757e765696a232d1926ece274ef35111188cdc1 100644 (file)
@@ -296,10 +296,11 @@ static int omap_usb2_probe(struct platform_device *pdev)
                        dev_warn(&pdev->dev,
                                 "found usb_otg_ss_refclk960m, please fix DTS\n");
                }
-       } else {
-               clk_prepare(phy->optclk);
        }
 
+       if (!IS_ERR(phy->optclk))
+               clk_prepare(phy->optclk);
+
        usb_add_phy_dev(&phy->phy);
 
        return 0;
@@ -383,7 +384,7 @@ static struct platform_driver omap_usb2_driver = {
 
 module_platform_driver(omap_usb2_driver);
 
-MODULE_ALIAS("platform: omap_usb2");
+MODULE_ALIAS("platform:omap_usb2");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("OMAP USB2 phy driver");
 MODULE_LICENSE("GPL v2");
index 22011c3b6a4bbdc3a3734a3ca27c665fcf099de8..7d4c33643768808780f71455900bc7dd51329103 100644 (file)
@@ -61,8 +61,6 @@ static int rockchip_usb_phy_power_off(struct phy *_phy)
                return ret;
 
        clk_disable_unprepare(phy->clk);
-       if (ret)
-               return ret;
 
        return 0;
 }
@@ -78,8 +76,10 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
 
        /* Power up usb phy analog blocks by set siddq 0 */
        ret = rockchip_usb_phy_power(phy, 0);
-       if (ret)
+       if (ret) {
+               clk_disable_unprepare(phy->clk);
                return ret;
+       }
 
        return 0;
 }
index 95c88f929f27f7d4113961e90215f3e769fe75f5..2ba610b72ca202842df7f6b43b18c7da17af1d1c 100644 (file)
@@ -165,15 +165,11 @@ static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy)
                cpu_relax();
                val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
                if (val & PLL_LOCK)
-                       break;
+                       return 0;
        } while (!time_after(jiffies, timeout));
 
-       if (!(val & PLL_LOCK)) {
-               dev_err(phy->dev, "DPLL failed to lock\n");
-               return -EBUSY;
-       }
-
-       return 0;
+       dev_err(phy->dev, "DPLL failed to lock\n");
+       return -EBUSY;
 }
 
 static int ti_pipe3_dpll_program(struct ti_pipe3 *phy)
@@ -608,7 +604,7 @@ static struct platform_driver ti_pipe3_driver = {
 
 module_platform_driver(ti_pipe3_driver);
 
-MODULE_ALIAS("platform: ti_pipe3");
+MODULE_ALIAS("platform:ti_pipe3");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("TI PIPE3 phy driver");
 MODULE_LICENSE("GPL v2");
index 8e87f54671f32de11915a7921824fc4a8929ab84..bc42d6a8939f4efd85fb1e10ea6d12faa1b76e97 100644 (file)
@@ -666,7 +666,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        twl->dev                = &pdev->dev;
        twl->irq                = platform_get_irq(pdev, 0);
        twl->vbus_supplied      = false;
-       twl->linkstat           = -EINVAL;
        twl->linkstat           = OMAP_MUSB_UNKNOWN;
 
        twl->phy.dev            = twl->dev;
index 29214a36ea28ef0c13ab972693f23e004fa77612..2263cd01003211e6d81a39fcb7a48538ba08e2c1 100644 (file)
@@ -1704,7 +1704,6 @@ static int xgene_phy_probe(struct platform_device *pdev)
        for (i = 0; i < MAX_LANE; i++)
                ctx->sata_param.speed[i] = 2; /* Default to Gen3 */
 
-       ctx->dev = &pdev->dev;
        platform_set_drvdata(pdev, ctx);
 
        ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops);
index 5afe03e28b911223c8909229d513a7c0e99fef4e..2062c224e32fbe7ee73da7b283205040fbd7164c 100644 (file)
 #define BYT_DIR_MASK           (BIT(1) | BIT(2))
 #define BYT_TRIG_MASK          (BIT(26) | BIT(25) | BIT(24))
 
+#define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | \
+                                BYT_PIN_MUX)
+#define BYT_VAL_RESTORE_MASK   (BYT_DIR_MASK | BYT_LEVEL)
+
 #define BYT_NGPIO_SCORE                102
 #define BYT_NGPIO_NCORE                28
 #define BYT_NGPIO_SUS          44
@@ -134,12 +138,18 @@ static struct pinctrl_gpio_range byt_ranges[] = {
        },
 };
 
+struct byt_gpio_pin_context {
+       u32 conf0;
+       u32 val;
+};
+
 struct byt_gpio {
        struct gpio_chip                chip;
        struct platform_device          *pdev;
        spinlock_t                      lock;
        void __iomem                    *reg_base;
        struct pinctrl_gpio_range       *range;
+       struct byt_gpio_pin_context     *saved_context;
 };
 
 #define to_byt_gpio(c) container_of(c, struct byt_gpio, chip)
@@ -158,40 +168,62 @@ static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
        return vg->reg_base + reg_offset + reg;
 }
 
-static bool is_special_pin(struct byt_gpio *vg, unsigned offset)
+static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned offset)
+{
+       void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+       unsigned long flags;
+       u32 value;
+
+       spin_lock_irqsave(&vg->lock, flags);
+       value = readl(reg);
+       value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
+       writel(value, reg);
+       spin_unlock_irqrestore(&vg->lock, flags);
+}
+
+static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset)
 {
        /* SCORE pin 92-93 */
        if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) &&
                offset >= 92 && offset <= 93)
-               return true;
+               return 1;
 
        /* SUS pin 11-21 */
        if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) &&
                offset >= 11 && offset <= 21)
-               return true;
+               return 1;
 
-       return false;
+       return 0;
 }
 
 static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
        struct byt_gpio *vg = to_byt_gpio(chip);
        void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
-       u32 value;
-       bool special;
+       u32 value, gpio_mux;
 
        /*
         * In most cases, func pin mux 000 means GPIO function.
         * But, some pins may have func pin mux 001 represents
-        * GPIO function. Only allow user to export pin with
-        * func pin mux preset as GPIO function by BIOS/FW.
+        * GPIO function.
+        *
+        * Because there are devices out there where some pins were not
+        * configured correctly we allow changing the mux value from
+        * request (but print out warning about that).
         */
        value = readl(reg) & BYT_PIN_MUX;
-       special = is_special_pin(vg, offset);
-       if ((special && value != 1) || (!special && value)) {
-               dev_err(&vg->pdev->dev,
-                       "pin %u cannot be used as GPIO.\n", offset);
-               return -EINVAL;
+       gpio_mux = byt_get_gpio_mux(vg, offset);
+       if (WARN_ON(gpio_mux != value)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&vg->lock, flags);
+               value = readl(reg) & ~BYT_PIN_MUX;
+               value |= gpio_mux;
+               writel(value, reg);
+               spin_unlock_irqrestore(&vg->lock, flags);
+
+               dev_warn(&vg->pdev->dev,
+                        "pin %u forcibly re-configured as GPIO\n", offset);
        }
 
        pm_runtime_get(&vg->pdev->dev);
@@ -202,14 +234,8 @@ static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
        struct byt_gpio *vg = to_byt_gpio(chip);
-       void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
-       u32 value;
-
-       /* clear interrupt triggering */
-       value = readl(reg);
-       value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
-       writel(value, reg);
 
+       byt_gpio_clear_triggering(vg, offset);
        pm_runtime_put(&vg->pdev->dev);
 }
 
@@ -236,23 +262,13 @@ static int byt_irq_type(struct irq_data *d, unsigned type)
        value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG |
                   BYT_TRIG_LVL);
 
-       switch (type) {
-       case IRQ_TYPE_LEVEL_HIGH:
-               value |= BYT_TRIG_LVL;
-       case IRQ_TYPE_EDGE_RISING:
-               value |= BYT_TRIG_POS;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               value |= BYT_TRIG_LVL;
-       case IRQ_TYPE_EDGE_FALLING:
-               value |= BYT_TRIG_NEG;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
-               break;
-       }
        writel(value, reg);
 
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
+       else if (type & IRQ_TYPE_LEVEL_MASK)
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+
        spin_unlock_irqrestore(&vg->lock, flags);
 
        return 0;
@@ -410,58 +426,80 @@ static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
        struct irq_data *data = irq_desc_get_irq_data(desc);
        struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc));
        struct irq_chip *chip = irq_data_get_irq_chip(data);
-       u32 base, pin, mask;
+       u32 base, pin;
        void __iomem *reg;
-       u32 pending;
+       unsigned long pending;
        unsigned virq;
-       int looplimit = 0;
 
        /* check from GPIO controller which pin triggered the interrupt */
        for (base = 0; base < vg->chip.ngpio; base += 32) {
-
                reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
-
-               while ((pending = readl(reg))) {
-                       pin = __ffs(pending);
-                       mask = BIT(pin);
-                       /* Clear before handling so we can't lose an edge */
-                       writel(mask, reg);
-
+               pending = readl(reg);
+               for_each_set_bit(pin, &pending, 32) {
                        virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
                        generic_handle_irq(virq);
-
-                       /* In case bios or user sets triggering incorretly a pin
-                        * might remain in "interrupt triggered" state.
-                        */
-                       if (looplimit++ > 32) {
-                               dev_err(&vg->pdev->dev,
-                                       "Gpio %d interrupt flood, disabling\n",
-                                       base + pin);
-
-                               reg = byt_gpio_reg(&vg->chip, base + pin,
-                                                  BYT_CONF0_REG);
-                               mask = readl(reg);
-                               mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS |
-                                         BYT_TRIG_LVL);
-                               writel(mask, reg);
-                               mask = readl(reg); /* flush */
-                               break;
-                       }
                }
        }
        chip->irq_eoi(data);
 }
 
+static void byt_irq_ack(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+       unsigned offset = irqd_to_hwirq(d);
+       void __iomem *reg;
+
+       reg = byt_gpio_reg(&vg->chip, offset, BYT_INT_STAT_REG);
+       writel(BIT(offset % 32), reg);
+}
+
 static void byt_irq_unmask(struct irq_data *d)
 {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+       unsigned offset = irqd_to_hwirq(d);
+       unsigned long flags;
+       void __iomem *reg;
+       u32 value;
+
+       spin_lock_irqsave(&vg->lock, flags);
+
+       reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+       value = readl(reg);
+
+       switch (irqd_get_trigger_type(d)) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               value |= BYT_TRIG_LVL;
+       case IRQ_TYPE_EDGE_RISING:
+               value |= BYT_TRIG_POS;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               value |= BYT_TRIG_LVL;
+       case IRQ_TYPE_EDGE_FALLING:
+               value |= BYT_TRIG_NEG;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
+               break;
+       }
+
+       writel(value, reg);
+
+       spin_unlock_irqrestore(&vg->lock, flags);
 }
 
 static void byt_irq_mask(struct irq_data *d)
 {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+
+       byt_gpio_clear_triggering(vg, irqd_to_hwirq(d));
 }
 
 static struct irq_chip byt_irqchip = {
        .name = "BYT-GPIO",
+       .irq_ack = byt_irq_ack,
        .irq_mask = byt_irq_mask,
        .irq_unmask = byt_irq_unmask,
        .irq_set_type = byt_irq_type,
@@ -472,6 +510,21 @@ static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
 {
        void __iomem *reg;
        u32 base, value;
+       int i;
+
+       /*
+        * Clear interrupt triggers for all pins that are GPIOs and
+        * do not use direct IRQ mode. This will prevent spurious
+        * interrupts from misconfigured pins.
+        */
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               value = readl(byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG));
+               if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i) &&
+                   !(value & BYT_DIRECT_IRQ_EN)) {
+                       byt_gpio_clear_triggering(vg, i);
+                       dev_dbg(&vg->pdev->dev, "disabling GPIO %d\n", i);
+               }
+       }
 
        /* clear interrupt status trigger registers */
        for (base = 0; base < vg->chip.ngpio; base += 32) {
@@ -541,6 +594,11 @@ static int byt_gpio_probe(struct platform_device *pdev)
        gc->can_sleep = false;
        gc->dev = dev;
 
+#ifdef CONFIG_PM_SLEEP
+       vg->saved_context = devm_kcalloc(&pdev->dev, gc->ngpio,
+                                      sizeof(*vg->saved_context), GFP_KERNEL);
+#endif
+
        ret = gpiochip_add(gc);
        if (ret) {
                dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
@@ -569,6 +627,69 @@ static int byt_gpio_probe(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int byt_gpio_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct byt_gpio *vg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               void __iomem *reg;
+               u32 value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG);
+               value = readl(reg) & BYT_CONF0_RESTORE_MASK;
+               vg->saved_context[i].conf0 = value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_VAL_REG);
+               value = readl(reg) & BYT_VAL_RESTORE_MASK;
+               vg->saved_context[i].val = value;
+       }
+
+       return 0;
+}
+
+static int byt_gpio_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct byt_gpio *vg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               void __iomem *reg;
+               u32 value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG);
+               value = readl(reg);
+               if ((value & BYT_CONF0_RESTORE_MASK) !=
+                    vg->saved_context[i].conf0) {
+                       value &= ~BYT_CONF0_RESTORE_MASK;
+                       value |= vg->saved_context[i].conf0;
+                       writel(value, reg);
+                       dev_info(dev, "restored pin %d conf0 %#08x", i, value);
+               }
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_VAL_REG);
+               value = readl(reg);
+               if ((value & BYT_VAL_RESTORE_MASK) !=
+                    vg->saved_context[i].val) {
+                       u32 v;
+
+                       v = value & ~BYT_VAL_RESTORE_MASK;
+                       v |= vg->saved_context[i].val;
+                       if (v != value) {
+                               writel(v, reg);
+                               dev_dbg(dev, "restored pin %d val %#08x\n",
+                                       i, v);
+                       }
+               }
+       }
+
+       return 0;
+}
+#endif
+
 static int byt_gpio_runtime_suspend(struct device *dev)
 {
        return 0;
@@ -580,8 +701,9 @@ static int byt_gpio_runtime_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops byt_gpio_pm_ops = {
-       .runtime_suspend = byt_gpio_runtime_suspend,
-       .runtime_resume = byt_gpio_runtime_resume,
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(byt_gpio_suspend, byt_gpio_resume)
+       SET_RUNTIME_PM_OPS(byt_gpio_runtime_suspend, byt_gpio_runtime_resume,
+                          NULL)
 };
 
 static const struct acpi_device_id byt_gpio_acpi_match[] = {
index 3034fd03bced3ff7587f8bfd248c7bb212a0c16c..82f691eeeec4d82cd5e75b7a96be719befbcd57f 100644 (file)
@@ -1226,6 +1226,7 @@ static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
                                     int value)
 {
+       chv_gpio_set(chip, offset, value);
        return pinctrl_gpio_direction_output(chip->base + offset);
 }
 
index f4cd0b9b2438b3548fafa4746b6c6a6cf8874bb4..a4814066ea0876d7f52063f5ba2cfb5ca5a6f6d3 100644 (file)
@@ -1477,28 +1477,25 @@ static void gpio_irq_ack(struct irq_data *d)
        /* the interrupt is already cleared before by reading ISR */
 }
 
-static unsigned int gpio_irq_startup(struct irq_data *d)
+static int gpio_irq_request_res(struct irq_data *d)
 {
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
        unsigned        pin = d->hwirq;
        int ret;
 
        ret = gpiochip_lock_as_irq(&at91_gpio->chip, pin);
-       if (ret) {
+       if (ret)
                dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n",
                        d->hwirq);
-               return ret;
-       }
-       gpio_irq_unmask(d);
-       return 0;
+
+       return ret;
 }
 
-static void gpio_irq_shutdown(struct irq_data *d)
+static void gpio_irq_release_res(struct irq_data *d)
 {
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
        unsigned        pin = d->hwirq;
 
-       gpio_irq_mask(d);
        gpiochip_unlock_as_irq(&at91_gpio->chip, pin);
 }
 
@@ -1577,8 +1574,8 @@ void at91_pinctrl_gpio_resume(void)
 static struct irq_chip gpio_irqchip = {
        .name           = "GPIO",
        .irq_ack        = gpio_irq_ack,
-       .irq_startup    = gpio_irq_startup,
-       .irq_shutdown   = gpio_irq_shutdown,
+       .irq_request_resources = gpio_irq_request_res,
+       .irq_release_resources = gpio_irq_release_res,
        .irq_disable    = gpio_irq_mask,
        .irq_mask       = gpio_irq_mask,
        .irq_unmask     = gpio_irq_unmask,
index 24c5d88f943f7809910507727ff50d4a43532530..3c68a8e5e0dd4d4bbb8d6fae4166a6bf92e521a2 100644 (file)
@@ -1011,6 +1011,7 @@ static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
        .pins = sun4i_a10_pins,
        .npins = ARRAY_SIZE(sun4i_a10_pins),
        .irq_banks = 1,
+       .irq_read_needs_mux = true,
 };
 
 static int sun4i_a10_pinctrl_probe(struct platform_device *pdev)
index 3d07443377362f0b84f59d971dcf73ecdf1d236c..f8e171b7669380d3d1f018124e04488fd4682f8f 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 
 #include "../core.h"
+#include "../../gpio/gpiolib.h"
 #include "pinctrl-sunxi.h"
 
 static struct irq_chip sunxi_pinctrl_edge_irq_chip;
@@ -464,10 +465,19 @@ static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
 static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
-
        u32 reg = sunxi_data_reg(offset);
        u8 index = sunxi_data_offset(offset);
-       u32 val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+       u32 set_mux = pctl->desc->irq_read_needs_mux &&
+                       test_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
+       u32 val;
+
+       if (set_mux)
+               sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_INPUT);
+
+       val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+
+       if (set_mux)
+               sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_IRQ);
 
        return val;
 }
index 5a51523a34599daba95571cb0d8b2597fdf4f45c..e248e81a0f9e0f8446cbd634040c93632b5e1268 100644 (file)
@@ -77,6 +77,9 @@
 #define IRQ_LEVEL_LOW          0x03
 #define IRQ_EDGE_BOTH          0x04
 
+#define SUN4I_FUNC_INPUT       0
+#define SUN4I_FUNC_IRQ         6
+
 struct sunxi_desc_function {
        const char      *name;
        u8              muxval;
@@ -94,6 +97,7 @@ struct sunxi_pinctrl_desc {
        int                             npins;
        unsigned                        pin_base;
        unsigned                        irq_banks;
+       bool                            irq_read_needs_mux;
 };
 
 struct sunxi_pinctrl_function {
index 97b5e4ee1ca40ae4bc5b50ab7e413833de693af7..63d4033eb683868738dedca38e838fe7e4b56cea 100644 (file)
@@ -73,7 +73,7 @@
 
 #define TIME_WINDOW_MAX_MSEC 40000
 #define TIME_WINDOW_MIN_MSEC 250
-
+#define ENERGY_UNIT_SCALE    1000 /* scale from driver unit to powercap unit */
 enum unit_type {
        ARBITRARY_UNIT, /* no translation */
        POWER_UNIT,
@@ -158,6 +158,7 @@ struct rapl_domain {
        struct rapl_power_limit rpl[NR_POWER_LIMITS];
        u64 attr_map; /* track capabilities */
        unsigned int state;
+       unsigned int domain_energy_unit;
        int package_id;
 };
 #define power_zone_to_rapl_domain(_zone) \
@@ -190,6 +191,7 @@ struct rapl_defaults {
        void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
        u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
                                bool to_raw);
+       unsigned int dram_domain_energy_unit;
 };
 static struct rapl_defaults *rapl_defaults;
 
@@ -227,7 +229,8 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
 static int rapl_write_data_raw(struct rapl_domain *rd,
                        enum rapl_primitives prim,
                        unsigned long long value);
-static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
+static u64 rapl_unit_xlate(struct rapl_domain *rd, int package,
+                       enum unit_type type, u64 value,
                        int to_raw);
 static void package_power_limit_irq_save(int package_id);
 
@@ -305,7 +308,9 @@ static int get_energy_counter(struct powercap_zone *power_zone, u64 *energy_raw)
 
 static int get_max_energy_counter(struct powercap_zone *pcd_dev, u64 *energy)
 {
-       *energy = rapl_unit_xlate(0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
+       struct rapl_domain *rd = power_zone_to_rapl_domain(pcd_dev);
+
+       *energy = rapl_unit_xlate(rd, 0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
        return 0;
 }
 
@@ -639,6 +644,11 @@ static void rapl_init_domains(struct rapl_package *rp)
                        rd->msrs[4] = MSR_DRAM_POWER_INFO;
                        rd->rpl[0].prim_id = PL1_ENABLE;
                        rd->rpl[0].name = pl1_name;
+                       rd->domain_energy_unit =
+                               rapl_defaults->dram_domain_energy_unit;
+                       if (rd->domain_energy_unit)
+                               pr_info("DRAM domain energy unit %dpj\n",
+                                       rd->domain_energy_unit);
                        break;
                }
                if (mask) {
@@ -648,11 +658,13 @@ static void rapl_init_domains(struct rapl_package *rp)
        }
 }
 
-static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
+static u64 rapl_unit_xlate(struct rapl_domain *rd, int package,
+                       enum unit_type type, u64 value,
                        int to_raw)
 {
        u64 units = 1;
        struct rapl_package *rp;
+       u64 scale = 1;
 
        rp = find_package_by_id(package);
        if (!rp)
@@ -663,7 +675,12 @@ static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
                units = rp->power_unit;
                break;
        case ENERGY_UNIT:
-               units = rp->energy_unit;
+               scale = ENERGY_UNIT_SCALE;
+               /* per domain unit takes precedence */
+               if (rd && rd->domain_energy_unit)
+                       units = rd->domain_energy_unit;
+               else
+                       units = rp->energy_unit;
                break;
        case TIME_UNIT:
                return rapl_defaults->compute_time_window(rp, value, to_raw);
@@ -673,11 +690,11 @@ static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
        };
 
        if (to_raw)
-               return div64_u64(value, units);
+               return div64_u64(value, units) * scale;
 
        value *= units;
 
-       return value;
+       return div64_u64(value, scale);
 }
 
 /* in the order of enum rapl_primitives */
@@ -773,7 +790,7 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
        final = value & rp->mask;
        final = final >> rp->shift;
        if (xlate)
-               *data = rapl_unit_xlate(rd->package_id, rp->unit, final, 0);
+               *data = rapl_unit_xlate(rd, rd->package_id, rp->unit, final, 0);
        else
                *data = final;
 
@@ -799,7 +816,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
                        "failed to read msr 0x%x on cpu %d\n", msr, cpu);
                return -EIO;
        }
-       value = rapl_unit_xlate(rd->package_id, rp->unit, value, 1);
+       value = rapl_unit_xlate(rd, rd->package_id, rp->unit, value, 1);
        msr_val &= ~rp->mask;
        msr_val |= value << rp->shift;
        if (wrmsrl_safe_on_cpu(cpu, msr, msr_val)) {
@@ -818,7 +835,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
  * calculate units differ on different CPUs.
  * We convert the units to below format based on CPUs.
  * i.e.
- * energy unit: microJoules : Represented in microJoules by default
+ * energy unit: picoJoules  : Represented in picoJoules by default
  * power unit : microWatts  : Represented in milliWatts by default
  * time unit  : microseconds: Represented in seconds by default
  */
@@ -834,7 +851,7 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
        }
 
        value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
-       rp->energy_unit = 1000000 / (1 << value);
+       rp->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value);
 
        value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
        rp->power_unit = 1000000 / (1 << value);
@@ -842,7 +859,7 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
        value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
        rp->time_unit = 1000000 / (1 << value);
 
-       pr_debug("Core CPU package %d energy=%duJ, time=%dus, power=%duW\n",
+       pr_debug("Core CPU package %d energy=%dpJ, time=%dus, power=%duW\n",
                rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
 
        return 0;
@@ -859,7 +876,7 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
                return -ENODEV;
        }
        value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
-       rp->energy_unit = 1 << value;
+       rp->energy_unit = ENERGY_UNIT_SCALE * 1 << value;
 
        value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
        rp->power_unit = (1 << value) * 1000;
@@ -867,7 +884,7 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
        value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
        rp->time_unit = 1000000 / (1 << value);
 
-       pr_debug("Atom package %d energy=%duJ, time=%dus, power=%duW\n",
+       pr_debug("Atom package %d energy=%dpJ, time=%dus, power=%duW\n",
                rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
 
        return 0;
@@ -1017,6 +1034,13 @@ static const struct rapl_defaults rapl_defaults_core = {
        .compute_time_window = rapl_compute_time_window_core,
 };
 
+static const struct rapl_defaults rapl_defaults_hsw_server = {
+       .check_unit = rapl_check_unit_core,
+       .set_floor_freq = set_floor_freq_default,
+       .compute_time_window = rapl_compute_time_window_core,
+       .dram_domain_energy_unit = 15300,
+};
+
 static const struct rapl_defaults rapl_defaults_atom = {
        .check_unit = rapl_check_unit_atom,
        .set_floor_freq = set_floor_freq_atom,
@@ -1037,7 +1061,7 @@ static const struct x86_cpu_id rapl_ids[] = {
        RAPL_CPU(0x3a, rapl_defaults_core),/* Ivy Bridge */
        RAPL_CPU(0x3c, rapl_defaults_core),/* Haswell */
        RAPL_CPU(0x3d, rapl_defaults_core),/* Broadwell */
-       RAPL_CPU(0x3f, rapl_defaults_core),/* Haswell */
+       RAPL_CPU(0x3f, rapl_defaults_hsw_server),/* Haswell servers */
        RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */
        RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */
        RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */
index b899947d839d87b03608d1f9bf4b4208cf57aa01..a4a8a6dc60c470bf6911632a8b14f790cc415ef4 100644 (file)
@@ -1839,10 +1839,12 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
        }
 
        if (rdev->ena_pin) {
-               ret = regulator_ena_gpio_ctrl(rdev, true);
-               if (ret < 0)
-                       return ret;
-               rdev->ena_gpio_state = 1;
+               if (!rdev->ena_gpio_state) {
+                       ret = regulator_ena_gpio_ctrl(rdev, true);
+                       if (ret < 0)
+                               return ret;
+                       rdev->ena_gpio_state = 1;
+               }
        } else if (rdev->desc->ops->enable) {
                ret = rdev->desc->ops->enable(rdev);
                if (ret < 0)
@@ -1939,10 +1941,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
        trace_regulator_disable(rdev_get_name(rdev));
 
        if (rdev->ena_pin) {
-               ret = regulator_ena_gpio_ctrl(rdev, false);
-               if (ret < 0)
-                       return ret;
-               rdev->ena_gpio_state = 0;
+               if (rdev->ena_gpio_state) {
+                       ret = regulator_ena_gpio_ctrl(rdev, false);
+                       if (ret < 0)
+                               return ret;
+                       rdev->ena_gpio_state = 0;
+               }
 
        } else if (rdev->desc->ops->disable) {
                ret = rdev->desc->ops->disable(rdev);
@@ -3444,13 +3448,6 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
        if (attr == &dev_attr_requested_microamps.attr)
                return rdev->desc->type == REGULATOR_CURRENT ? mode : 0;
 
-       /* all the other attributes exist to support constraints;
-        * don't show them if there are no constraints, or if the
-        * relevant supporting methods are missing.
-        */
-       if (!rdev->constraints)
-               return 0;
-
        /* constraints need specific supporting methods */
        if (attr == &dev_attr_min_microvolts.attr ||
            attr == &dev_attr_max_microvolts.attr)
@@ -3633,12 +3630,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
                                 config->ena_gpio, ret);
                        goto wash;
                }
-
-               if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
-                       rdev->ena_gpio_state = 1;
-
-               if (config->ena_gpio_invert)
-                       rdev->ena_gpio_state = !rdev->ena_gpio_state;
        }
 
        /* set regulator constraints */
@@ -3807,9 +3798,11 @@ int regulator_suspend_finish(void)
        list_for_each_entry(rdev, &regulator_list, list) {
                mutex_lock(&rdev->mutex);
                if (rdev->use_count > 0  || rdev->constraints->always_on) {
-                       error = _regulator_do_enable(rdev);
-                       if (error)
-                               ret = error;
+                       if (!_regulator_is_enabled(rdev)) {
+                               error = _regulator_do_enable(rdev);
+                               if (error)
+                                       ret = error;
+                       }
                } else {
                        if (!have_full_constraints())
                                goto unlock;
index bc6100103f7f476e7381482a404f33ea01851fad..f0489cb9018b4e7895937d330d077e100783fc16 100644 (file)
@@ -152,6 +152,15 @@ static int da9210_i2c_probe(struct i2c_client *i2c,
        config.regmap = chip->regmap;
        config.of_node = dev->of_node;
 
+       /* Mask all interrupt sources to deassert interrupt line */
+       error = regmap_write(chip->regmap, DA9210_REG_MASK_A, ~0);
+       if (!error)
+               error = regmap_write(chip->regmap, DA9210_REG_MASK_B, ~0);
+       if (error) {
+               dev_err(&i2c->dev, "Failed to write to mask reg: %d\n", error);
+               return error;
+       }
+
        rdev = devm_regulator_register(&i2c->dev, &da9210_reg, &config);
        if (IS_ERR(rdev)) {
                dev_err(&i2c->dev, "Failed to register DA9210 regulator\n");
index 9205f433573cc124bd84701f6ee6324969b093e9..18198316b6cf15c406c6f9eb243bc39601b97979 100644 (file)
@@ -1572,6 +1572,10 @@ static int palmas_regulators_probe(struct platform_device *pdev)
        if (!pmic)
                return -ENOMEM;
 
+       if (of_device_is_compatible(node, "ti,tps659038-pmic"))
+               palmas_generic_regs_info[PALMAS_REG_REGEN2].ctrl_addr =
+                                                       TPS659038_REGEN2_CTRL;
+
        pmic->dev = &pdev->dev;
        pmic->palmas = palmas;
        palmas->pmic = pmic;
index 1f93b752a81cdc36a824459ebf66354aea275af8..3fd44353cc80eea153fe1118c81180b5e2d21b67 100644 (file)
@@ -235,6 +235,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(0),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG2",
@@ -249,6 +250,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(1),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG3",
@@ -263,6 +265,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_BUCK4_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(2),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG4",
@@ -277,6 +280,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(3),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG5",
@@ -291,6 +295,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(4),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG6",
@@ -305,6 +310,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(5),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG7",
@@ -319,6 +325,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(6),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG8",
@@ -333,6 +340,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(7),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "SWITCH_REG1",
index e2cffe01b8072263330b28164130cf2fd23953b5..fb991ec764235d55443a9f99414efc3511cad7a2 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
index 92f6af6da6991f0f15400b07572b4338458ff8ca..73354ee278771ac0be6fc9fcaa40b96f9964bc9b 100644 (file)
@@ -951,6 +951,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
        void *bufs_va;
        int err = 0, i;
        size_t total_buf_space;
+       bool notify;
 
        vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
        if (!vrp)
@@ -1030,8 +1031,22 @@ static int rpmsg_probe(struct virtio_device *vdev)
                }
        }
 
+       /*
+        * Prepare to kick but don't notify yet - we can't do this before
+        * device is ready.
+        */
+       notify = virtqueue_kick_prepare(vrp->rvq);
+
+       /* From this point on, we can notify and get callbacks. */
+       virtio_device_ready(vdev);
+
        /* tell the remote processor it can start sending messages */
-       virtqueue_kick(vrp->rvq);
+       /*
+        * this might be concurrent with callbacks, but we are only
+        * doing notify, not a full kick here, so that's ok.
+        */
+       if (notify)
+               virtqueue_notify(vrp->rvq);
 
        dev_info(&vdev->dev, "rpmsg host is online\n");
 
index 70a5d94cc766af5302dfaf945dfb4a1a36b48236..b283a1a573b30549cb101f763ed430e258a29124 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/suspend.h>
 #include <linux/uaccess.h>
 
 #include "rtc-at91rm9200.h"
@@ -54,6 +55,10 @@ static void __iomem *at91_rtc_regs;
 static int irq;
 static DEFINE_SPINLOCK(at91_rtc_lock);
 static u32 at91_rtc_shadow_imr;
+static bool suspended;
+static DEFINE_SPINLOCK(suspended_lock);
+static unsigned long cached_events;
+static u32 at91_rtc_imr;
 
 static void at91_rtc_write_ier(u32 mask)
 {
@@ -290,7 +295,9 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
        struct rtc_device *rtc = platform_get_drvdata(pdev);
        unsigned int rtsr;
        unsigned long events = 0;
+       int ret = IRQ_NONE;
 
+       spin_lock(&suspended_lock);
        rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read_imr();
        if (rtsr) {             /* this interrupt is shared!  Is it ours? */
                if (rtsr & AT91_RTC_ALARM)
@@ -304,14 +311,22 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
 
                at91_rtc_write(AT91_RTC_SCCR, rtsr);    /* clear status reg */
 
-               rtc_update_irq(rtc, 1, events);
+               if (!suspended) {
+                       rtc_update_irq(rtc, 1, events);
 
-               dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__,
-                       events >> 8, events & 0x000000FF);
+                       dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n",
+                               __func__, events >> 8, events & 0x000000FF);
+               } else {
+                       cached_events |= events;
+                       at91_rtc_write_idr(at91_rtc_imr);
+                       pm_system_wakeup();
+               }
 
-               return IRQ_HANDLED;
+               ret = IRQ_HANDLED;
        }
-       return IRQ_NONE;                /* not handled */
+       spin_unlock(&suspended_lock);
+
+       return ret;
 }
 
 static const struct at91_rtc_config at91rm9200_config = {
@@ -401,8 +416,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
                                        AT91_RTC_CALEV);
 
        ret = devm_request_irq(&pdev->dev, irq, at91_rtc_interrupt,
-                               IRQF_SHARED,
-                               "at91_rtc", pdev);
+                              IRQF_SHARED | IRQF_COND_SUSPEND,
+                              "at91_rtc", pdev);
        if (ret) {
                dev_err(&pdev->dev, "IRQ %d already in use.\n", irq);
                return ret;
@@ -454,8 +469,6 @@ static void at91_rtc_shutdown(struct platform_device *pdev)
 
 /* AT91RM9200 RTC Power management control */
 
-static u32 at91_rtc_imr;
-
 static int at91_rtc_suspend(struct device *dev)
 {
        /* this IRQ is shared with DBGU and other hardware which isn't
@@ -464,21 +477,42 @@ static int at91_rtc_suspend(struct device *dev)
        at91_rtc_imr = at91_rtc_read_imr()
                        & (AT91_RTC_ALARM|AT91_RTC_SECEV);
        if (at91_rtc_imr) {
-               if (device_may_wakeup(dev))
+               if (device_may_wakeup(dev)) {
+                       unsigned long flags;
+
                        enable_irq_wake(irq);
-               else
+
+                       spin_lock_irqsave(&suspended_lock, flags);
+                       suspended = true;
+                       spin_unlock_irqrestore(&suspended_lock, flags);
+               } else {
                        at91_rtc_write_idr(at91_rtc_imr);
+               }
        }
        return 0;
 }
 
 static int at91_rtc_resume(struct device *dev)
 {
+       struct rtc_device *rtc = dev_get_drvdata(dev);
+
        if (at91_rtc_imr) {
-               if (device_may_wakeup(dev))
+               if (device_may_wakeup(dev)) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&suspended_lock, flags);
+
+                       if (cached_events) {
+                               rtc_update_irq(rtc, 1, cached_events);
+                               cached_events = 0;
+                       }
+
+                       suspended = false;
+                       spin_unlock_irqrestore(&suspended_lock, flags);
+
                        disable_irq_wake(irq);
-               else
-                       at91_rtc_write_ier(at91_rtc_imr);
+               }
+               at91_rtc_write_ier(at91_rtc_imr);
        }
        return 0;
 }
index 2183fd2750abd9d4b388ca4a5f48916600356122..5ccaee32df7223ad1aeb2d8cb74233caa7fae351 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/suspend.h>
 #include <linux/clk.h>
 
 /*
@@ -77,6 +78,9 @@ struct sam9_rtc {
        unsigned int            gpbr_offset;
        int                     irq;
        struct clk              *sclk;
+       bool                    suspended;
+       unsigned long           events;
+       spinlock_t              lock;
 };
 
 #define rtt_readl(rtc, field) \
@@ -271,14 +275,9 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
        return 0;
 }
 
-/*
- * IRQ handler for the RTC
- */
-static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
+static irqreturn_t at91_rtc_cache_events(struct sam9_rtc *rtc)
 {
-       struct sam9_rtc *rtc = _rtc;
        u32 sr, mr;
-       unsigned long events = 0;
 
        /* Shared interrupt may be for another device.  Note: reading
         * SR clears it, so we must only read it in this irq handler!
@@ -290,18 +289,54 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
 
        /* alarm status */
        if (sr & AT91_RTT_ALMS)
-               events |= (RTC_AF | RTC_IRQF);
+               rtc->events |= (RTC_AF | RTC_IRQF);
 
        /* timer update/increment */
        if (sr & AT91_RTT_RTTINC)
-               events |= (RTC_UF | RTC_IRQF);
+               rtc->events |= (RTC_UF | RTC_IRQF);
+
+       return IRQ_HANDLED;
+}
+
+static void at91_rtc_flush_events(struct sam9_rtc *rtc)
+{
+       if (!rtc->events)
+               return;
 
-       rtc_update_irq(rtc->rtcdev, 1, events);
+       rtc_update_irq(rtc->rtcdev, 1, rtc->events);
+       rtc->events = 0;
 
        pr_debug("%s: num=%ld, events=0x%02lx\n", __func__,
-               events >> 8, events & 0x000000FF);
+               rtc->events >> 8, rtc->events & 0x000000FF);
+}
 
-       return IRQ_HANDLED;
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
+{
+       struct sam9_rtc *rtc = _rtc;
+       int ret;
+
+       spin_lock(&rtc->lock);
+
+       ret = at91_rtc_cache_events(rtc);
+
+       /* We're called in suspended state */
+       if (rtc->suspended) {
+               /* Mask irqs coming from this peripheral */
+               rtt_writel(rtc, MR,
+                          rtt_readl(rtc, MR) &
+                          ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+               /* Trigger a system wakeup */
+               pm_system_wakeup();
+       } else {
+               at91_rtc_flush_events(rtc);
+       }
+
+       spin_unlock(&rtc->lock);
+
+       return ret;
 }
 
 static const struct rtc_class_ops at91_rtc_ops = {
@@ -421,7 +456,8 @@ static int at91_rtc_probe(struct platform_device *pdev)
 
        /* register irq handler after we know what name we'll use */
        ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt,
-                               IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc);
+                              IRQF_SHARED | IRQF_COND_SUSPEND,
+                              dev_name(&rtc->rtcdev->dev), rtc);
        if (ret) {
                dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq);
                return ret;
@@ -482,7 +518,12 @@ static int at91_rtc_suspend(struct device *dev)
        rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
        if (rtc->imr) {
                if (device_may_wakeup(dev) && (mr & AT91_RTT_ALMIEN)) {
+                       unsigned long flags;
+
                        enable_irq_wake(rtc->irq);
+                       spin_lock_irqsave(&rtc->lock, flags);
+                       rtc->suspended = true;
+                       spin_unlock_irqrestore(&rtc->lock, flags);
                        /* don't let RTTINC cause wakeups */
                        if (mr & AT91_RTT_RTTINCIEN)
                                rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
@@ -499,10 +540,18 @@ static int at91_rtc_resume(struct device *dev)
        u32             mr;
 
        if (rtc->imr) {
+               unsigned long flags;
+
                if (device_may_wakeup(dev))
                        disable_irq_wake(rtc->irq);
                mr = rtt_readl(rtc, MR);
                rtt_writel(rtc, MR, mr | rtc->imr);
+
+               spin_lock_irqsave(&rtc->lock, flags);
+               rtc->suspended = false;
+               at91_rtc_cache_events(rtc);
+               at91_rtc_flush_events(rtc);
+               spin_unlock_irqrestore(&rtc->lock, flags);
        }
 
        return 0;
index 8c3bfcb115b787318d0ce942c07c655f79fc1cb7..803869c7d7c206f6dbff5cc7427ea3faf8e1bf2b 100644 (file)
@@ -399,21 +399,21 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
         * of this RTC chip.  We check for it anyways in case support is
         * added in the future.
         */
-       if (unlikely((seconds >= 0xc0) && (seconds <= 0xff)))
+       if (unlikely(seconds >= 0xc0))
                alrm->time.tm_sec = -1;
        else
                alrm->time.tm_sec = ds1685_rtc_bcd2bin(rtc, seconds,
                                                       RTC_SECS_BCD_MASK,
                                                       RTC_SECS_BIN_MASK);
 
-       if (unlikely((minutes >= 0xc0) && (minutes <= 0xff)))
+       if (unlikely(minutes >= 0xc0))
                alrm->time.tm_min = -1;
        else
                alrm->time.tm_min = ds1685_rtc_bcd2bin(rtc, minutes,
                                                       RTC_MINS_BCD_MASK,
                                                       RTC_MINS_BIN_MASK);
 
-       if (unlikely((hours >= 0xc0) && (hours <= 0xff)))
+       if (unlikely(hours >= 0xc0))
                alrm->time.tm_hour = -1;
        else
                alrm->time.tm_hour = ds1685_rtc_bcd2bin(rtc, hours,
@@ -472,13 +472,13 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
         * field, and we only support four fields.  We put the support
         * here anyways for the future.
         */
-       if (unlikely((seconds >= 0xc0) && (seconds <= 0xff)))
+       if (unlikely(seconds >= 0xc0))
                seconds = 0xff;
 
-       if (unlikely((minutes >= 0xc0) && (minutes <= 0xff)))
+       if (unlikely(minutes >= 0xc0))
                minutes = 0xff;
 
-       if (unlikely((hours >= 0xc0) && (hours <= 0xff)))
+       if (unlikely(hours >= 0xc0))
                hours = 0xff;
 
        alrm->time.tm_mon       = -1;
@@ -528,7 +528,6 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 /* ----------------------------------------------------------------------- */
 /* /dev/rtcX Interface functions */
 
-#ifdef CONFIG_RTC_INTF_DEV
 /**
  * ds1685_rtc_alarm_irq_enable - replaces ioctl() RTC_AIE on/off.
  * @dev: pointer to device structure.
@@ -557,7 +556,6 @@ ds1685_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 
        return 0;
 }
-#endif
 /* ----------------------------------------------------------------------- */
 
 
@@ -1612,7 +1610,7 @@ ds1685_rtc_sysfs_time_regs_show(struct device *dev,
                ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false);
 
        /* Make sure we actually matched something. */
-       if (!bcd_reg_info && !bin_reg_info)
+       if (!bcd_reg_info || !bin_reg_info)
                return -EINVAL;
 
        /* bcd_reg_info->reg == bin_reg_info->reg. */
@@ -1650,7 +1648,7 @@ ds1685_rtc_sysfs_time_regs_store(struct device *dev,
                return -EINVAL;
 
        /* Make sure we actually matched something. */
-       if (!bcd_reg_info && !bin_reg_info)
+       if (!bcd_reg_info || !bin_reg_info)
                return -EINVAL;
 
        /* Check for a valid range. */
index e2436d140175a109907e55eacafeb1906105748d..3a6fd3a8a2ec63d389a2f4dbf948f5c2090ecc3a 100644 (file)
@@ -413,8 +413,8 @@ static void rtc_mrst_do_remove(struct device *dev)
        mrst->dev = NULL;
 }
 
-#ifdef CONFIG_PM
-static int mrst_suspend(struct device *dev, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int mrst_suspend(struct device *dev)
 {
        struct mrst_rtc *mrst = dev_get_drvdata(dev);
        unsigned char   tmp;
@@ -453,7 +453,7 @@ static int mrst_suspend(struct device *dev, pm_message_t mesg)
  */
 static inline int mrst_poweroff(struct device *dev)
 {
-       return mrst_suspend(dev, PMSG_HIBERNATE);
+       return mrst_suspend(dev);
 }
 
 static int mrst_resume(struct device *dev)
@@ -490,9 +490,11 @@ static int mrst_resume(struct device *dev)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(mrst_pm_ops, mrst_suspend, mrst_resume);
+#define MRST_PM_OPS (&mrst_pm_ops)
+
 #else
-#define        mrst_suspend    NULL
-#define        mrst_resume     NULL
+#define MRST_PM_OPS NULL
 
 static inline int mrst_poweroff(struct device *dev)
 {
@@ -529,9 +531,8 @@ static struct platform_driver vrtc_mrst_platform_driver = {
        .remove         = vrtc_mrst_platform_remove,
        .shutdown       = vrtc_mrst_platform_shutdown,
        .driver = {
-               .name           = (char *) driver_name,
-               .suspend        = mrst_suspend,
-               .resume         = mrst_resume,
+               .name   = driver_name,
+               .pm     = MRST_PM_OPS,
        }
 };
 
index 4241eeab3386ab3803d4238471fd2bd92ac66226..f4cf6851fae971e34d4b43e945ac91160bcaef21 100644 (file)
@@ -849,6 +849,7 @@ static struct s3c_rtc_data const s3c2443_rtc_data = {
 
 static struct s3c_rtc_data const s3c6410_rtc_data = {
        .max_user_freq          = 32768,
+       .needs_src_clk          = true,
        .irq_handler            = s3c6410_rtc_irq,
        .set_freq               = s3c6410_rtc_setfreq,
        .enable_tick            = s3c6410_rtc_enable_tick,
index 96128cb009f352dba8497a47427dda713f608a4b..da212813f2d5dcd301a923df946daa9c481cb06f 100644 (file)
@@ -547,7 +547,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
         * parse input
         */
        num_of_segments = 0;
-       for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) {
+       for (i = 0; (i < count && (buf[i] != '\0') && (buf[i] != '\n')); i++) {
                for (j = i; (buf[j] != ':') &&
                        (buf[j] != '\0') &&
                        (buf[j] != '\n') &&
index 09db45296eed2c87330399abbfecdbb2f9b44014..7497ddde2dd67a28ce2e042970bebda9b3e9da5b 100644 (file)
@@ -92,7 +92,7 @@ bool scm_reserve_cluster(struct scm_request *scmrq)
                        add = 0;
                        continue;
                }
-               for (pos = 0; pos <= iter->aob->request.msb_count; pos++) {
+               for (pos = 0; pos < iter->aob->request.msb_count; pos++) {
                        if (clusters_intersect(req, iter->request[pos]) &&
                            (rq_data_dir(req) == WRITE ||
                             rq_data_dir(iter->request[pos]) == WRITE)) {
index 9219953ee949a9dfaf1ff0f044e41a3e5c13adc7..d9afc51af7d3dbc7df2e38865596ba3473a1f708 100644 (file)
@@ -6815,7 +6815,8 @@ static struct ata_port_operations ipr_sata_ops = {
 };
 
 static struct ata_port_info sata_port_info = {
-       .flags          = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
+       .flags          = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA |
+                         ATA_FLAG_SAS_HOST,
        .pio_mask       = ATA_PIO4_ONLY,
        .mwdma_mask     = ATA_MWDMA2,
        .udma_mask      = ATA_UDMA6,
index 932d9cc98d2fc807c4ef0e7715fe922803bbc29c..9c706d8c144174dae8cf87c1aa62a95a98f961e4 100644 (file)
@@ -547,7 +547,8 @@ static struct ata_port_operations sas_sata_ops = {
 };
 
 static struct ata_port_info sata_port_info = {
-       .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ,
+       .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ |
+                ATA_FLAG_SAS_HOST,
        .pio_mask = ATA_PIO4,
        .mwdma_mask = ATA_MWDMA2,
        .udma_mask = ATA_UDMA6,
index 62b58d38ce2e63beda6d1ba4d9876c9af2e51008..60de66252fa2b9ea168648c5097da7f8ae7f49ae 100644 (file)
@@ -500,6 +500,7 @@ static void sas_revalidate_domain(struct work_struct *work)
        struct sas_discovery_event *ev = to_sas_discovery_event(work);
        struct asd_sas_port *port = ev->port;
        struct sas_ha_struct *ha = port->ha;
+       struct domain_device *ddev = port->port_dev;
 
        /* prevent revalidation from finding sata links in recovery */
        mutex_lock(&ha->disco_mutex);
@@ -514,8 +515,9 @@ static void sas_revalidate_domain(struct work_struct *work)
        SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
                    task_pid_nr(current));
 
-       if (port->port_dev)
-               res = sas_ex_revalidate_domain(port->port_dev);
+       if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
+                    ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE))
+               res = sas_ex_revalidate_domain(ddev);
 
        SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
                    port->id, task_pid_nr(current), res);
index 99f43b7fc9ab74256d6f22f17e3c6d75c6e5fcdb..ab4879e12ea7fd0b2745327400b2166451519483 100644 (file)
@@ -1596,7 +1596,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
        /*
         * Finally register the new FC Nexus with TCM
         */
-       __transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess);
+       transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess);
 
        return 0;
 }
index f3ee439d6f0e23b41bd54b0ad1bbb7941ec4e505..cd4c293f0dd0d375be6d6d815108aeb588304fec 100644 (file)
@@ -81,7 +81,9 @@ static int __init sh_pm_runtime_init(void)
                if (!of_machine_is_compatible("renesas,emev2") &&
                    !of_machine_is_compatible("renesas,r7s72100") &&
                    !of_machine_is_compatible("renesas,r8a73a4") &&
+#ifndef CONFIG_PM_GENERIC_DOMAINS_OF
                    !of_machine_is_compatible("renesas,r8a7740") &&
+#endif
                    !of_machine_is_compatible("renesas,r8a7778") &&
                    !of_machine_is_compatible("renesas,r8a7779") &&
                    !of_machine_is_compatible("renesas,r8a7790") &&
index 9af7841f2e8c6010060c17a038bc8c86c792a729..06de34001c6695a5a741925e862d7baa05853c98 100644 (file)
@@ -764,17 +764,17 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
                        (unsigned long long)xfer->rx_dma);
        }
 
-       /* REVISIT: We're waiting for ENDRX before we start the next
+       /* REVISIT: We're waiting for RXBUFF before we start the next
         * transfer because we need to handle some difficult timing
-        * issues otherwise. If we wait for ENDTX in one transfer and
-        * then starts waiting for ENDRX in the next, it's difficult
-        * to tell the difference between the ENDRX interrupt we're
-        * actually waiting for and the ENDRX interrupt of the
+        * issues otherwise. If we wait for TXBUFE in one transfer and
+        * then starts waiting for RXBUFF in the next, it's difficult
+        * to tell the difference between the RXBUFF interrupt we're
+        * actually waiting for and the RXBUFF interrupt of the
         * previous transfer.
         *
         * It should be doable, though. Just not now...
         */
-       spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
+       spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES));
        spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
 }
 
index a0197fd4e95c40b26817fe942d2069a0381a41e5..4f8c798e0633a81483c3b05af46805b1848ba386 100644 (file)
@@ -108,7 +108,8 @@ static void dw_spi_dma_tx_done(void *arg)
 {
        struct dw_spi *dws = arg;
 
-       if (test_and_clear_bit(TX_BUSY, &dws->dma_chan_busy) & BIT(RX_BUSY))
+       clear_bit(TX_BUSY, &dws->dma_chan_busy);
+       if (test_bit(RX_BUSY, &dws->dma_chan_busy))
                return;
        dw_spi_xfer_done(dws);
 }
@@ -139,6 +140,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws)
                                1,
                                DMA_MEM_TO_DEV,
                                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!txdesc)
+               return NULL;
+
        txdesc->callback = dw_spi_dma_tx_done;
        txdesc->callback_param = dws;
 
@@ -153,7 +157,8 @@ static void dw_spi_dma_rx_done(void *arg)
 {
        struct dw_spi *dws = arg;
 
-       if (test_and_clear_bit(RX_BUSY, &dws->dma_chan_busy) & BIT(TX_BUSY))
+       clear_bit(RX_BUSY, &dws->dma_chan_busy);
+       if (test_bit(TX_BUSY, &dws->dma_chan_busy))
                return;
        dw_spi_xfer_done(dws);
 }
@@ -184,6 +189,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws)
                                1,
                                DMA_DEV_TO_MEM,
                                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!rxdesc)
+               return NULL;
+
        rxdesc->callback = dw_spi_dma_rx_done;
        rxdesc->callback_param = dws;
 
index 5ba331047cbefdea6d948ca20c8d6d3898cafbb0..6d331e0db33122b23cfa17f6602618a510efcde1 100644 (file)
@@ -36,13 +36,13 @@ struct spi_pci_desc {
 
 static struct spi_pci_desc spi_pci_mid_desc_1 = {
        .setup = dw_spi_mid_init,
-       .num_cs = 32,
+       .num_cs = 5,
        .bus_num = 0,
 };
 
 static struct spi_pci_desc spi_pci_mid_desc_2 = {
        .setup = dw_spi_mid_init,
-       .num_cs = 4,
+       .num_cs = 2,
        .bus_num = 1,
 };
 
index 5a97a62b298ac1a526d4c1bde932f3eb2d5ad574..4847afba89f4e933e5a5d778c5f94e1a14ffe156 100644 (file)
@@ -621,14 +621,14 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
        if (!dws->fifo_len) {
                u32 fifo;
 
-               for (fifo = 2; fifo <= 256; fifo++) {
+               for (fifo = 1; fifo < 256; fifo++) {
                        dw_writew(dws, DW_SPI_TXFLTR, fifo);
                        if (fifo != dw_readw(dws, DW_SPI_TXFLTR))
                                break;
                }
                dw_writew(dws, DW_SPI_TXFLTR, 0);
 
-               dws->fifo_len = (fifo == 2) ? 0 : fifo - 1;
+               dws->fifo_len = (fifo == 1) ? 0 : fifo;
                dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
        }
 }
index c01567d53581c0dcdfc6fcb61e7f6e821d0e0b39..e649bc7d4c086bb789d2dc1803c621bebdc29a19 100644 (file)
@@ -459,6 +459,13 @@ static int img_spfi_transfer_one(struct spi_master *master,
        unsigned long flags;
        int ret;
 
+       if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) {
+               dev_err(spfi->dev,
+                       "Transfer length (%d) is greater than the max supported (%d)",
+                       xfer->len, SPFI_TRANSACTION_TSIZE_MASK);
+               return -EINVAL;
+       }
+
        /*
         * Stop all DMA and reset the controller if the previous transaction
         * timed-out and never completed it's DMA.
index 89ca162801da10b8ec7a9c4311a33344f6a438a7..ee513a85296b19a3c57aad4daef4ec42ee3d90b1 100644 (file)
@@ -534,12 +534,12 @@ static void giveback(struct pl022 *pl022)
        pl022->cur_msg = NULL;
        pl022->cur_transfer = NULL;
        pl022->cur_chip = NULL;
-       spi_finalize_current_message(pl022->master);
 
        /* disable the SPI/SSP operation */
        writew((readw(SSP_CR1(pl022->virtbase)) &
                (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
 
+       spi_finalize_current_message(pl022->master);
 }
 
 /**
index ff9cdbdb6672371df54b6c59ce54579a46758602..2b2c359f5a501da32a38af38cfe0c0956b0e23c9 100644 (file)
@@ -498,7 +498,7 @@ static int spi_qup_probe(struct platform_device *pdev)
        struct resource *res;
        struct device *dev;
        void __iomem *base;
-       u32 max_freq, iomode;
+       u32 max_freq, iomode, num_cs;
        int ret, irq, size;
 
        dev = &pdev->dev;
@@ -550,10 +550,11 @@ static int spi_qup_probe(struct platform_device *pdev)
        }
 
        /* use num-cs unless not present or out of range */
-       if (of_property_read_u16(dev->of_node, "num-cs",
-                       &master->num_chipselect) ||
-                       (master->num_chipselect > SPI_NUM_CHIPSELECTS))
+       if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) ||
+           num_cs > SPI_NUM_CHIPSELECTS)
                master->num_chipselect = SPI_NUM_CHIPSELECTS;
+       else
+               master->num_chipselect = num_cs;
 
        master->bus_num = pdev->id;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
index 884a716e50cb822ce49dcb0e925a2c1856130bcb..5c061687035886e5768bf6031616068906540b04 100644 (file)
@@ -101,6 +101,7 @@ struct ti_qspi {
 #define QSPI_FLEN(n)                   ((n - 1) << 0)
 
 /* STATUS REGISTER */
+#define BUSY                           0x01
 #define WC                             0x02
 
 /* INTERRUPT REGISTER */
@@ -199,6 +200,21 @@ static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
        ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG);
 }
 
+static inline u32 qspi_is_busy(struct ti_qspi *qspi)
+{
+       u32 stat;
+       unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT;
+
+       stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
+       while ((stat & BUSY) && time_after(timeout, jiffies)) {
+               cpu_relax();
+               stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
+       }
+
+       WARN(stat & BUSY, "qspi busy\n");
+       return stat & BUSY;
+}
+
 static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
 {
        int wlen, count;
@@ -211,6 +227,9 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
        wlen = t->bits_per_word >> 3;   /* in bytes */
 
        while (count) {
+               if (qspi_is_busy(qspi))
+                       return -EBUSY;
+
                switch (wlen) {
                case 1:
                        dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
@@ -266,6 +285,9 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t)
 
        while (count) {
                dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
+               if (qspi_is_busy(qspi))
+                       return -EBUSY;
+
                ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
                if (!wait_for_completion_timeout(&qspi->transfer_complete,
                                                 QSPI_COMPLETION_TIMEOUT)) {
index c64a3e59fce30a7f9658afcca246a6d6872627da..57a195041dc72e019a02b3c7c4b6f4c2a6fac59b 100644 (file)
@@ -1105,13 +1105,14 @@ void spi_finalize_current_message(struct spi_master *master)
                                "failed to unprepare message: %d\n", ret);
                }
        }
+
+       trace_spi_message_done(mesg);
+
        master->cur_msg_prepared = false;
 
        mesg->state = NULL;
        if (mesg->complete)
                mesg->complete(mesg->context);
-
-       trace_spi_message_done(mesg);
 }
 EXPORT_SYMBOL_GPL(spi_finalize_current_message);
 
index 9800c01e6fb97409966e1b35157656ff139f31ea..3f72451d2de01aa44d1b16f633ddd8999894db25 100644 (file)
@@ -426,7 +426,6 @@ static int pci171x_ai_insn_read(struct comedi_device *dev,
                                unsigned int *data)
 {
        struct pci1710_private *devpriv = dev->private;
-       unsigned int chan = CR_CHAN(insn->chanspec);
        int ret = 0;
        int i;
 
@@ -447,7 +446,7 @@ static int pci171x_ai_insn_read(struct comedi_device *dev,
                if (ret)
                        break;
 
-               ret = pci171x_ai_read_sample(dev, s, chan, &val);
+               ret = pci171x_ai_read_sample(dev, s, 0, &val);
                if (ret)
                        break;
 
index dbdea71d6b95b5e3c25a0a2fe2deb9eb57422a94..e856f01ca07716c8acb3881bbe8e4373a64beab5 100644 (file)
@@ -91,9 +91,10 @@ unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan,
                        stalled++;
                        if (stalled > 10)
                                break;
+               } else {
+                       residue = new_residue;
+                       stalled = 0;
                }
-               residue = new_residue;
-               stalled = 0;
        }
        return residue;
 }
index e37118321a278466ab75f1e51294b2183551bc58..a0906685e27fcb59d9712e9b2619c9f343e5db5e 100644 (file)
@@ -103,11 +103,6 @@ enum vmk80xx_model {
        VMK8061_MODEL
 };
 
-struct firmware_version {
-       unsigned char ic3_vers[32];     /* USB-Controller */
-       unsigned char ic6_vers[32];     /* CPU */
-};
-
 static const struct comedi_lrange vmk8061_range = {
        2, {
                UNI_RANGE(5),
@@ -156,68 +151,12 @@ static const struct vmk80xx_board vmk80xx_boardinfo[] = {
 struct vmk80xx_private {
        struct usb_endpoint_descriptor *ep_rx;
        struct usb_endpoint_descriptor *ep_tx;
-       struct firmware_version fw;
        struct semaphore limit_sem;
        unsigned char *usb_rx_buf;
        unsigned char *usb_tx_buf;
        enum vmk80xx_model model;
 };
 
-static int vmk80xx_check_data_link(struct comedi_device *dev)
-{
-       struct vmk80xx_private *devpriv = dev->private;
-       struct usb_device *usb = comedi_to_usb_dev(dev);
-       unsigned int tx_pipe;
-       unsigned int rx_pipe;
-       unsigned char tx[1];
-       unsigned char rx[2];
-
-       tx_pipe = usb_sndbulkpipe(usb, 0x01);
-       rx_pipe = usb_rcvbulkpipe(usb, 0x81);
-
-       tx[0] = VMK8061_CMD_RD_PWR_STAT;
-
-       /*
-        * Check that IC6 (PIC16F871) is powered and
-        * running and the data link between IC3 and
-        * IC6 is working properly
-        */
-       usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
-       usb_bulk_msg(usb, rx_pipe, rx, 2, NULL, HZ * 10);
-
-       return (int)rx[1];
-}
-
-static void vmk80xx_read_eeprom(struct comedi_device *dev, int flag)
-{
-       struct vmk80xx_private *devpriv = dev->private;
-       struct usb_device *usb = comedi_to_usb_dev(dev);
-       unsigned int tx_pipe;
-       unsigned int rx_pipe;
-       unsigned char tx[1];
-       unsigned char rx[64];
-       int cnt;
-
-       tx_pipe = usb_sndbulkpipe(usb, 0x01);
-       rx_pipe = usb_rcvbulkpipe(usb, 0x81);
-
-       tx[0] = VMK8061_CMD_RD_VERSION;
-
-       /*
-        * Read the firmware version info of IC3 and
-        * IC6 from the internal EEPROM of the IC
-        */
-       usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
-       usb_bulk_msg(usb, rx_pipe, rx, 64, &cnt, HZ * 10);
-
-       rx[cnt] = '\0';
-
-       if (flag & IC3_VERSION)
-               strncpy(devpriv->fw.ic3_vers, rx + 1, 24);
-       else                    /* IC6_VERSION */
-               strncpy(devpriv->fw.ic6_vers, rx + 25, 24);
-}
-
 static void vmk80xx_do_bulk_msg(struct comedi_device *dev)
 {
        struct vmk80xx_private *devpriv = dev->private;
@@ -878,16 +817,6 @@ static int vmk80xx_auto_attach(struct comedi_device *dev,
 
        usb_set_intfdata(intf, devpriv);
 
-       if (devpriv->model == VMK8061_MODEL) {
-               vmk80xx_read_eeprom(dev, IC3_VERSION);
-               dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers);
-
-               if (vmk80xx_check_data_link(dev)) {
-                       vmk80xx_read_eeprom(dev, IC6_VERSION);
-                       dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers);
-               }
-       }
-
        if (devpriv->model == VMK8055_MODEL)
                vmk80xx_reset_device(dev);
 
index d9d6fad7cb00725f43142967bad4ca6b39a32b06..816174388f13347447c495700e3dad85e7c269db 100644 (file)
@@ -214,11 +214,17 @@ struct mxs_lradc {
        unsigned long           is_divided;
 
        /*
-        * Touchscreen LRADC channels receives a private slot in the CTRL4
-        * register, the slot #7. Therefore only 7 slots instead of 8 in the
-        * CTRL4 register can be mapped to LRADC channels when using the
-        * touchscreen.
-        *
+        * When the touchscreen is enabled, we give it two private virtual
+        * channels: #6 and #7. This means that only 6 virtual channels (instead
+        * of 8) will be available for buffered capture.
+        */
+#define TOUCHSCREEN_VCHANNEL1          7
+#define TOUCHSCREEN_VCHANNEL2          6
+#define BUFFER_VCHANS_LIMITED          0x3f
+#define BUFFER_VCHANS_ALL              0xff
+       u8                      buffer_vchans;
+
+       /*
         * Furthermore, certain LRADC channels are shared between touchscreen
         * and/or touch-buttons and generic LRADC block. Therefore when using
         * either of these, these channels are not available for the regular
@@ -342,6 +348,9 @@ struct mxs_lradc {
 #define        LRADC_CTRL4                             0x140
 #define        LRADC_CTRL4_LRADCSELECT_MASK(n)         (0xf << ((n) * 4))
 #define        LRADC_CTRL4_LRADCSELECT_OFFSET(n)       ((n) * 4)
+#define        LRADC_CTRL4_LRADCSELECT(n, x) \
+                               (((x) << LRADC_CTRL4_LRADCSELECT_OFFSET(n)) & \
+                               LRADC_CTRL4_LRADCSELECT_MASK(n))
 
 #define LRADC_RESOLUTION                       12
 #define LRADC_SINGLE_SAMPLE_MASK               ((1 << LRADC_RESOLUTION) - 1)
@@ -416,6 +425,14 @@ static bool mxs_lradc_check_touch_event(struct mxs_lradc *lradc)
                                        LRADC_STATUS_TOUCH_DETECT_RAW);
 }
 
+static void mxs_lradc_map_channel(struct mxs_lradc *lradc, unsigned vch,
+                                 unsigned ch)
+{
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(vch),
+                               LRADC_CTRL4);
+       mxs_lradc_reg_set(lradc, LRADC_CTRL4_LRADCSELECT(vch, ch), LRADC_CTRL4);
+}
+
 static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
 {
        /*
@@ -450,12 +467,8 @@ static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
                LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
                        LRADC_DELAY(3));
 
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) |
-                       LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) |
-                       LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch), LRADC_CTRL1);
 
-       /* wake us again, when the complete conversion is done */
-       mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch), LRADC_CTRL1);
        /*
         * after changing the touchscreen plates setting
         * the signals need some initial time to settle. Start the
@@ -509,12 +522,8 @@ static void mxs_lradc_setup_ts_pressure(struct mxs_lradc *lradc, unsigned ch1,
                LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
                                        LRADC_DELAY(3));
 
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) |
-                       LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) |
-                       LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch2), LRADC_CTRL1);
 
-       /* wake us again, when the conversions are done */
-       mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch2), LRADC_CTRL1);
        /*
         * after changing the touchscreen plates setting
         * the signals need some initial time to settle. Start the
@@ -580,36 +589,6 @@ static unsigned mxs_lradc_read_ts_pressure(struct mxs_lradc *lradc,
 #define TS_CH_XM 4
 #define TS_CH_YM 5
 
-static int mxs_lradc_read_ts_channel(struct mxs_lradc *lradc)
-{
-       u32 reg;
-       int val;
-
-       reg = readl(lradc->base + LRADC_CTRL1);
-
-       /* only channels 3 to 5 are of interest here */
-       if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YP)) {
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YP) |
-                       LRADC_CTRL1_LRADC_IRQ(TS_CH_YP), LRADC_CTRL1);
-               val = mxs_lradc_read_raw_channel(lradc, TS_CH_YP);
-       } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_XM)) {
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_XM) |
-                       LRADC_CTRL1_LRADC_IRQ(TS_CH_XM), LRADC_CTRL1);
-               val = mxs_lradc_read_raw_channel(lradc, TS_CH_XM);
-       } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YM)) {
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YM) |
-                       LRADC_CTRL1_LRADC_IRQ(TS_CH_YM), LRADC_CTRL1);
-               val = mxs_lradc_read_raw_channel(lradc, TS_CH_YM);
-       } else {
-               return -EIO;
-       }
-
-       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
-       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
-
-       return val;
-}
-
 /*
  * YP(open)--+-------------+
  *           |             |--+
@@ -653,7 +632,8 @@ static void mxs_lradc_prepare_x_pos(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, mxs_lradc_drive_x_plate(lradc), LRADC_CTRL0);
 
        lradc->cur_plate = LRADC_SAMPLE_X;
-       mxs_lradc_setup_ts_channel(lradc, TS_CH_YP);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YP);
+       mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
 }
 
 /*
@@ -674,7 +654,8 @@ static void mxs_lradc_prepare_y_pos(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, mxs_lradc_drive_y_plate(lradc), LRADC_CTRL0);
 
        lradc->cur_plate = LRADC_SAMPLE_Y;
-       mxs_lradc_setup_ts_channel(lradc, TS_CH_XM);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_XM);
+       mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
 }
 
 /*
@@ -695,7 +676,10 @@ static void mxs_lradc_prepare_pressure(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, mxs_lradc_drive_pressure(lradc), LRADC_CTRL0);
 
        lradc->cur_plate = LRADC_SAMPLE_PRESSURE;
-       mxs_lradc_setup_ts_pressure(lradc, TS_CH_XP, TS_CH_YM);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YM);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL2, TS_CH_XP);
+       mxs_lradc_setup_ts_pressure(lradc, TOUCHSCREEN_VCHANNEL2,
+                                               TOUCHSCREEN_VCHANNEL1);
 }
 
 static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
@@ -708,6 +692,19 @@ static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
 }
 
+static void mxs_lradc_start_touch_event(struct mxs_lradc *lradc)
+{
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+                               LRADC_CTRL1);
+       mxs_lradc_reg_set(lradc,
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1);
+       /*
+        * start with the Y-pos, because it uses nearly the same plate
+        * settings like the touch detection
+        */
+       mxs_lradc_prepare_y_pos(lradc);
+}
+
 static void mxs_lradc_report_ts_event(struct mxs_lradc *lradc)
 {
        input_report_abs(lradc->ts_input, ABS_X, lradc->ts_x_pos);
@@ -725,10 +722,12 @@ static void mxs_lradc_complete_touch_event(struct mxs_lradc *lradc)
         * start a dummy conversion to burn time to settle the signals
         * note: we are not interested in the conversion's value
         */
-       mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(5));
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
-       mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(5), LRADC_CTRL1);
-       mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << 5) |
+       mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(TOUCHSCREEN_VCHANNEL1));
+       mxs_lradc_reg_clear(lradc,
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
+       mxs_lradc_reg_wrt(lradc,
+               LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) |
                LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10), /* waste 5 ms */
                        LRADC_DELAY(2));
 }
@@ -760,59 +759,45 @@ static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid)
 
        /* if it is released, wait for the next touch via IRQ */
        lradc->cur_plate = LRADC_TOUCH;
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1);
+       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
+       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ |
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1);
        mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
 }
 
 /* touchscreen's state machine */
 static void mxs_lradc_handle_touch(struct mxs_lradc *lradc)
 {
-       int val;
-
        switch (lradc->cur_plate) {
        case LRADC_TOUCH:
-               /*
-                * start with the Y-pos, because it uses nearly the same plate
-                * settings like the touch detection
-                */
-               if (mxs_lradc_check_touch_event(lradc)) {
-                       mxs_lradc_reg_clear(lradc,
-                                       LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
-                                       LRADC_CTRL1);
-                       mxs_lradc_prepare_y_pos(lradc);
-               }
+               if (mxs_lradc_check_touch_event(lradc))
+                       mxs_lradc_start_touch_event(lradc);
                mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ,
                                        LRADC_CTRL1);
                return;
 
        case LRADC_SAMPLE_Y:
-               val = mxs_lradc_read_ts_channel(lradc);
-               if (val < 0) {
-                       mxs_lradc_enable_touch_detection(lradc); /* re-start */
-                       return;
-               }
-               lradc->ts_y_pos = val;
+               lradc->ts_y_pos = mxs_lradc_read_raw_channel(lradc,
+                                                       TOUCHSCREEN_VCHANNEL1);
                mxs_lradc_prepare_x_pos(lradc);
                return;
 
        case LRADC_SAMPLE_X:
-               val = mxs_lradc_read_ts_channel(lradc);
-               if (val < 0) {
-                       mxs_lradc_enable_touch_detection(lradc); /* re-start */
-                       return;
-               }
-               lradc->ts_x_pos = val;
+               lradc->ts_x_pos = mxs_lradc_read_raw_channel(lradc,
+                                                       TOUCHSCREEN_VCHANNEL1);
                mxs_lradc_prepare_pressure(lradc);
                return;
 
        case LRADC_SAMPLE_PRESSURE:
-               lradc->ts_pressure =
-                       mxs_lradc_read_ts_pressure(lradc, TS_CH_XP, TS_CH_YM);
+               lradc->ts_pressure = mxs_lradc_read_ts_pressure(lradc,
+                                                       TOUCHSCREEN_VCHANNEL2,
+                                                       TOUCHSCREEN_VCHANNEL1);
                mxs_lradc_complete_touch_event(lradc);
                return;
 
        case LRADC_SAMPLE_VALID:
-               val = mxs_lradc_read_ts_channel(lradc); /* ignore the value */
                mxs_lradc_finish_touch_event(lradc, 1);
                break;
        }
@@ -844,9 +829,9 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val)
         * used if doing raw sampling.
         */
        if (lradc->soc == IMX28_LRADC)
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
+               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0),
                        LRADC_CTRL1);
-       mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
+       mxs_lradc_reg_clear(lradc, 0x1, LRADC_CTRL0);
 
        /* Enable / disable the divider per requirement */
        if (test_bit(chan, &lradc->is_divided))
@@ -1090,9 +1075,8 @@ static void mxs_lradc_disable_ts(struct mxs_lradc *lradc)
 {
        /* stop all interrupts from firing */
        mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN |
-               LRADC_CTRL1_LRADC_IRQ_EN(2) | LRADC_CTRL1_LRADC_IRQ_EN(3) |
-               LRADC_CTRL1_LRADC_IRQ_EN(4) | LRADC_CTRL1_LRADC_IRQ_EN(5),
-               LRADC_CTRL1);
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
 
        /* Power-down touchscreen touch-detect circuitry. */
        mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0);
@@ -1158,26 +1142,31 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data)
        struct iio_dev *iio = data;
        struct mxs_lradc *lradc = iio_priv(iio);
        unsigned long reg = readl(lradc->base + LRADC_CTRL1);
+       uint32_t clr_irq = mxs_lradc_irq_mask(lradc);
        const uint32_t ts_irq_mask =
                LRADC_CTRL1_TOUCH_DETECT_IRQ |
-               LRADC_CTRL1_LRADC_IRQ(2) |
-               LRADC_CTRL1_LRADC_IRQ(3) |
-               LRADC_CTRL1_LRADC_IRQ(4) |
-               LRADC_CTRL1_LRADC_IRQ(5);
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2);
 
        if (!(reg & mxs_lradc_irq_mask(lradc)))
                return IRQ_NONE;
 
-       if (lradc->use_touchscreen && (reg & ts_irq_mask))
+       if (lradc->use_touchscreen && (reg & ts_irq_mask)) {
                mxs_lradc_handle_touch(lradc);
 
-       if (iio_buffer_enabled(iio))
-               iio_trigger_poll(iio->trig);
-       else if (reg & LRADC_CTRL1_LRADC_IRQ(0))
+               /* Make sure we don't clear the next conversion's interrupt. */
+               clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+                               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2));
+       }
+
+       if (iio_buffer_enabled(iio)) {
+               if (reg & lradc->buffer_vchans)
+                       iio_trigger_poll(iio->trig);
+       } else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) {
                complete(&lradc->completion);
+       }
 
-       mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc),
-                       LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, reg & clr_irq, LRADC_CTRL1);
 
        return IRQ_HANDLED;
 }
@@ -1289,9 +1278,10 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
        }
 
        if (lradc->soc == IMX28_LRADC)
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
-                                                       LRADC_CTRL1);
-       mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
+               mxs_lradc_reg_clear(lradc,
+                       lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+                       LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0);
 
        for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
                ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
@@ -1324,10 +1314,11 @@ static int mxs_lradc_buffer_postdisable(struct iio_dev *iio)
        mxs_lradc_reg_clear(lradc, LRADC_DELAY_TRIGGER_LRADCS_MASK |
                                        LRADC_DELAY_KICK, LRADC_DELAY(0));
 
-       mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
+       mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0);
        if (lradc->soc == IMX28_LRADC)
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
-                                       LRADC_CTRL1);
+               mxs_lradc_reg_clear(lradc,
+                       lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+                       LRADC_CTRL1);
 
        kfree(lradc->buffer);
        mutex_unlock(&lradc->lock);
@@ -1353,7 +1344,7 @@ static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio,
        if (lradc->use_touchbutton)
                rsvd_chans++;
        if (lradc->use_touchscreen)
-               rsvd_chans++;
+               rsvd_chans += 2;
 
        /* Test for attempts to map channels with special mode of operation. */
        if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS))
@@ -1413,6 +1404,13 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
                .channel = 8,
                .scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
        },
+       /* Hidden channel to keep indexes */
+       {
+               .type = IIO_TEMP,
+               .indexed = 1,
+               .scan_index = -1,
+               .channel = 9,
+       },
        MXS_ADC_CHAN(10, IIO_VOLTAGE),  /* VDDIO */
        MXS_ADC_CHAN(11, IIO_VOLTAGE),  /* VTH */
        MXS_ADC_CHAN(12, IIO_VOLTAGE),  /* VDDA */
@@ -1583,6 +1581,11 @@ static int mxs_lradc_probe(struct platform_device *pdev)
 
        touch_ret = mxs_lradc_probe_touchscreen(lradc, node);
 
+       if (touch_ret == 0)
+               lradc->buffer_vchans = BUFFER_VCHANS_LIMITED;
+       else
+               lradc->buffer_vchans = BUFFER_VCHANS_ALL;
+
        /* Grab all IRQ sources */
        for (i = 0; i < of_cfg->irq_count; i++) {
                lradc->irq[i] = platform_get_irq(pdev, i);
index 017d2f8379b78ca86f7e30ed0e85855684c7b6ec..c17893b4918c82bf176e9ecfac235cd6439e7763 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -68,7 +69,7 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev,
                break;
        case IIO_ANGL_VEL:
                vel = (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
-               vel = (vel << 4) >> 4;
+               vel = sign_extend32(vel, 11);
                *val = vel;
                break;
        default:
index 4324282afe499bc83f32318873a6cd484875df1b..03b2a90b9ac0b6f73109686b66623c61f0cd5ccb 100644 (file)
@@ -330,16 +330,6 @@ static void device_init_registers(struct vnt_private *pDevice)
        /* zonetype initial */
        pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
 
-       /* Get RFType */
-       pDevice->byRFType = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RFTYPE);
-
-       /* force change RevID for VT3253 emu */
-       if ((pDevice->byRFType & RF_EMU) != 0)
-                       pDevice->byRevId = 0x80;
-
-       pDevice->byRFType &= RF_MASK;
-       pr_debug("pDevice->byRFType = %x\n", pDevice->byRFType);
-
        if (!pDevice->bZoneRegExist)
                pDevice->byZoneType = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
 
@@ -1187,12 +1177,14 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        PSTxDesc head_td;
-       u32 dma_idx = TYPE_AC0DMA;
+       u32 dma_idx;
        unsigned long flags;
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       if (!ieee80211_is_data(hdr->frame_control))
+       if (ieee80211_is_data(hdr->frame_control))
+               dma_idx = TYPE_AC0DMA;
+       else
                dma_idx = TYPE_TXDMA0;
 
        if (AVAIL_TD(priv, dma_idx) < 1) {
@@ -1206,6 +1198,9 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        head_td->pTDInfo->skb = skb;
 
+       if (dma_idx == TYPE_AC0DMA)
+               head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
+
        priv->iTDUsed[dma_idx]++;
 
        /* Take ownership */
@@ -1234,13 +1229,10 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma);
 
-       if (dma_idx == TYPE_AC0DMA) {
-               head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
-
+       if (head_td->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)
                MACvTransmitAC0(priv->PortOffset);
-       } else {
+       else
                MACvTransmit0(priv->PortOffset);
-       }
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1778,6 +1770,12 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
        MACvInitialize(priv->PortOffset);
        MACvReadEtherAddress(priv->PortOffset, priv->abyCurrentNetAddr);
 
+       /* Get RFType */
+       priv->byRFType = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_RFTYPE);
+       priv->byRFType &= RF_MASK;
+
+       dev_dbg(&pcid->dev, "RF Type = %x\n", priv->byRFType);
+
        device_get_options(priv);
        device_set_options(priv);
        /* Mask out the options cannot be set to the chip */
index 941b2adca95a9d8fbb01bf2afe8a4c99cd1b04fb..7626f635f160799f581b50d3e1e50bbcc7fd8da0 100644 (file)
@@ -794,6 +794,7 @@ bool RFbSetPower(
                break;
        case RATE_6M:
        case RATE_9M:
+       case RATE_12M:
        case RATE_18M:
                byPwr = priv->abyOFDMPwrTbl[uCH];
                if (priv->byRFType == RF_UW2452)
index c42cde59f598efe27f8bff760ce94ca20692a177..c4286ccac32034558966cc52b7fac8501ecc5daa 100644 (file)
@@ -640,6 +640,7 @@ int vnt_rf_setpower(struct vnt_private *priv, u32 rate, u32 channel)
                break;
        case RATE_6M:
        case RATE_9M:
+       case RATE_12M:
        case RATE_18M:
        case RATE_24M:
        case RATE_36M:
index 50bad55a0c42e3bd9eef6925520cb1e9bddf2209..2accb6e47beb35c1eff10256f7a85d749fe6d590 100644 (file)
@@ -4256,11 +4256,17 @@ int iscsit_close_connection(
        pr_debug("Closing iSCSI connection CID %hu on SID:"
                " %u\n", conn->cid, sess->sid);
        /*
-        * Always up conn_logout_comp just in case the RX Thread is sleeping
-        * and the logout response never got sent because the connection
-        * failed.
+        * Always up conn_logout_comp for the traditional TCP case just in case
+        * the RX Thread in iscsi_target_rx_opcode() is sleeping and the logout
+        * response never got sent because the connection failed.
+        *
+        * However for iser-target, isert_wait4logout() is using conn_logout_comp
+        * to signal logout response TX interrupt completion.  Go ahead and skip
+        * this for iser since isert_rx_opcode() does not wait on logout failure,
+        * and to avoid iscsi_conn pointer dereference in iser-target code.
         */
-       complete(&conn->conn_logout_comp);
+       if (conn->conn_transport->transport_type == ISCSI_TCP)
+               complete(&conn->conn_logout_comp);
 
        iscsi_release_thread_set(conn);
 
index 1c197bad6132be98cd267b6ea666fc24e41e00a9..bdd8731a4daa677083d829333fc651591ebca046 100644 (file)
@@ -22,7 +22,6 @@
 #include <target/target_core_fabric.h>
 
 #include <target/iscsi/iscsi_target_core.h>
-#include <target/iscsi/iscsi_transport.h>
 #include "iscsi_target_seq_pdu_list.h"
 #include "iscsi_target_tq.h"
 #include "iscsi_target_erl0.h"
@@ -940,8 +939,7 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
 
        if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
                spin_unlock_bh(&conn->state_lock);
-               if (conn->conn_transport->transport_type == ISCSI_TCP)
-                       iscsit_close_connection(conn);
+               iscsit_close_connection(conn);
                return;
        }
 
index 6b3c329546895ab1095beb5c048ef24c6e1cea19..c36bd7c29136aba1ea42afbc28cae34c6c7ad6a8 100644 (file)
@@ -953,11 +953,8 @@ static int tcm_loop_make_nexus(
                transport_free_session(tl_nexus->se_sess);
                goto out;
        }
-       /*
-        * Now, register the SAS I_T Nexus as active with the call to
-        * transport_register_session()
-        */
-       __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
+       /* Now, register the SAS I_T Nexus as active. */
+       transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
                        tl_nexus->se_sess, tl_nexus);
        tl_tpg->tl_nexus = tl_nexus;
        pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated"
index 58f49ff69b1424bf5feb33ed64eba495d8826851..79b4ec3ca2db12416a692fba785a09b462e3169f 100644 (file)
@@ -650,6 +650,18 @@ static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
        return aligned_max_sectors;
 }
 
+bool se_dev_check_wce(struct se_device *dev)
+{
+       bool wce = false;
+
+       if (dev->transport->get_write_cache)
+               wce = dev->transport->get_write_cache(dev);
+       else if (dev->dev_attrib.emulate_write_cache > 0)
+               wce = true;
+
+       return wce;
+}
+
 int se_dev_set_max_unmap_lba_count(
        struct se_device *dev,
        u32 max_unmap_lba_count)
@@ -767,6 +779,16 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
                pr_err("Illegal value %d\n", flag);
                return -EINVAL;
        }
+       if (flag &&
+           dev->transport->get_write_cache) {
+               pr_err("emulate_fua_write not supported for this device\n");
+               return -EINVAL;
+       }
+       if (dev->export_count) {
+               pr_err("emulate_fua_write cannot be changed with active"
+                      " exports: %d\n", dev->export_count);
+               return -EINVAL;
+       }
        dev->dev_attrib.emulate_fua_write = flag;
        pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n",
                        dev, dev->dev_attrib.emulate_fua_write);
@@ -801,7 +823,11 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
                pr_err("emulate_write_cache not supported for this device\n");
                return -EINVAL;
        }
-
+       if (dev->export_count) {
+               pr_err("emulate_write_cache cannot be changed with active"
+                      " exports: %d\n", dev->export_count);
+               return -EINVAL;
+       }
        dev->dev_attrib.emulate_write_cache = flag;
        pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n",
                        dev, dev->dev_attrib.emulate_write_cache);
@@ -1534,8 +1560,6 @@ int target_configure_device(struct se_device *dev)
        ret = dev->transport->configure_device(dev);
        if (ret)
                goto out;
-       dev->dev_flags |= DF_CONFIGURED;
-
        /*
         * XXX: there is not much point to have two different values here..
         */
@@ -1597,6 +1621,8 @@ int target_configure_device(struct se_device *dev)
        list_add_tail(&dev->g_dev_node, &g_device_list);
        mutex_unlock(&g_device_mutex);
 
+       dev->dev_flags |= DF_CONFIGURED;
+
        return 0;
 
 out_free_alua:
index 1045dcd7bf651b679ee355a19401065d559976b1..f6c954c4635f5dab27ac24ea117dd284561c836a 100644 (file)
@@ -1121,7 +1121,7 @@ static u32 pscsi_get_device_type(struct se_device *dev)
        struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
        struct scsi_device *sd = pdv->pdv_sd;
 
-       return sd->type;
+       return (sd) ? sd->type : TYPE_NO_LUN;
 }
 
 static sector_t pscsi_get_blocks(struct se_device *dev)
index 9a2f9d3a6e70514ad9351ab6e144709e8b95f91d..3e729741111075cf4828a46ac2f434414e70faf1 100644 (file)
@@ -708,8 +708,7 @@ sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
                }
        }
        if (cdb[1] & 0x8) {
-               if (!dev->dev_attrib.emulate_fua_write ||
-                   !dev->dev_attrib.emulate_write_cache) {
+               if (!dev->dev_attrib.emulate_fua_write || !se_dev_check_wce(dev)) {
                        pr_err("Got CDB: 0x%02x with FUA bit set, but device"
                               " does not advertise support for FUA write\n",
                               cdb[0]);
index 460e9310947399661ce1fbd6ab4ed3e86b4a47e1..6c8bd6bc175ca48fb9d33063dc3f3b8185d19876 100644 (file)
@@ -454,19 +454,6 @@ check_scsi_name:
 }
 EXPORT_SYMBOL(spc_emulate_evpd_83);
 
-static bool
-spc_check_dev_wce(struct se_device *dev)
-{
-       bool wce = false;
-
-       if (dev->transport->get_write_cache)
-               wce = dev->transport->get_write_cache(dev);
-       else if (dev->dev_attrib.emulate_write_cache > 0)
-               wce = true;
-
-       return wce;
-}
-
 /* Extended INQUIRY Data VPD Page */
 static sense_reason_t
 spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
@@ -490,7 +477,7 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
        buf[5] = 0x07;
 
        /* If WriteCache emulation is enabled, set V_SUP */
-       if (spc_check_dev_wce(dev))
+       if (se_dev_check_wce(dev))
                buf[6] = 0x01;
        /* If an LBA map is present set R_SUP */
        spin_lock(&cmd->se_dev->t10_alua.lba_map_lock);
@@ -897,7 +884,7 @@ static int spc_modesense_caching(struct se_cmd *cmd, u8 pc, u8 *p)
        if (pc == 1)
                goto out;
 
-       if (spc_check_dev_wce(dev))
+       if (se_dev_check_wce(dev))
                p[2] = 0x04; /* Write Cache Enable */
        p[12] = 0x20; /* Disabled Read Ahead */
 
@@ -1009,7 +996,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
             (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
                spc_modesense_write_protect(&buf[length], type);
 
-       if ((spc_check_dev_wce(dev)) &&
+       if ((se_dev_check_wce(dev)) &&
            (dev->dev_attrib.emulate_fua_write > 0))
                spc_modesense_dpofua(&buf[length], type);
 
index 0adc0f6502134eb3292a7a2cab66ac75be4d6406..ac3cbabdbdf0243ecbfd91c01e331ee3e0013a1a 100644 (file)
@@ -2389,6 +2389,10 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
        list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
 out:
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+       if (ret && ack_kref)
+               target_put_sess_cmd(se_sess, se_cmd);
+
        return ret;
 }
 EXPORT_SYMBOL(target_get_sess_cmd);
index 97b486c3dda136a21824d02ea0f70c828b214d46..583e755d809177d59953b991a9c8dd9068649205 100644 (file)
@@ -359,7 +359,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
                ep = fc_seq_exch(seq);
                if (ep) {
                        lport = ep->lp;
-                       if (lport && (ep->xid <= lport->lro_xid))
+                       if (lport && (ep->xid <= lport->lro_xid)) {
                                /*
                                 * "ddp_done" trigger invalidation of HW
                                 * specific DDP context
@@ -374,6 +374,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
                                 * identified using ep->xid)
                                 */
                                cmd->was_ddp_setup = 0;
+                       }
                }
        }
 }
index 25d244cbbe8fda719658e35be8f2081ee0f5989f..031018e7a65bd72a4ec8ba3a452e16f455e5f3a1 100644 (file)
@@ -262,13 +262,12 @@ static int int3400_thermal_probe(struct platform_device *pdev)
        result = acpi_parse_art(priv->adev->handle, &priv->art_count,
                                &priv->arts, true);
        if (result)
-               goto free_priv;
-
+               dev_dbg(&pdev->dev, "_ART table parsing error\n");
 
        result = acpi_parse_trt(priv->adev->handle, &priv->trt_count,
                                &priv->trts, true);
        if (result)
-               goto free_art;
+               dev_dbg(&pdev->dev, "_TRT table parsing error\n");
 
        platform_set_drvdata(pdev, priv);
 
@@ -281,7 +280,7 @@ static int int3400_thermal_probe(struct platform_device *pdev)
                                                &int3400_thermal_params, 0, 0);
        if (IS_ERR(priv->thermal)) {
                result = PTR_ERR(priv->thermal);
-               goto free_trt;
+               goto free_art_trt;
        }
 
        priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add(
@@ -295,9 +294,8 @@ static int int3400_thermal_probe(struct platform_device *pdev)
 
 free_zone:
        thermal_zone_device_unregister(priv->thermal);
-free_trt:
+free_art_trt:
        kfree(priv->trts);
-free_art:
        kfree(priv->arts);
 free_priv:
        kfree(priv);
index f88b0887702568578a5d288f925ab1c5b08e7a97..1e25133d35e2cbe8e7476a382bd27433a5801b0c 100644 (file)
@@ -208,7 +208,7 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
                                trip_cnt, GFP_KERNEL);
                if (!int34x_thermal_zone->aux_trips) {
                        ret = -ENOMEM;
-                       goto free_mem;
+                       goto err_trip_alloc;
                }
                trip_mask = BIT(trip_cnt) - 1;
                int34x_thermal_zone->aux_trip_nr = trip_cnt;
@@ -248,14 +248,15 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
                                                0, 0);
        if (IS_ERR(int34x_thermal_zone->zone)) {
                ret = PTR_ERR(int34x_thermal_zone->zone);
-               goto free_lpat;
+               goto err_thermal_zone;
        }
 
        return int34x_thermal_zone;
 
-free_lpat:
+err_thermal_zone:
        acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
-free_mem:
+       kfree(int34x_thermal_zone->aux_trips);
+err_trip_alloc:
        kfree(int34x_thermal_zone);
        return ERR_PTR(ret);
 }
@@ -266,6 +267,7 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone
 {
        thermal_zone_device_unregister(int34x_thermal_zone->zone);
        acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
+       kfree(int34x_thermal_zone->aux_trips);
        kfree(int34x_thermal_zone);
 }
 EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
index 6ceebd659dd400423c0640b1d0911da36b441b74..12623bc02f46679674d9bd1c3f1574fc21b57c37 100644 (file)
@@ -688,6 +688,7 @@ static const struct x86_cpu_id intel_powerclamp_ids[] = {
        { X86_VENDOR_INTEL, 6, 0x45},
        { X86_VENDOR_INTEL, 6, 0x46},
        { X86_VENDOR_INTEL, 6, 0x4c},
+       { X86_VENDOR_INTEL, 6, 0x4d},
        { X86_VENDOR_INTEL, 6, 0x56},
        {}
 };
index 2580a4872f90febeb5af00136e16054bb59e4903..fe4e767018c4cf73afa3c53852b6d48191e2a81e 100644 (file)
@@ -387,21 +387,9 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 
        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (irq) {
-               int ret;
-
                /*
                 * platform has IRQ support.
                 * Then, driver uses common registers
-                */
-
-               ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
-                                      dev_name(dev), common);
-               if (ret) {
-                       dev_err(dev, "irq request failed\n ");
-                       return ret;
-               }
-
-               /*
                 * rcar_has_irq_support() will be enabled
                 */
                res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
@@ -456,8 +444,16 @@ static int rcar_thermal_probe(struct platform_device *pdev)
        }
 
        /* enable temperature comparation */
-       if (irq)
+       if (irq) {
+               ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
+                                      dev_name(dev), common);
+               if (ret) {
+                       dev_err(dev, "irq request failed\n ");
+                       goto error_unregister;
+               }
+
                rcar_thermal_common_write(common, ENR, enr_bits);
+       }
 
        platform_set_drvdata(pdev, common);
 
@@ -467,9 +463,9 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 
 error_unregister:
        rcar_thermal_for_each_priv(priv, common) {
-               thermal_zone_device_unregister(priv->zone);
                if (rcar_has_irq_support(priv))
                        rcar_thermal_irq_disable(priv);
+               thermal_zone_device_unregister(priv->zone);
        }
 
        pm_runtime_put(dev);
@@ -485,9 +481,9 @@ static int rcar_thermal_remove(struct platform_device *pdev)
        struct rcar_thermal_priv *priv;
 
        rcar_thermal_for_each_priv(priv, common) {
-               thermal_zone_device_unregister(priv->zone);
                if (rcar_has_irq_support(priv))
                        rcar_thermal_irq_disable(priv);
+               thermal_zone_device_unregister(priv->zone);
        }
 
        pm_runtime_put(dev);
index 933cd80a6bc5693e23da36048461bfd6250ba40b..1d30b0975651547bdc1464befd517eb450957fc0 100644 (file)
@@ -682,6 +682,7 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on)
 
        if (on) {
                con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
+               con |= (1 << EXYNOS7_PD_DET_EN_SHIFT);
                interrupt_en =
                        (of_thermal_is_trip_valid(tz, 7)
                        << EXYNOS7_TMU_INTEN_RISE7_SHIFT) |
@@ -704,9 +705,9 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on)
                        interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
        } else {
                con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
+               con &= ~(1 << EXYNOS7_PD_DET_EN_SHIFT);
                interrupt_en = 0; /* Disable all interrupts */
        }
-       con |= 1 << EXYNOS7_PD_DET_EN_SHIFT;
 
        writel(interrupt_en, data->base + EXYNOS7_TMU_REG_INTEN);
        writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
@@ -918,34 +919,16 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
 }
 
 static const struct of_device_id exynos_tmu_match[] = {
-       {
-               .compatible = "samsung,exynos3250-tmu",
-       },
-       {
-               .compatible = "samsung,exynos4210-tmu",
-       },
-       {
-               .compatible = "samsung,exynos4412-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5250-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5260-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5420-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5420-tmu-ext-triminfo",
-       },
-       {
-               .compatible = "samsung,exynos5440-tmu",
-       },
-       {
-               .compatible = "samsung,exynos7-tmu",
-       },
-       {},
+       { .compatible = "samsung,exynos3250-tmu", },
+       { .compatible = "samsung,exynos4210-tmu", },
+       { .compatible = "samsung,exynos4412-tmu", },
+       { .compatible = "samsung,exynos5250-tmu", },
+       { .compatible = "samsung,exynos5260-tmu", },
+       { .compatible = "samsung,exynos5420-tmu", },
+       { .compatible = "samsung,exynos5420-tmu-ext-triminfo", },
+       { .compatible = "samsung,exynos5440-tmu", },
+       { .compatible = "samsung,exynos7-tmu", },
+       { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, exynos_tmu_match);
 
index 48491d1a81d650f1d10812c1fb8d5e05ff99cbe1..174d3bcf8bd7a16a161cdf94c53e8d14efaa55a6 100644 (file)
@@ -899,6 +899,22 @@ thermal_cooling_device_trip_point_show(struct device *dev,
                return sprintf(buf, "%d\n", instance->trip);
 }
 
+static struct attribute *cooling_device_attrs[] = {
+       &dev_attr_cdev_type.attr,
+       &dev_attr_max_state.attr,
+       &dev_attr_cur_state.attr,
+       NULL,
+};
+
+static const struct attribute_group cooling_device_attr_group = {
+       .attrs = cooling_device_attrs,
+};
+
+static const struct attribute_group *cooling_device_attr_groups[] = {
+       &cooling_device_attr_group,
+       NULL,
+};
+
 /* Device management */
 
 /**
@@ -1130,6 +1146,7 @@ __thermal_cooling_device_register(struct device_node *np,
        cdev->ops = ops;
        cdev->updated = false;
        cdev->device.class = &thermal_class;
+       cdev->device.groups = cooling_device_attr_groups;
        cdev->devdata = devdata;
        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
        result = device_register(&cdev->device);
@@ -1139,21 +1156,6 @@ __thermal_cooling_device_register(struct device_node *np,
                return ERR_PTR(result);
        }
 
-       /* sys I/F */
-       if (type) {
-               result = device_create_file(&cdev->device, &dev_attr_cdev_type);
-               if (result)
-                       goto unregister;
-       }
-
-       result = device_create_file(&cdev->device, &dev_attr_max_state);
-       if (result)
-               goto unregister;
-
-       result = device_create_file(&cdev->device, &dev_attr_cur_state);
-       if (result)
-               goto unregister;
-
        /* Add 'this' new cdev to the global cdev list */
        mutex_lock(&thermal_list_lock);
        list_add(&cdev->node, &thermal_cdev_list);
@@ -1163,11 +1165,6 @@ __thermal_cooling_device_register(struct device_node *np,
        bind_cdev(cdev);
 
        return cdev;
-
-unregister:
-       release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
-       device_unregister(&cdev->device);
-       return ERR_PTR(result);
 }
 
 /**
index 634b6ce0e63ace5757c06513b45ac563dcfab593..62a5d449c38805019db7d554e6c0f7f43d215341 100644 (file)
@@ -1402,7 +1402,7 @@ int ti_bandgap_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ti_bandgap_save_ctxt(struct ti_bandgap *bgp)
 {
        int i;
index 3fb054a10f6a0fde450e29a98ee4cdf90e18f6c7..a38c1756442aa2611e0e207466aabba4e72b94cc 100644 (file)
@@ -429,7 +429,7 @@ int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
 
        data = ti_bandgap_get_sensor_data(bgp, id);
 
-       if (data && data->cool_dev)
+       if (data)
                cpufreq_cooling_unregister(data->cool_dev);
 
        return 0;
index d7b198c400c755487309cf6e6d9b615c9cfe4a69..ce24182f851479ab61372d1091840696cfe6857f 100644 (file)
@@ -210,18 +210,6 @@ bfin_jc_chars_in_buffer(struct tty_struct *tty)
        return circ_cnt(&bfin_jc_write_buf);
 }
 
-static void
-bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       unsigned long expire = jiffies + timeout;
-       while (!circ_empty(&bfin_jc_write_buf)) {
-               if (signal_pending(current))
-                       break;
-               if (time_after(jiffies, expire))
-                       break;
-       }
-}
-
 static const struct tty_operations bfin_jc_ops = {
        .open            = bfin_jc_open,
        .close           = bfin_jc_close,
@@ -230,7 +218,6 @@ static const struct tty_operations bfin_jc_ops = {
        .flush_chars     = bfin_jc_flush_chars,
        .write_room      = bfin_jc_write_room,
        .chars_in_buffer = bfin_jc_chars_in_buffer,
-       .wait_until_sent = bfin_jc_wait_until_sent,
 };
 
 static int __init bfin_jc_init(void)
index e3b9570a1eff8aa467ec7dabbe93369c47940e87..deae122c9c4bac6a2bb28d6bbc191bfc18d16747 100644 (file)
@@ -2138,8 +2138,8 @@ int serial8250_do_startup(struct uart_port *port)
        /*
         * Clear the interrupt registers.
         */
-       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
-               serial_port_in(port, UART_RX);
+       serial_port_in(port, UART_LSR);
+       serial_port_in(port, UART_RX);
        serial_port_in(port, UART_IIR);
        serial_port_in(port, UART_MSR);
 
@@ -2300,8 +2300,8 @@ dont_test_tx_en:
         * saved flags to avoid getting false values from polling
         * routines or the previous session.
         */
-       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
-               serial_port_in(port, UART_RX);
+       serial_port_in(port, UART_LSR);
+       serial_port_in(port, UART_RX);
        serial_port_in(port, UART_IIR);
        serial_port_in(port, UART_MSR);
        up->lsr_saved_flags = 0;
@@ -2394,8 +2394,7 @@ void serial8250_do_shutdown(struct uart_port *port)
         * Read data port to reset things, and then unlink from
         * the IRQ chain.
         */
-       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
-               serial_port_in(port, UART_RX);
+       serial_port_in(port, UART_RX);
        serial8250_rpm_put(up);
 
        del_timer_sync(&up->timer);
index e60116235836498e5b20ce56219b7d8c949acd25..6ae5b8560e4d764cafb8143a8a4654a81bf21f83 100644 (file)
@@ -59,6 +59,8 @@ struct dw8250_data {
        u8                      usr_reg;
        int                     last_mcr;
        int                     line;
+       int                     msr_mask_on;
+       int                     msr_mask_off;
        struct clk              *clk;
        struct clk              *pclk;
        struct reset_control    *rst;
@@ -81,6 +83,12 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
                value &= ~UART_MSR_DCTS;
        }
 
+       /* Override any modem control signals if needed */
+       if (offset == UART_MSR) {
+               value |= d->msr_mask_on;
+               value &= ~d->msr_mask_off;
+       }
+
        return value;
 }
 
@@ -111,7 +119,10 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
                        dw8250_force_idle(p);
                        writeb(value, p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 
@@ -155,7 +166,10 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
                        __raw_writeq(value & 0xff,
                                     p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 #endif /* CONFIG_64BIT */
@@ -179,7 +193,10 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
                        dw8250_force_idle(p);
                        writel(value, p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 
@@ -334,6 +351,30 @@ static int dw8250_probe_of(struct uart_port *p,
        if (id >= 0)
                p->line = id;
 
+       if (of_property_read_bool(np, "dcd-override")) {
+               /* Always report DCD as active */
+               data->msr_mask_on |= UART_MSR_DCD;
+               data->msr_mask_off |= UART_MSR_DDCD;
+       }
+
+       if (of_property_read_bool(np, "dsr-override")) {
+               /* Always report DSR as active */
+               data->msr_mask_on |= UART_MSR_DSR;
+               data->msr_mask_off |= UART_MSR_DDSR;
+       }
+
+       if (of_property_read_bool(np, "cts-override")) {
+               /* Always report DSR as active */
+               data->msr_mask_on |= UART_MSR_DSR;
+               data->msr_mask_off |= UART_MSR_DDSR;
+       }
+
+       if (of_property_read_bool(np, "ri-override")) {
+               /* Always report Ring indicator as inactive */
+               data->msr_mask_off |= UART_MSR_RI;
+               data->msr_mask_off |= UART_MSR_TERI;
+       }
+
        /* clock got configured through clk api, all done */
        if (p->uartclk)
                return 0;
index daf2c82984e95d94d806b175bc59944ac1cd9713..892eb32cdef4bd98586d02e2e432c38aea512797 100644 (file)
@@ -69,7 +69,7 @@ static void moan_device(const char *str, struct pci_dev *dev)
               "Please send the output of lspci -vv, this\n"
               "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
               "manufacturer and name of serial board or\n"
-              "modem board to rmk+serial@arm.linux.org.uk.\n",
+              "modem board to <linux-serial@vger.kernel.org>.\n",
               pci_name(dev), str, dev->vendor, dev->device,
               dev->subsystem_vendor, dev->subsystem_device);
 }
@@ -1987,13 +1987,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = byt_serial_setup,
        },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_QRK_UART,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_default_setup,
-       },
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = PCI_DEVICE_ID_INTEL_BSW_UART1,
@@ -2199,13 +2192,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
        /*
         * PLX
         */
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9030,
-               .subvendor      = PCI_SUBVENDOR_ID_PERLE,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_default_setup,
-       },
        {
                .vendor         = PCI_VENDOR_ID_PLX,
                .device         = PCI_DEVICE_ID_PLX_9050,
@@ -5415,10 +5401,6 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_b0_bt_2_115200 },
 
-       {       PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH352_2S,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0, 0, pbn_b0_bt_2_115200 },
-
        {       PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_wch384_4 },
index 846552bff67d6f005c3966e80368134dcd9ab27f..4e959c43f6804d12f8677d916e1f050bdc740457 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/err.h>
 #include <linux/irq.h>
+#include <linux/suspend.h>
 
 #include <asm/io.h>
 #include <asm/ioctls.h>
@@ -173,6 +174,12 @@ struct atmel_uart_port {
        bool                    ms_irq_enabled;
        bool                    is_usart;       /* usart or uart */
        struct timer_list       uart_timer;     /* uart timer */
+
+       bool                    suspended;
+       unsigned int            pending;
+       unsigned int            pending_status;
+       spinlock_t              lock_suspended;
+
        int (*prepare_rx)(struct uart_port *port);
        int (*prepare_tx)(struct uart_port *port);
        void (*schedule_rx)(struct uart_port *port);
@@ -1179,12 +1186,15 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
 {
        struct uart_port *port = dev_id;
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int status, pending, pass_counter = 0;
+       unsigned int status, pending, mask, pass_counter = 0;
        bool gpio_handled = false;
 
+       spin_lock(&atmel_port->lock_suspended);
+
        do {
                status = atmel_get_lines_status(port);
-               pending = status & UART_GET_IMR(port);
+               mask = UART_GET_IMR(port);
+               pending = status & mask;
                if (!gpio_handled) {
                        /*
                         * Dealing with GPIO interrupt
@@ -1206,11 +1216,21 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
                if (!pending)
                        break;
 
+               if (atmel_port->suspended) {
+                       atmel_port->pending |= pending;
+                       atmel_port->pending_status = status;
+                       UART_PUT_IDR(port, mask);
+                       pm_system_wakeup();
+                       break;
+               }
+
                atmel_handle_receive(port, pending);
                atmel_handle_status(port, pending, status);
                atmel_handle_transmit(port, pending);
        } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
 
+       spin_unlock(&atmel_port->lock_suspended);
+
        return pass_counter ? IRQ_HANDLED : IRQ_NONE;
 }
 
@@ -1742,7 +1762,8 @@ static int atmel_startup(struct uart_port *port)
        /*
         * Allocate the IRQ
         */
-       retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
+       retval = request_irq(port->irq, atmel_interrupt,
+                       IRQF_SHARED | IRQF_COND_SUSPEND,
                        tty ? tty->name : "atmel_serial", port);
        if (retval) {
                dev_err(port->dev, "atmel_startup - Can't get irq\n");
@@ -2513,8 +2534,14 @@ static int atmel_serial_suspend(struct platform_device *pdev,
 
        /* we can not wake up if we're running on slow clock */
        atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
-       if (atmel_serial_clk_will_stop())
+       if (atmel_serial_clk_will_stop()) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&atmel_port->lock_suspended, flags);
+               atmel_port->suspended = true;
+               spin_unlock_irqrestore(&atmel_port->lock_suspended, flags);
                device_set_wakeup_enable(&pdev->dev, 0);
+       }
 
        uart_suspend_port(&atmel_uart, port);
 
@@ -2525,6 +2552,18 @@ static int atmel_serial_resume(struct platform_device *pdev)
 {
        struct uart_port *port = platform_get_drvdata(pdev);
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&atmel_port->lock_suspended, flags);
+       if (atmel_port->pending) {
+               atmel_handle_receive(port, atmel_port->pending);
+               atmel_handle_status(port, atmel_port->pending,
+                                   atmel_port->pending_status);
+               atmel_handle_transmit(port, atmel_port->pending);
+               atmel_port->pending = 0;
+       }
+       atmel_port->suspended = false;
+       spin_unlock_irqrestore(&atmel_port->lock_suspended, flags);
 
        uart_resume_port(&atmel_uart, port);
        device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
@@ -2593,6 +2632,8 @@ static int atmel_serial_probe(struct platform_device *pdev)
        port->backup_imr = 0;
        port->uart.line = ret;
 
+       spin_lock_init(&port->lock_suspended);
+
        ret = atmel_init_gpios(port, &pdev->dev);
        if (ret < 0)
                dev_err(&pdev->dev, "%s",
index 7ff61e24a195cbca54d60aaefd65bbdf3d0af187..33fb94f7896773c53141ec283f15a3a18be96f1a 100644 (file)
@@ -133,10 +133,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
        if (of_find_property(np, "no-loopback-test", NULL))
                port->flags |= UPF_SKIP_TEST;
 
-       ret = of_alias_get_id(np, "serial");
-       if (ret >= 0)
-               port->line = ret;
-
        port->dev = &ofdev->dev;
 
        switch (type) {
index 594b63331ef40e42fa75a87cde1c139a46014398..bca975f5093b73fd5ebf3e0f4ec8c42e97dfea35 100644 (file)
@@ -293,8 +293,10 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
 
        ims = serial_in(port, SPRD_IMSR);
 
-       if (!ims)
+       if (!ims) {
+               spin_unlock(&port->lock);
                return IRQ_NONE;
+       }
 
        serial_out(port, SPRD_ICLR, ~0);
 
index 51f066aa375e64789e03b9a527679e3a0a7e1c8d..2bb4dfc028734079f29a89bfb779bfdc7e0079eb 100644 (file)
@@ -1028,8 +1028,8 @@ EXPORT_SYMBOL(start_tty);
 /* We limit tty time update visibility to every 8 seconds or so. */
 static void tty_update_time(struct timespec *time)
 {
-       unsigned long sec = get_seconds() & ~7;
-       if ((long)(sec - time->tv_sec) > 0)
+       unsigned long sec = get_seconds();
+       if (abs(sec - time->tv_sec) & ~7)
                time->tv_sec = sec;
 }
 
index a5cf253b2544f001a775f93a7905e63475f7eb7e..632fc815206169281af9aa13f6ca345eb846eabe 100644 (file)
@@ -217,11 +217,17 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
 #endif
        if (!timeout)
                timeout = MAX_SCHEDULE_TIMEOUT;
-       if (wait_event_interruptible_timeout(tty->write_wait,
-                       !tty_chars_in_buffer(tty), timeout) >= 0) {
-               if (tty->ops->wait_until_sent)
-                       tty->ops->wait_until_sent(tty, timeout);
-       }
+
+       timeout = wait_event_interruptible_timeout(tty->write_wait,
+                       !tty_chars_in_buffer(tty), timeout);
+       if (timeout <= 0)
+               return;
+
+       if (timeout == MAX_SCHEDULE_TIMEOUT)
+               timeout = 0;
+
+       if (tty->ops->wait_until_sent)
+               tty->ops->wait_until_sent(tty, timeout);
 }
 EXPORT_SYMBOL(tty_wait_until_sent);
 
index ff451048c1aca26d14cd23a40b344810134695cf..4bfb7ac0239f9b4bac46ec3246ff99f29e4dcc2a 100644 (file)
@@ -929,6 +929,13 @@ __acquires(hwep->lock)
        return retval;
 }
 
+static int otg_a_alt_hnp_support(struct ci_hdrc *ci)
+{
+       dev_warn(&ci->gadget.dev,
+               "connect the device to an alternate port if you want HNP\n");
+       return isr_setup_status_phase(ci);
+}
+
 /**
  * isr_setup_packet_handler: setup packet handler
  * @ci: UDC descriptor
@@ -1061,6 +1068,10 @@ __acquires(ci->lock)
                                                        ci);
                                }
                                break;
+                       case USB_DEVICE_A_ALT_HNP_SUPPORT:
+                               if (ci_otg_is_fsm_mode(ci))
+                                       err = otg_a_alt_hnp_support(ci);
+                               break;
                        default:
                                goto delegate;
                        }
index e78720b59d67e66adebff9594475b124341b0608..683617714e7cf852fdf3fc2d4ec8590ab6d1a114 100644 (file)
@@ -1650,6 +1650,8 @@ static int acm_reset_resume(struct usb_interface *intf)
 
 static const struct usb_device_id acm_ids[] = {
        /* quirky and broken devices */
+       { USB_DEVICE(0x076d, 0x0006), /* Denso Cradle CU-321 */
+       .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
        { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
        .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
        { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
index c6b35b77dab73a173eb08d2522d4d961bebc7163..61d538aa23466b62ddf37eec8567460ecf0cd363 100644 (file)
@@ -150,9 +150,9 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
                break;
        case OTG_STATE_B_PERIPHERAL:
                otg_chrg_vbus(fsm, 0);
-               otg_loc_conn(fsm, 1);
                otg_loc_sof(fsm, 0);
                otg_set_protocol(fsm, PROTO_GADGET);
+               otg_loc_conn(fsm, 1);
                break;
        case OTG_STATE_B_WAIT_ACON:
                otg_chrg_vbus(fsm, 0);
@@ -213,10 +213,10 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 
                break;
        case OTG_STATE_A_PERIPHERAL:
-               otg_loc_conn(fsm, 1);
                otg_loc_sof(fsm, 0);
                otg_set_protocol(fsm, PROTO_GADGET);
                otg_drv_vbus(fsm, 1);
+               otg_loc_conn(fsm, 1);
                otg_add_timer(fsm, A_BIDL_ADIS);
                break;
        case OTG_STATE_A_WAIT_VFALL:
index 66abdbcfbfa55c08c4989d5ce4fe16b087486a79..11635537c052cdc5d4e4c78d615a09aafc4c5e83 100644 (file)
@@ -501,6 +501,7 @@ static void async_completed(struct urb *urb)
        as->status = urb->status;
        signr = as->signr;
        if (signr) {
+               memset(&sinfo, 0, sizeof(sinfo));
                sinfo.si_signo = as->signr;
                sinfo.si_errno = as->status;
                sinfo.si_code = SI_ASYNCIO;
@@ -2382,6 +2383,7 @@ static void usbdev_remove(struct usb_device *udev)
                wake_up_all(&ps->wait);
                list_del_init(&ps->list);
                if (ps->discsignr) {
+                       memset(&sinfo, 0, sizeof(sinfo));
                        sinfo.si_signo = ps->discsignr;
                        sinfo.si_errno = EPIPE;
                        sinfo.si_code = SI_ASYNCIO;
index 02e3e2d4ea5658c0ddd6de8b1cb1729425a3c0ab..6cf047878dbae1812d19c27b13d5d5a1ce71536a 100644 (file)
@@ -377,6 +377,9 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
                dwc2_is_host_mode(hsotg) ? "Host" : "Device",
                dwc2_op_state_str(hsotg));
 
+       if (hsotg->op_state == OTG_STATE_A_HOST)
+               dwc2_hcd_disconnect(hsotg);
+
        /* Change to L3 (OFF) state */
        hsotg->lx_state = DWC2_L3;
 
index 172d64e585b61b014f3333ef200d2cb2ba48958d..52e0c4e5e48efa8cc1ccecf0ee30364ff1419634 100644 (file)
@@ -205,6 +205,18 @@ static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value)
                                                omap->irq0_offset, value);
 }
 
+static void dwc3_omap_write_irqmisc_clr(struct dwc3_omap *omap, u32 value)
+{
+       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_MISC +
+                                               omap->irqmisc_offset, value);
+}
+
+static void dwc3_omap_write_irq0_clr(struct dwc3_omap *omap, u32 value)
+{
+       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_0 -
+                                               omap->irq0_offset, value);
+}
+
 static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
        enum omap_dwc3_vbus_id_status status)
 {
@@ -345,9 +357,23 @@ static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
 
 static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
 {
+       u32                     reg;
+
        /* disable all IRQs */
-       dwc3_omap_write_irqmisc_set(omap, 0x00);
-       dwc3_omap_write_irq0_set(omap, 0x00);
+       reg = USBOTGSS_IRQO_COREIRQ_ST;
+       dwc3_omap_write_irq0_clr(omap, reg);
+
+       reg = (USBOTGSS_IRQMISC_OEVT |
+                       USBOTGSS_IRQMISC_DRVVBUS_RISE |
+                       USBOTGSS_IRQMISC_CHRGVBUS_RISE |
+                       USBOTGSS_IRQMISC_DISCHRGVBUS_RISE |
+                       USBOTGSS_IRQMISC_IDPULLUP_RISE |
+                       USBOTGSS_IRQMISC_DRVVBUS_FALL |
+                       USBOTGSS_IRQMISC_CHRGVBUS_FALL |
+                       USBOTGSS_IRQMISC_DISCHRGVBUS_FALL |
+                       USBOTGSS_IRQMISC_IDPULLUP_FALL);
+
+       dwc3_omap_write_irqmisc_clr(omap, reg);
 }
 
 static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
index 75648145dc1b686a89cae9f8d4de451b71ef376a..c42765b3a060bc6b28b0f7a55f0231489afe651c 100644 (file)
@@ -1161,7 +1161,6 @@ static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc,
        if (desc->opts_mutex)
                mutex_lock(desc->opts_mutex);
        memcpy(desc->ext_compat_id, page, l);
-       desc->ext_compat_id[l] = '\0';
 
        if (desc->opts_mutex)
                mutex_unlock(desc->opts_mutex);
@@ -1192,7 +1191,6 @@ static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc,
        if (desc->opts_mutex)
                mutex_lock(desc->opts_mutex);
        memcpy(desc->ext_compat_id + 8, page, l);
-       desc->ext_compat_id[l + 8] = '\0';
 
        if (desc->opts_mutex)
                mutex_unlock(desc->opts_mutex);
index af98b096af2fde060aea8978005e8ea620762566..175c9956cbe3a36949526029103d38b4c97225c3 100644 (file)
@@ -144,10 +144,9 @@ struct ffs_io_data {
        bool read;
 
        struct kiocb *kiocb;
-       const struct iovec *iovec;
-       unsigned long nr_segs;
-       char __user *buf;
-       size_t len;
+       struct iov_iter data;
+       const void *to_free;
+       char *buf;
 
        struct mm_struct *mm;
        struct work_struct work;
@@ -649,29 +648,10 @@ static void ffs_user_copy_worker(struct work_struct *work)
                                         io_data->req->actual;
 
        if (io_data->read && ret > 0) {
-               int i;
-               size_t pos = 0;
-
-               /*
-                * Since req->length may be bigger than io_data->len (after
-                * being rounded up to maxpacketsize), we may end up with more
-                * data then user space has space for.
-                */
-               ret = min_t(int, ret, io_data->len);
-
                use_mm(io_data->mm);
-               for (i = 0; i < io_data->nr_segs; i++) {
-                       size_t len = min_t(size_t, ret - pos,
-                                       io_data->iovec[i].iov_len);
-                       if (!len)
-                               break;
-                       if (unlikely(copy_to_user(io_data->iovec[i].iov_base,
-                                                &io_data->buf[pos], len))) {
-                               ret = -EFAULT;
-                               break;
-                       }
-                       pos += len;
-               }
+               ret = copy_to_iter(io_data->buf, ret, &io_data->data);
+               if (iov_iter_count(&io_data->data))
+                       ret = -EFAULT;
                unuse_mm(io_data->mm);
        }
 
@@ -684,7 +664,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
 
        io_data->kiocb->private = NULL;
        if (io_data->read)
-               kfree(io_data->iovec);
+               kfree(io_data->to_free);
        kfree(io_data->buf);
        kfree(io_data);
 }
@@ -743,6 +723,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                 * before the waiting completes, so do not assign to 'gadget' earlier
                 */
                struct usb_gadget *gadget = epfile->ffs->gadget;
+               size_t copied;
 
                spin_lock_irq(&epfile->ffs->eps_lock);
                /* In the meantime, endpoint got disabled or changed. */
@@ -750,34 +731,21 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                        spin_unlock_irq(&epfile->ffs->eps_lock);
                        return -ESHUTDOWN;
                }
+               data_len = iov_iter_count(&io_data->data);
                /*
                 * Controller may require buffer size to be aligned to
                 * maxpacketsize of an out endpoint.
                 */
-               data_len = io_data->read ?
-                          usb_ep_align_maybe(gadget, ep->ep, io_data->len) :
-                          io_data->len;
+               if (io_data->read)
+                       data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
                spin_unlock_irq(&epfile->ffs->eps_lock);
 
                data = kmalloc(data_len, GFP_KERNEL);
                if (unlikely(!data))
                        return -ENOMEM;
-               if (io_data->aio && !io_data->read) {
-                       int i;
-                       size_t pos = 0;
-                       for (i = 0; i < io_data->nr_segs; i++) {
-                               if (unlikely(copy_from_user(&data[pos],
-                                            io_data->iovec[i].iov_base,
-                                            io_data->iovec[i].iov_len))) {
-                                       ret = -EFAULT;
-                                       goto error;
-                               }
-                               pos += io_data->iovec[i].iov_len;
-                       }
-               } else {
-                       if (!io_data->read &&
-                           unlikely(__copy_from_user(data, io_data->buf,
-                                                     io_data->len))) {
+               if (!io_data->read) {
+                       copied = copy_from_iter(data, data_len, &io_data->data);
+                       if (copied != data_len) {
                                ret = -EFAULT;
                                goto error;
                        }
@@ -876,10 +844,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                                 */
                                ret = ep->status;
                                if (io_data->read && ret > 0) {
-                                       ret = min_t(size_t, ret, io_data->len);
-
-                                       if (unlikely(copy_to_user(io_data->buf,
-                                               data, ret)))
+                                       ret = copy_to_iter(data, ret, &io_data->data);
+                                       if (unlikely(iov_iter_count(&io_data->data)))
                                                ret = -EFAULT;
                                }
                        }
@@ -898,37 +864,6 @@ error:
        return ret;
 }
 
-static ssize_t
-ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
-                loff_t *ptr)
-{
-       struct ffs_io_data io_data;
-
-       ENTER();
-
-       io_data.aio = false;
-       io_data.read = false;
-       io_data.buf = (char * __user)buf;
-       io_data.len = len;
-
-       return ffs_epfile_io(file, &io_data);
-}
-
-static ssize_t
-ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ffs_io_data io_data;
-
-       ENTER();
-
-       io_data.aio = false;
-       io_data.read = true;
-       io_data.buf = buf;
-       io_data.len = len;
-
-       return ffs_epfile_io(file, &io_data);
-}
-
 static int
 ffs_epfile_open(struct inode *inode, struct file *file)
 {
@@ -965,67 +900,86 @@ static int ffs_aio_cancel(struct kiocb *kiocb)
        return value;
 }
 
-static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb,
-                                   const struct iovec *iovec,
-                                   unsigned long nr_segs, loff_t loff)
+static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 {
-       struct ffs_io_data *io_data;
+       struct ffs_io_data io_data, *p = &io_data;
+       ssize_t res;
 
        ENTER();
 
-       io_data = kmalloc(sizeof(*io_data), GFP_KERNEL);
-       if (unlikely(!io_data))
-               return -ENOMEM;
+       if (!is_sync_kiocb(kiocb)) {
+               p = kmalloc(sizeof(io_data), GFP_KERNEL);
+               if (unlikely(!p))
+                       return -ENOMEM;
+               p->aio = true;
+       } else {
+               p->aio = false;
+       }
 
-       io_data->aio = true;
-       io_data->read = false;
-       io_data->kiocb = kiocb;
-       io_data->iovec = iovec;
-       io_data->nr_segs = nr_segs;
-       io_data->len = kiocb->ki_nbytes;
-       io_data->mm = current->mm;
+       p->read = false;
+       p->kiocb = kiocb;
+       p->data = *from;
+       p->mm = current->mm;
 
-       kiocb->private = io_data;
+       kiocb->private = p;
 
        kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
-       return ffs_epfile_io(kiocb->ki_filp, io_data);
+       res = ffs_epfile_io(kiocb->ki_filp, p);
+       if (res == -EIOCBQUEUED)
+               return res;
+       if (p->aio)
+               kfree(p);
+       else
+               *from = p->data;
+       return res;
 }
 
-static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb,
-                                  const struct iovec *iovec,
-                                  unsigned long nr_segs, loff_t loff)
+static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
 {
-       struct ffs_io_data *io_data;
-       struct iovec *iovec_copy;
+       struct ffs_io_data io_data, *p = &io_data;
+       ssize_t res;
 
        ENTER();
 
-       iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL);
-       if (unlikely(!iovec_copy))
-               return -ENOMEM;
-
-       memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs);
-
-       io_data = kmalloc(sizeof(*io_data), GFP_KERNEL);
-       if (unlikely(!io_data)) {
-               kfree(iovec_copy);
-               return -ENOMEM;
+       if (!is_sync_kiocb(kiocb)) {
+               p = kmalloc(sizeof(io_data), GFP_KERNEL);
+               if (unlikely(!p))
+                       return -ENOMEM;
+               p->aio = true;
+       } else {
+               p->aio = false;
        }
 
-       io_data->aio = true;
-       io_data->read = true;
-       io_data->kiocb = kiocb;
-       io_data->iovec = iovec_copy;
-       io_data->nr_segs = nr_segs;
-       io_data->len = kiocb->ki_nbytes;
-       io_data->mm = current->mm;
+       p->read = true;
+       p->kiocb = kiocb;
+       if (p->aio) {
+               p->to_free = dup_iter(&p->data, to, GFP_KERNEL);
+               if (!p->to_free) {
+                       kfree(p);
+                       return -ENOMEM;
+               }
+       } else {
+               p->data = *to;
+               p->to_free = NULL;
+       }
+       p->mm = current->mm;
 
-       kiocb->private = io_data;
+       kiocb->private = p;
 
        kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
-       return ffs_epfile_io(kiocb->ki_filp, io_data);
+       res = ffs_epfile_io(kiocb->ki_filp, p);
+       if (res == -EIOCBQUEUED)
+               return res;
+
+       if (p->aio) {
+               kfree(p->to_free);
+               kfree(p);
+       } else {
+               *to = p->data;
+       }
+       return res;
 }
 
 static int
@@ -1105,10 +1059,10 @@ static const struct file_operations ffs_epfile_operations = {
        .llseek =       no_llseek,
 
        .open =         ffs_epfile_open,
-       .write =        ffs_epfile_write,
-       .read =         ffs_epfile_read,
-       .aio_write =    ffs_epfile_aio_write,
-       .aio_read =     ffs_epfile_aio_read,
+       .write =        new_sync_write,
+       .read =         new_sync_read,
+       .write_iter =   ffs_epfile_write_iter,
+       .read_iter =    ffs_epfile_read_iter,
        .release =      ffs_epfile_release,
        .unlocked_ioctl =       ffs_epfile_ioctl,
 };
index 426d69a9c018a0a651beac78ce63709c4b283613..a2612fb79eff261ee336b73940f88e7514f9c5e0 100644 (file)
@@ -569,7 +569,7 @@ fail:
        return status;
 }
 
-const struct file_operations f_hidg_fops = {
+static const struct file_operations f_hidg_fops = {
        .owner          = THIS_MODULE,
        .open           = f_hidg_open,
        .release        = f_hidg_release,
index 298b46112b1a354eaa2965edc548b10b628ac577..39f49f1ad22f287e58df631077a9a1506381707b 100644 (file)
@@ -289,8 +289,7 @@ static void disable_loopback(struct f_loopback *loop)
        struct usb_composite_dev        *cdev;
 
        cdev = loop->function.config->cdev;
-       disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL, NULL,
-                       NULL);
+       disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
        VDBG(cdev, "%s disabled\n", loop->function.name);
 }
 
index c89e96cfa3e47b95d179d06910d528710e59d5de..c0c3ef272714b58ea4980ba25cf24076b502a105 100644 (file)
@@ -417,7 +417,10 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                        return -EINVAL;
 
                spin_lock(&port->lock);
-               __pn_reset(f);
+
+               if (fp->in_ep->driver_data)
+                       __pn_reset(f);
+
                if (alt == 1) {
                        int i;
 
index e07c50ced64ddc09256b271f72a5baacfc3b8f18..3a5ae9900b1ee585881aa8233065ef9772de8da7 100644 (file)
 #include "gadget_chips.h"
 #include "u_f.h"
 
-#define USB_MS_TO_SS_INTERVAL(x) USB_MS_TO_HS_INTERVAL(x)
-
-enum eptype {
-       EP_CONTROL = 0,
-       EP_BULK,
-       EP_ISOC,
-       EP_INTERRUPT,
-};
-
 /*
  * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
  * controller drivers.
@@ -64,8 +55,6 @@ struct f_sourcesink {
        struct usb_ep           *out_ep;
        struct usb_ep           *iso_in_ep;
        struct usb_ep           *iso_out_ep;
-       struct usb_ep           *int_in_ep;
-       struct usb_ep           *int_out_ep;
        int                     cur_alt;
 };
 
@@ -79,10 +68,6 @@ static unsigned isoc_interval;
 static unsigned isoc_maxpacket;
 static unsigned isoc_mult;
 static unsigned isoc_maxburst;
-static unsigned int_interval; /* In ms */
-static unsigned int_maxpacket;
-static unsigned int_mult;
-static unsigned int_maxburst;
 static unsigned buflen;
 
 /*-------------------------------------------------------------------------*/
@@ -107,16 +92,6 @@ static struct usb_interface_descriptor source_sink_intf_alt1 = {
        /* .iInterface          = DYNAMIC */
 };
 
-static struct usb_interface_descriptor source_sink_intf_alt2 = {
-       .bLength =              USB_DT_INTERFACE_SIZE,
-       .bDescriptorType =      USB_DT_INTERFACE,
-
-       .bAlternateSetting =    2,
-       .bNumEndpoints =        2,
-       .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
-       /* .iInterface          = DYNAMIC */
-};
-
 /* full speed support: */
 
 static struct usb_endpoint_descriptor fs_source_desc = {
@@ -155,26 +130,6 @@ static struct usb_endpoint_descriptor fs_iso_sink_desc = {
        .bInterval =            4,
 };
 
-static struct usb_endpoint_descriptor fs_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(64),
-       .bInterval =            GZERO_INT_INTERVAL,
-};
-
-static struct usb_endpoint_descriptor fs_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(64),
-       .bInterval =            GZERO_INT_INTERVAL,
-};
-
 static struct usb_descriptor_header *fs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &fs_sink_desc,
@@ -185,10 +140,6 @@ static struct usb_descriptor_header *fs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &fs_source_desc,
        (struct usb_descriptor_header *) &fs_iso_sink_desc,
        (struct usb_descriptor_header *) &fs_iso_source_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define FS_ALT_IFC_2_OFFSET    8
-       (struct usb_descriptor_header *) &fs_int_sink_desc,
-       (struct usb_descriptor_header *) &fs_int_source_desc,
        NULL,
 };
 
@@ -228,24 +179,6 @@ static struct usb_endpoint_descriptor hs_iso_sink_desc = {
        .bInterval =            4,
 };
 
-static struct usb_endpoint_descriptor hs_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-static struct usb_endpoint_descriptor hs_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
 static struct usb_descriptor_header *hs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &hs_source_desc,
@@ -256,10 +189,6 @@ static struct usb_descriptor_header *hs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &hs_sink_desc,
        (struct usb_descriptor_header *) &hs_iso_source_desc,
        (struct usb_descriptor_header *) &hs_iso_sink_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define HS_ALT_IFC_2_OFFSET    8
-       (struct usb_descriptor_header *) &hs_int_source_desc,
-       (struct usb_descriptor_header *) &hs_int_sink_desc,
        NULL,
 };
 
@@ -335,42 +264,6 @@ static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
        .wBytesPerInterval =    cpu_to_le16(1024),
 };
 
-static struct usb_endpoint_descriptor ss_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-struct usb_ss_ep_comp_descriptor ss_int_source_comp_desc = {
-       .bLength =              USB_DT_SS_EP_COMP_SIZE,
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-
-       .bMaxBurst =            0,
-       .bmAttributes =         0,
-       .wBytesPerInterval =    cpu_to_le16(1024),
-};
-
-static struct usb_endpoint_descriptor ss_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-struct usb_ss_ep_comp_descriptor ss_int_sink_comp_desc = {
-       .bLength =              USB_DT_SS_EP_COMP_SIZE,
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-
-       .bMaxBurst =            0,
-       .bmAttributes =         0,
-       .wBytesPerInterval =    cpu_to_le16(1024),
-};
-
 static struct usb_descriptor_header *ss_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &ss_source_desc,
@@ -387,12 +280,6 @@ static struct usb_descriptor_header *ss_source_sink_descs[] = {
        (struct usb_descriptor_header *) &ss_iso_source_comp_desc,
        (struct usb_descriptor_header *) &ss_iso_sink_desc,
        (struct usb_descriptor_header *) &ss_iso_sink_comp_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define SS_ALT_IFC_2_OFFSET    14
-       (struct usb_descriptor_header *) &ss_int_source_desc,
-       (struct usb_descriptor_header *) &ss_int_source_comp_desc,
-       (struct usb_descriptor_header *) &ss_int_sink_desc,
-       (struct usb_descriptor_header *) &ss_int_sink_comp_desc,
        NULL,
 };
 
@@ -414,21 +301,6 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
 };
 
 /*-------------------------------------------------------------------------*/
-static const char *get_ep_string(enum eptype ep_type)
-{
-       switch (ep_type) {
-       case EP_ISOC:
-               return "ISOC-";
-       case EP_INTERRUPT:
-               return "INTERRUPT-";
-       case EP_CONTROL:
-               return "CTRL-";
-       case EP_BULK:
-               return "BULK-";
-       default:
-               return "UNKNOWN-";
-       }
-}
 
 static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
 {
@@ -456,8 +328,7 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
 
 void disable_endpoints(struct usb_composite_dev *cdev,
                struct usb_ep *in, struct usb_ep *out,
-               struct usb_ep *iso_in, struct usb_ep *iso_out,
-               struct usb_ep *int_in, struct usb_ep *int_out)
+               struct usb_ep *iso_in, struct usb_ep *iso_out)
 {
        disable_ep(cdev, in);
        disable_ep(cdev, out);
@@ -465,10 +336,6 @@ void disable_endpoints(struct usb_composite_dev *cdev,
                disable_ep(cdev, iso_in);
        if (iso_out)
                disable_ep(cdev, iso_out);
-       if (int_in)
-               disable_ep(cdev, int_in);
-       if (int_out)
-               disable_ep(cdev, int_out);
 }
 
 static int
@@ -485,7 +352,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
                return id;
        source_sink_intf_alt0.bInterfaceNumber = id;
        source_sink_intf_alt1.bInterfaceNumber = id;
-       source_sink_intf_alt2.bInterfaceNumber = id;
 
        /* allocate bulk endpoints */
        ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
@@ -546,55 +412,14 @@ no_iso:
        if (isoc_maxpacket > 1024)
                isoc_maxpacket = 1024;
 
-       /* sanity check the interrupt module parameters */
-       if (int_interval < 1)
-               int_interval = 1;
-       if (int_interval > 4096)
-               int_interval = 4096;
-       if (int_mult > 2)
-               int_mult = 2;
-       if (int_maxburst > 15)
-               int_maxburst = 15;
-
-       /* fill in the FS interrupt descriptors from the module parameters */
-       fs_int_source_desc.wMaxPacketSize = int_maxpacket > 64 ?
-                                               64 : int_maxpacket;
-       fs_int_source_desc.bInterval = int_interval > 255 ?
-                                               255 : int_interval;
-       fs_int_sink_desc.wMaxPacketSize = int_maxpacket > 64 ?
-                                               64 : int_maxpacket;
-       fs_int_sink_desc.bInterval = int_interval > 255 ?
-                                               255 : int_interval;
-
-       /* allocate int endpoints */
-       ss->int_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_source_desc);
-       if (!ss->int_in_ep)
-               goto no_int;
-       ss->int_in_ep->driver_data = cdev;      /* claim */
-
-       ss->int_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_sink_desc);
-       if (ss->int_out_ep) {
-               ss->int_out_ep->driver_data = cdev;     /* claim */
-       } else {
-               ss->int_in_ep->driver_data = NULL;
-               ss->int_in_ep = NULL;
-no_int:
-               fs_source_sink_descs[FS_ALT_IFC_2_OFFSET] = NULL;
-               hs_source_sink_descs[HS_ALT_IFC_2_OFFSET] = NULL;
-               ss_source_sink_descs[SS_ALT_IFC_2_OFFSET] = NULL;
-       }
-
-       if (int_maxpacket > 1024)
-               int_maxpacket = 1024;
-
        /* support high speed hardware */
        hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
        hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 
        /*
-        * Fill in the HS isoc and interrupt descriptors from the module
-        * parameters. We assume that the user knows what they are doing and
-        * won't give parameters that their UDC doesn't support.
+        * Fill in the HS isoc descriptors from the module parameters.
+        * We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
         */
        hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
        hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
@@ -607,17 +432,6 @@ no_int:
        hs_iso_sink_desc.bInterval = isoc_interval;
        hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
 
-       hs_int_source_desc.wMaxPacketSize = int_maxpacket;
-       hs_int_source_desc.wMaxPacketSize |= int_mult << 11;
-       hs_int_source_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval);
-       hs_int_source_desc.bEndpointAddress =
-               fs_int_source_desc.bEndpointAddress;
-
-       hs_int_sink_desc.wMaxPacketSize = int_maxpacket;
-       hs_int_sink_desc.wMaxPacketSize |= int_mult << 11;
-       hs_int_sink_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval);
-       hs_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress;
-
        /* support super speed hardware */
        ss_source_desc.bEndpointAddress =
                fs_source_desc.bEndpointAddress;
@@ -625,9 +439,9 @@ no_int:
                fs_sink_desc.bEndpointAddress;
 
        /*
-        * Fill in the SS isoc and interrupt descriptors from the module
-        * parameters. We assume that the user knows what they are doing and
-        * won't give parameters that their UDC doesn't support.
+        * Fill in the SS isoc descriptors from the module parameters.
+        * We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
         */
        ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
        ss_iso_source_desc.bInterval = isoc_interval;
@@ -646,37 +460,17 @@ no_int:
                isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
        ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
 
-       ss_int_source_desc.wMaxPacketSize = int_maxpacket;
-       ss_int_source_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval);
-       ss_int_source_comp_desc.bmAttributes = int_mult;
-       ss_int_source_comp_desc.bMaxBurst = int_maxburst;
-       ss_int_source_comp_desc.wBytesPerInterval =
-               int_maxpacket * (int_mult + 1) * (int_maxburst + 1);
-       ss_int_source_desc.bEndpointAddress =
-               fs_int_source_desc.bEndpointAddress;
-
-       ss_int_sink_desc.wMaxPacketSize = int_maxpacket;
-       ss_int_sink_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval);
-       ss_int_sink_comp_desc.bmAttributes = int_mult;
-       ss_int_sink_comp_desc.bMaxBurst = int_maxburst;
-       ss_int_sink_comp_desc.wBytesPerInterval =
-               int_maxpacket * (int_mult + 1) * (int_maxburst + 1);
-       ss_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress;
-
        ret = usb_assign_descriptors(f, fs_source_sink_descs,
                        hs_source_sink_descs, ss_source_sink_descs);
        if (ret)
                return ret;
 
-       DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s, "
-                       "INT-IN/%s, INT-OUT/%s\n",
+       DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
            (gadget_is_superspeed(c->cdev->gadget) ? "super" :
             (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
                        f->name, ss->in_ep->name, ss->out_ep->name,
                        ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
-                       ss->iso_out_ep ? ss->iso_out_ep->name : "<none>",
-                       ss->int_in_ep ? ss->int_in_ep->name : "<none>",
-                       ss->int_out_ep ? ss->int_out_ep->name : "<none>");
+                       ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
        return 0;
 }
 
@@ -807,15 +601,14 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
 }
 
 static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
-               enum eptype ep_type, int speed)
+               bool is_iso, int speed)
 {
        struct usb_ep           *ep;
        struct usb_request      *req;
        int                     i, size, status;
 
        for (i = 0; i < 8; i++) {
-               switch (ep_type) {
-               case EP_ISOC:
+               if (is_iso) {
                        switch (speed) {
                        case USB_SPEED_SUPER:
                                size = isoc_maxpacket * (isoc_mult + 1) *
@@ -831,28 +624,9 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
                        }
                        ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
                        req = ss_alloc_ep_req(ep, size);
-                       break;
-               case EP_INTERRUPT:
-                       switch (speed) {
-                       case USB_SPEED_SUPER:
-                               size = int_maxpacket * (int_mult + 1) *
-                                               (int_maxburst + 1);
-                               break;
-                       case USB_SPEED_HIGH:
-                               size = int_maxpacket * (int_mult + 1);
-                               break;
-                       default:
-                               size = int_maxpacket > 1023 ?
-                                               1023 : int_maxpacket;
-                               break;
-                       }
-                       ep = is_in ? ss->int_in_ep : ss->int_out_ep;
-                       req = ss_alloc_ep_req(ep, size);
-                       break;
-               default:
+               } else {
                        ep = is_in ? ss->in_ep : ss->out_ep;
                        req = ss_alloc_ep_req(ep, 0);
-                       break;
                }
 
                if (!req)
@@ -870,12 +644,12 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 
                        cdev = ss->function.config->cdev;
                        ERROR(cdev, "start %s%s %s --> %d\n",
-                               get_ep_string(ep_type), is_in ? "IN" : "OUT",
-                               ep->name, status);
+                             is_iso ? "ISO-" : "", is_in ? "IN" : "OUT",
+                             ep->name, status);
                        free_ep_req(ep, req);
                }
 
-               if (!(ep_type == EP_ISOC))
+               if (!is_iso)
                        break;
        }
 
@@ -888,7 +662,7 @@ static void disable_source_sink(struct f_sourcesink *ss)
 
        cdev = ss->function.config->cdev;
        disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep,
-                       ss->iso_out_ep, ss->int_in_ep, ss->int_out_ep);
+                       ss->iso_out_ep);
        VDBG(cdev, "%s disabled\n", ss->function.name);
 }
 
@@ -900,62 +674,6 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
        int                                     speed = cdev->gadget->speed;
        struct usb_ep                           *ep;
 
-       if (alt == 2) {
-               /* Configure for periodic interrupt endpoint */
-               ep = ss->int_in_ep;
-               if (ep) {
-                       result = config_ep_by_speed(cdev->gadget,
-                                       &(ss->function), ep);
-                       if (result)
-                               return result;
-
-                       result = usb_ep_enable(ep);
-                       if (result < 0)
-                               return result;
-
-                       ep->driver_data = ss;
-                       result = source_sink_start_ep(ss, true, EP_INTERRUPT,
-                                       speed);
-                       if (result < 0) {
-fail1:
-                               ep = ss->int_in_ep;
-                               if (ep) {
-                                       usb_ep_disable(ep);
-                                       ep->driver_data = NULL;
-                               }
-                               return result;
-                       }
-               }
-
-               /*
-                * one interrupt endpoint reads (sinks) anything OUT (from the
-                * host)
-                */
-               ep = ss->int_out_ep;
-               if (ep) {
-                       result = config_ep_by_speed(cdev->gadget,
-                                       &(ss->function), ep);
-                       if (result)
-                               goto fail1;
-
-                       result = usb_ep_enable(ep);
-                       if (result < 0)
-                               goto fail1;
-
-                       ep->driver_data = ss;
-                       result = source_sink_start_ep(ss, false, EP_INTERRUPT,
-                                       speed);
-                       if (result < 0) {
-                               ep = ss->int_out_ep;
-                               usb_ep_disable(ep);
-                               ep->driver_data = NULL;
-                               goto fail1;
-                       }
-               }
-
-               goto out;
-       }
-
        /* one bulk endpoint writes (sources) zeroes IN (to the host) */
        ep = ss->in_ep;
        result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
@@ -966,7 +684,7 @@ fail1:
                return result;
        ep->driver_data = ss;
 
-       result = source_sink_start_ep(ss, true, EP_BULK, speed);
+       result = source_sink_start_ep(ss, true, false, speed);
        if (result < 0) {
 fail:
                ep = ss->in_ep;
@@ -985,7 +703,7 @@ fail:
                goto fail;
        ep->driver_data = ss;
 
-       result = source_sink_start_ep(ss, false, EP_BULK, speed);
+       result = source_sink_start_ep(ss, false, false, speed);
        if (result < 0) {
 fail2:
                ep = ss->out_ep;
@@ -1008,7 +726,7 @@ fail2:
                        goto fail2;
                ep->driver_data = ss;
 
-               result = source_sink_start_ep(ss, true, EP_ISOC, speed);
+               result = source_sink_start_ep(ss, true, true, speed);
                if (result < 0) {
 fail3:
                        ep = ss->iso_in_ep;
@@ -1031,14 +749,13 @@ fail3:
                        goto fail3;
                ep->driver_data = ss;
 
-               result = source_sink_start_ep(ss, false, EP_ISOC, speed);
+               result = source_sink_start_ep(ss, false, true, speed);
                if (result < 0) {
                        usb_ep_disable(ep);
                        ep->driver_data = NULL;
                        goto fail3;
                }
        }
-
 out:
        ss->cur_alt = alt;
 
@@ -1054,8 +771,6 @@ static int sourcesink_set_alt(struct usb_function *f,
 
        if (ss->in_ep->driver_data)
                disable_source_sink(ss);
-       else if (alt == 2 && ss->int_in_ep->driver_data)
-               disable_source_sink(ss);
        return enable_source_sink(cdev, ss, alt);
 }
 
@@ -1168,10 +883,6 @@ static struct usb_function *source_sink_alloc_func(
        isoc_maxpacket = ss_opts->isoc_maxpacket;
        isoc_mult = ss_opts->isoc_mult;
        isoc_maxburst = ss_opts->isoc_maxburst;
-       int_interval = ss_opts->int_interval;
-       int_maxpacket = ss_opts->int_maxpacket;
-       int_mult = ss_opts->int_mult;
-       int_maxburst = ss_opts->int_maxburst;
        buflen = ss_opts->bulk_buflen;
 
        ss->function.name = "source/sink";
@@ -1468,182 +1179,6 @@ static struct f_ss_opts_attribute f_ss_opts_bulk_buflen =
                        f_ss_opts_bulk_buflen_show,
                        f_ss_opts_bulk_buflen_store);
 
-static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_interval);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_interval_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u32 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou32(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 4096) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_interval = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_interval =
-       __CONFIGFS_ATTR(int_interval, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_interval_show,
-                       f_ss_opts_int_interval_store);
-
-static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_maxpacket);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_maxpacket_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u16 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou16(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 1024) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_maxpacket = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_maxpacket =
-       __CONFIGFS_ATTR(int_maxpacket, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_maxpacket_show,
-                       f_ss_opts_int_maxpacket_store);
-
-static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_mult);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_mult_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u8 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou8(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 2) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_mult = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_mult =
-       __CONFIGFS_ATTR(int_mult, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_mult_show,
-                       f_ss_opts_int_mult_store);
-
-static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_maxburst);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_maxburst_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u8 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou8(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 15) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_maxburst = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_maxburst =
-       __CONFIGFS_ATTR(int_maxburst, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_maxburst_show,
-                       f_ss_opts_int_maxburst_store);
-
 static struct configfs_attribute *ss_attrs[] = {
        &f_ss_opts_pattern.attr,
        &f_ss_opts_isoc_interval.attr,
@@ -1651,10 +1186,6 @@ static struct configfs_attribute *ss_attrs[] = {
        &f_ss_opts_isoc_mult.attr,
        &f_ss_opts_isoc_maxburst.attr,
        &f_ss_opts_bulk_buflen.attr,
-       &f_ss_opts_int_interval.attr,
-       &f_ss_opts_int_maxpacket.attr,
-       &f_ss_opts_int_mult.attr,
-       &f_ss_opts_int_maxburst.attr,
        NULL,
 };
 
@@ -1684,8 +1215,6 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
        ss_opts->isoc_interval = GZERO_ISOC_INTERVAL;
        ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET;
        ss_opts->bulk_buflen = GZERO_BULK_BUFLEN;
-       ss_opts->int_interval = GZERO_INT_INTERVAL;
-       ss_opts->int_maxpacket = GZERO_INT_MAXPACKET;
 
        config_group_init_type_name(&ss_opts->func_inst.group, "",
                                    &ss_func_type);
index 33e16658e5cfeb50d01c44c7a63a2379634e82b7..6d3eb8b00a488446db954334e80ac12eccf0d5cf 100644 (file)
@@ -54,7 +54,7 @@
 #define UNFLW_CTRL     8
 #define OVFLW_CTRL     10
 
-const char *uac2_name = "snd_uac2";
+static const char *uac2_name = "snd_uac2";
 
 struct uac2_req {
        struct uac2_rtd_params *pp; /* parent param */
@@ -634,7 +634,7 @@ static struct usb_interface_descriptor std_ac_if_desc = {
 };
 
 /* Clock source for IN traffic */
-struct uac_clock_source_descriptor in_clk_src_desc = {
+static struct uac_clock_source_descriptor in_clk_src_desc = {
        .bLength = sizeof in_clk_src_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -646,7 +646,7 @@ struct uac_clock_source_descriptor in_clk_src_desc = {
 };
 
 /* Clock source for OUT traffic */
-struct uac_clock_source_descriptor out_clk_src_desc = {
+static struct uac_clock_source_descriptor out_clk_src_desc = {
        .bLength = sizeof out_clk_src_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -658,7 +658,7 @@ struct uac_clock_source_descriptor out_clk_src_desc = {
 };
 
 /* Input Terminal for USB_OUT */
-struct uac2_input_terminal_descriptor usb_out_it_desc = {
+static struct uac2_input_terminal_descriptor usb_out_it_desc = {
        .bLength = sizeof usb_out_it_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -672,7 +672,7 @@ struct uac2_input_terminal_descriptor usb_out_it_desc = {
 };
 
 /* Input Terminal for I/O-In */
-struct uac2_input_terminal_descriptor io_in_it_desc = {
+static struct uac2_input_terminal_descriptor io_in_it_desc = {
        .bLength = sizeof io_in_it_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -686,7 +686,7 @@ struct uac2_input_terminal_descriptor io_in_it_desc = {
 };
 
 /* Ouput Terminal for USB_IN */
-struct uac2_output_terminal_descriptor usb_in_ot_desc = {
+static struct uac2_output_terminal_descriptor usb_in_ot_desc = {
        .bLength = sizeof usb_in_ot_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -700,7 +700,7 @@ struct uac2_output_terminal_descriptor usb_in_ot_desc = {
 };
 
 /* Ouput Terminal for I/O-Out */
-struct uac2_output_terminal_descriptor io_out_ot_desc = {
+static struct uac2_output_terminal_descriptor io_out_ot_desc = {
        .bLength = sizeof io_out_ot_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -713,7 +713,7 @@ struct uac2_output_terminal_descriptor io_out_ot_desc = {
        .bmControls = (CONTROL_RDWR << COPY_CTRL),
 };
 
-struct uac2_ac_header_descriptor ac_hdr_desc = {
+static struct uac2_ac_header_descriptor ac_hdr_desc = {
        .bLength = sizeof ac_hdr_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -751,7 +751,7 @@ static struct usb_interface_descriptor std_as_out_if1_desc = {
 };
 
 /* Audio Stream OUT Intface Desc */
-struct uac2_as_header_descriptor as_out_hdr_desc = {
+static struct uac2_as_header_descriptor as_out_hdr_desc = {
        .bLength = sizeof as_out_hdr_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -764,7 +764,7 @@ struct uac2_as_header_descriptor as_out_hdr_desc = {
 };
 
 /* Audio USB_OUT Format */
-struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
+static struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
        .bLength = sizeof as_out_fmt1_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubtype = UAC_FORMAT_TYPE,
@@ -772,7 +772,7 @@ struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
 };
 
 /* STD AS ISO OUT Endpoint */
-struct usb_endpoint_descriptor fs_epout_desc = {
+static struct usb_endpoint_descriptor fs_epout_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -782,7 +782,7 @@ struct usb_endpoint_descriptor fs_epout_desc = {
        .bInterval = 1,
 };
 
-struct usb_endpoint_descriptor hs_epout_desc = {
+static struct usb_endpoint_descriptor hs_epout_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -828,7 +828,7 @@ static struct usb_interface_descriptor std_as_in_if1_desc = {
 };
 
 /* Audio Stream IN Intface Desc */
-struct uac2_as_header_descriptor as_in_hdr_desc = {
+static struct uac2_as_header_descriptor as_in_hdr_desc = {
        .bLength = sizeof as_in_hdr_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -841,7 +841,7 @@ struct uac2_as_header_descriptor as_in_hdr_desc = {
 };
 
 /* Audio USB_IN Format */
-struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
+static struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
        .bLength = sizeof as_in_fmt1_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubtype = UAC_FORMAT_TYPE,
@@ -849,7 +849,7 @@ struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
 };
 
 /* STD AS ISO IN Endpoint */
-struct usb_endpoint_descriptor fs_epin_desc = {
+static struct usb_endpoint_descriptor fs_epin_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -859,7 +859,7 @@ struct usb_endpoint_descriptor fs_epin_desc = {
        .bInterval = 1,
 };
 
-struct usb_endpoint_descriptor hs_epin_desc = {
+static struct usb_endpoint_descriptor hs_epin_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -1563,7 +1563,7 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
                agdev->out_ep->driver_data = NULL;
 }
 
-struct usb_function *afunc_alloc(struct usb_function_instance *fi)
+static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
 {
        struct audio_dev *agdev;
        struct f_uac2_opts *opts;
index 2ce28b9d97cc81a519cff3adb6e07fa89aeb9e2a..15f180904f8a3980e2845c38bf327e5174b8df30 100644 (file)
@@ -10,8 +10,6 @@
 #define GZERO_QLEN             32
 #define GZERO_ISOC_INTERVAL    4
 #define GZERO_ISOC_MAXPACKET   1024
-#define GZERO_INT_INTERVAL     1 /* Default interrupt interval = 1 ms */
-#define GZERO_INT_MAXPACKET    1024
 
 struct usb_zero_options {
        unsigned pattern;
@@ -19,10 +17,6 @@ struct usb_zero_options {
        unsigned isoc_maxpacket;
        unsigned isoc_mult;
        unsigned isoc_maxburst;
-       unsigned int_interval; /* In ms */
-       unsigned int_maxpacket;
-       unsigned int_mult;
-       unsigned int_maxburst;
        unsigned bulk_buflen;
        unsigned qlen;
 };
@@ -34,10 +28,6 @@ struct f_ss_opts {
        unsigned isoc_maxpacket;
        unsigned isoc_mult;
        unsigned isoc_maxburst;
-       unsigned int_interval; /* In ms */
-       unsigned int_maxpacket;
-       unsigned int_mult;
-       unsigned int_maxburst;
        unsigned bulk_buflen;
 
        /*
@@ -72,7 +62,6 @@ int lb_modinit(void);
 void free_ep_req(struct usb_ep *ep, struct usb_request *req);
 void disable_endpoints(struct usb_composite_dev *cdev,
                struct usb_ep *in, struct usb_ep *out,
-               struct usb_ep *iso_in, struct usb_ep *iso_out,
-               struct usb_ep *int_in, struct usb_ep *int_out);
+               struct usb_ep *iso_in, struct usb_ep *iso_out);
 
 #endif /* __G_ZERO_H */
index 5aad7fededa589bdb7b143a9f6dfbfb65c81cedd..8b818fd027b3380772030c2a650c67df830a4e56 100644 (file)
@@ -27,6 +27,7 @@
 #include "uvc.h"
 #include "uvc_queue.h"
 #include "uvc_video.h"
+#include "uvc_v4l2.h"
 
 /* --------------------------------------------------------------------------
  * Requests handling
index 9cb86bc1a9a5444b4ed7895489c2b0c5860bac37..50a5e637ca35ad804925112675e54b2ee115b80f 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "uvc.h"
 #include "uvc_queue.h"
+#include "uvc_video.h"
 
 /* --------------------------------------------------------------------------
  * Video codecs
index 06acfa55864a639a6015689770b4ccb06f01ad40..b01b88e1b716a5902d5276196ef459663545a216 100644 (file)
@@ -133,7 +133,9 @@ struct gfs_configuration {
        struct usb_configuration c;
        int (*eth)(struct usb_configuration *c);
        int num;
-} gfs_configurations[] = {
+};
+
+static struct gfs_configuration gfs_configurations[] = {
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
        {
                .eth            = bind_rndis_config,
@@ -278,7 +280,7 @@ static void *functionfs_acquire_dev(struct ffs_dev *dev)
        if (!try_module_get(THIS_MODULE))
                return ERR_PTR(-ENOENT);
        
-       return 0;
+       return NULL;
 }
 
 static void functionfs_release_dev(struct ffs_dev *dev)
index db49ec4c748e9469bd694645c8cfc22df7c829fa..200f9a584064fd9199ba99ff75a2e26a33c788f7 100644 (file)
@@ -74,6 +74,8 @@ MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_AUTHOR ("David Brownell");
 MODULE_LICENSE ("GPL");
 
+static int ep_open(struct inode *, struct file *);
+
 
 /*----------------------------------------------------------------------*/
 
@@ -283,14 +285,15 @@ static void epio_complete (struct usb_ep *ep, struct usb_request *req)
  * still need dev->lock to use epdata->ep.
  */
 static int
-get_ready_ep (unsigned f_flags, struct ep_data *epdata)
+get_ready_ep (unsigned f_flags, struct ep_data *epdata, bool is_write)
 {
        int     val;
 
        if (f_flags & O_NONBLOCK) {
                if (!mutex_trylock(&epdata->lock))
                        goto nonblock;
-               if (epdata->state != STATE_EP_ENABLED) {
+               if (epdata->state != STATE_EP_ENABLED &&
+                   (!is_write || epdata->state != STATE_EP_READY)) {
                        mutex_unlock(&epdata->lock);
 nonblock:
                        val = -EAGAIN;
@@ -305,18 +308,20 @@ nonblock:
 
        switch (epdata->state) {
        case STATE_EP_ENABLED:
+               return 0;
+       case STATE_EP_READY:                    /* not configured yet */
+               if (is_write)
+                       return 0;
+               // FALLTHRU
+       case STATE_EP_UNBOUND:                  /* clean disconnect */
                break;
        // case STATE_EP_DISABLED:              /* "can't happen" */
-       // case STATE_EP_READY:                 /* "can't happen" */
        default:                                /* error! */
                pr_debug ("%s: ep %p not available, state %d\n",
                                shortname, epdata, epdata->state);
-               // FALLTHROUGH
-       case STATE_EP_UNBOUND:                  /* clean disconnect */
-               val = -ENODEV;
-               mutex_unlock(&epdata->lock);
        }
-       return val;
+       mutex_unlock(&epdata->lock);
+       return -ENODEV;
 }
 
 static ssize_t
@@ -363,97 +368,6 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len)
        return value;
 }
 
-
-/* handle a synchronous OUT bulk/intr/iso transfer */
-static ssize_t
-ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ep_data          *data = fd->private_data;
-       void                    *kbuf;
-       ssize_t                 value;
-
-       if ((value = get_ready_ep (fd->f_flags, data)) < 0)
-               return value;
-
-       /* halt any endpoint by doing a "wrong direction" i/o call */
-       if (usb_endpoint_dir_in(&data->desc)) {
-               if (usb_endpoint_xfer_isoc(&data->desc)) {
-                       mutex_unlock(&data->lock);
-                       return -EINVAL;
-               }
-               DBG (data->dev, "%s halt\n", data->name);
-               spin_lock_irq (&data->dev->lock);
-               if (likely (data->ep != NULL))
-                       usb_ep_set_halt (data->ep);
-               spin_unlock_irq (&data->dev->lock);
-               mutex_unlock(&data->lock);
-               return -EBADMSG;
-       }
-
-       /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */
-
-       value = -ENOMEM;
-       kbuf = kmalloc (len, GFP_KERNEL);
-       if (unlikely (!kbuf))
-               goto free1;
-
-       value = ep_io (data, kbuf, len);
-       VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
-               data->name, len, (int) value);
-       if (value >= 0 && copy_to_user (buf, kbuf, value))
-               value = -EFAULT;
-
-free1:
-       mutex_unlock(&data->lock);
-       kfree (kbuf);
-       return value;
-}
-
-/* handle a synchronous IN bulk/intr/iso transfer */
-static ssize_t
-ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ep_data          *data = fd->private_data;
-       void                    *kbuf;
-       ssize_t                 value;
-
-       if ((value = get_ready_ep (fd->f_flags, data)) < 0)
-               return value;
-
-       /* halt any endpoint by doing a "wrong direction" i/o call */
-       if (!usb_endpoint_dir_in(&data->desc)) {
-               if (usb_endpoint_xfer_isoc(&data->desc)) {
-                       mutex_unlock(&data->lock);
-                       return -EINVAL;
-               }
-               DBG (data->dev, "%s halt\n", data->name);
-               spin_lock_irq (&data->dev->lock);
-               if (likely (data->ep != NULL))
-                       usb_ep_set_halt (data->ep);
-               spin_unlock_irq (&data->dev->lock);
-               mutex_unlock(&data->lock);
-               return -EBADMSG;
-       }
-
-       /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */
-
-       value = -ENOMEM;
-       kbuf = memdup_user(buf, len);
-       if (IS_ERR(kbuf)) {
-               value = PTR_ERR(kbuf);
-               kbuf = NULL;
-               goto free1;
-       }
-
-       value = ep_io (data, kbuf, len);
-       VDEBUG (data->dev, "%s write %zu IN, status %d\n",
-               data->name, len, (int) value);
-free1:
-       mutex_unlock(&data->lock);
-       kfree (kbuf);
-       return value;
-}
-
 static int
 ep_release (struct inode *inode, struct file *fd)
 {
@@ -481,7 +395,7 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
        struct ep_data          *data = fd->private_data;
        int                     status;
 
-       if ((status = get_ready_ep (fd->f_flags, data)) < 0)
+       if ((status = get_ready_ep (fd->f_flags, data, false)) < 0)
                return status;
 
        spin_lock_irq (&data->dev->lock);
@@ -517,8 +431,8 @@ struct kiocb_priv {
        struct mm_struct        *mm;
        struct work_struct      work;
        void                    *buf;
-       const struct iovec      *iv;
-       unsigned long           nr_segs;
+       struct iov_iter         to;
+       const void              *to_free;
        unsigned                actual;
 };
 
@@ -541,35 +455,6 @@ static int ep_aio_cancel(struct kiocb *iocb)
        return value;
 }
 
-static ssize_t ep_copy_to_user(struct kiocb_priv *priv)
-{
-       ssize_t                 len, total;
-       void                    *to_copy;
-       int                     i;
-
-       /* copy stuff into user buffers */
-       total = priv->actual;
-       len = 0;
-       to_copy = priv->buf;
-       for (i=0; i < priv->nr_segs; i++) {
-               ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
-
-               if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) {
-                       if (len == 0)
-                               len = -EFAULT;
-                       break;
-               }
-
-               total -= this;
-               len += this;
-               to_copy += this;
-               if (total == 0)
-                       break;
-       }
-
-       return len;
-}
-
 static void ep_user_copy_worker(struct work_struct *work)
 {
        struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work);
@@ -578,13 +463,16 @@ static void ep_user_copy_worker(struct work_struct *work)
        size_t ret;
 
        use_mm(mm);
-       ret = ep_copy_to_user(priv);
+       ret = copy_to_iter(priv->buf, priv->actual, &priv->to);
        unuse_mm(mm);
+       if (!ret)
+               ret = -EFAULT;
 
        /* completing the iocb can drop the ctx and mm, don't touch mm after */
        aio_complete(iocb, ret, ret);
 
        kfree(priv->buf);
+       kfree(priv->to_free);
        kfree(priv);
 }
 
@@ -603,8 +491,9 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
         * don't need to copy anything to userspace, so we can
         * complete the aio request immediately.
         */
-       if (priv->iv == NULL || unlikely(req->actual == 0)) {
+       if (priv->to_free == NULL || unlikely(req->actual == 0)) {
                kfree(req->buf);
+               kfree(priv->to_free);
                kfree(priv);
                iocb->private = NULL;
                /* aio_complete() reports bytes-transferred _and_ faults */
@@ -618,6 +507,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
 
                priv->buf = req->buf;
                priv->actual = req->actual;
+               INIT_WORK(&priv->work, ep_user_copy_worker);
                schedule_work(&priv->work);
        }
        spin_unlock(&epdata->dev->lock);
@@ -626,38 +516,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
        put_ep(epdata);
 }
 
-static ssize_t
-ep_aio_rwtail(
-       struct kiocb    *iocb,
-       char            *buf,
-       size_t          len,
-       struct ep_data  *epdata,
-       const struct iovec *iv,
-       unsigned long   nr_segs
-)
+static ssize_t ep_aio(struct kiocb *iocb,
+                     struct kiocb_priv *priv,
+                     struct ep_data *epdata,
+                     char *buf,
+                     size_t len)
 {
-       struct kiocb_priv       *priv;
-       struct usb_request      *req;
-       ssize_t                 value;
+       struct usb_request *req;
+       ssize_t value;
 
-       priv = kmalloc(sizeof *priv, GFP_KERNEL);
-       if (!priv) {
-               value = -ENOMEM;
-fail:
-               kfree(buf);
-               return value;
-       }
        iocb->private = priv;
        priv->iocb = iocb;
-       priv->iv = iv;
-       priv->nr_segs = nr_segs;
-       INIT_WORK(&priv->work, ep_user_copy_worker);
-
-       value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
-       if (unlikely(value < 0)) {
-               kfree(priv);
-               goto fail;
-       }
 
        kiocb_set_cancel_fn(iocb, ep_aio_cancel);
        get_ep(epdata);
@@ -669,75 +538,154 @@ fail:
         * allocate or submit those if the host disconnected.
         */
        spin_lock_irq(&epdata->dev->lock);
-       if (likely(epdata->ep)) {
-               req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
-               if (likely(req)) {
-                       priv->req = req;
-                       req->buf = buf;
-                       req->length = len;
-                       req->complete = ep_aio_complete;
-                       req->context = iocb;
-                       value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC);
-                       if (unlikely(0 != value))
-                               usb_ep_free_request(epdata->ep, req);
-               } else
-                       value = -EAGAIN;
-       } else
-               value = -ENODEV;
-       spin_unlock_irq(&epdata->dev->lock);
+       value = -ENODEV;
+       if (unlikely(epdata->ep))
+               goto fail;
 
-       mutex_unlock(&epdata->lock);
+       req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
+       value = -ENOMEM;
+       if (unlikely(!req))
+               goto fail;
 
-       if (unlikely(value)) {
-               kfree(priv);
-               put_ep(epdata);
-       } else
-               value = -EIOCBQUEUED;
+       priv->req = req;
+       req->buf = buf;
+       req->length = len;
+       req->complete = ep_aio_complete;
+       req->context = iocb;
+       value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC);
+       if (unlikely(0 != value)) {
+               usb_ep_free_request(epdata->ep, req);
+               goto fail;
+       }
+       spin_unlock_irq(&epdata->dev->lock);
+       return -EIOCBQUEUED;
+
+fail:
+       spin_unlock_irq(&epdata->dev->lock);
+       kfree(priv->to_free);
+       kfree(priv);
+       put_ep(epdata);
        return value;
 }
 
 static ssize_t
-ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t o)
+ep_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
-       struct ep_data          *epdata = iocb->ki_filp->private_data;
-       char                    *buf;
+       struct file *file = iocb->ki_filp;
+       struct ep_data *epdata = file->private_data;
+       size_t len = iov_iter_count(to);
+       ssize_t value;
+       char *buf;
 
-       if (unlikely(usb_endpoint_dir_in(&epdata->desc)))
-               return -EINVAL;
+       if ((value = get_ready_ep(file->f_flags, epdata, false)) < 0)
+               return value;
 
-       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
-       if (unlikely(!buf))
-               return -ENOMEM;
+       /* halt any endpoint by doing a "wrong direction" i/o call */
+       if (usb_endpoint_dir_in(&epdata->desc)) {
+               if (usb_endpoint_xfer_isoc(&epdata->desc) ||
+                   !is_sync_kiocb(iocb)) {
+                       mutex_unlock(&epdata->lock);
+                       return -EINVAL;
+               }
+               DBG (epdata->dev, "%s halt\n", epdata->name);
+               spin_lock_irq(&epdata->dev->lock);
+               if (likely(epdata->ep != NULL))
+                       usb_ep_set_halt(epdata->ep);
+               spin_unlock_irq(&epdata->dev->lock);
+               mutex_unlock(&epdata->lock);
+               return -EBADMSG;
+       }
 
-       return ep_aio_rwtail(iocb, buf, iocb->ki_nbytes, epdata, iov, nr_segs);
+       buf = kmalloc(len, GFP_KERNEL);
+       if (unlikely(!buf)) {
+               mutex_unlock(&epdata->lock);
+               return -ENOMEM;
+       }
+       if (is_sync_kiocb(iocb)) {
+               value = ep_io(epdata, buf, len);
+               if (value >= 0 && copy_to_iter(buf, value, to))
+                       value = -EFAULT;
+       } else {
+               struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL);
+               value = -ENOMEM;
+               if (!priv)
+                       goto fail;
+               priv->to_free = dup_iter(&priv->to, to, GFP_KERNEL);
+               if (!priv->to_free) {
+                       kfree(priv);
+                       goto fail;
+               }
+               value = ep_aio(iocb, priv, epdata, buf, len);
+               if (value == -EIOCBQUEUED)
+                       buf = NULL;
+       }
+fail:
+       kfree(buf);
+       mutex_unlock(&epdata->lock);
+       return value;
 }
 
+static ssize_t ep_config(struct ep_data *, const char *, size_t);
+
 static ssize_t
-ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t o)
+ep_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
-       struct ep_data          *epdata = iocb->ki_filp->private_data;
-       char                    *buf;
-       size_t                  len = 0;
-       int                     i = 0;
+       struct file *file = iocb->ki_filp;
+       struct ep_data *epdata = file->private_data;
+       size_t len = iov_iter_count(from);
+       bool configured;
+       ssize_t value;
+       char *buf;
+
+       if ((value = get_ready_ep(file->f_flags, epdata, true)) < 0)
+               return value;
 
-       if (unlikely(!usb_endpoint_dir_in(&epdata->desc)))
-               return -EINVAL;
+       configured = epdata->state == STATE_EP_ENABLED;
 
-       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
-       if (unlikely(!buf))
+       /* halt any endpoint by doing a "wrong direction" i/o call */
+       if (configured && !usb_endpoint_dir_in(&epdata->desc)) {
+               if (usb_endpoint_xfer_isoc(&epdata->desc) ||
+                   !is_sync_kiocb(iocb)) {
+                       mutex_unlock(&epdata->lock);
+                       return -EINVAL;
+               }
+               DBG (epdata->dev, "%s halt\n", epdata->name);
+               spin_lock_irq(&epdata->dev->lock);
+               if (likely(epdata->ep != NULL))
+                       usb_ep_set_halt(epdata->ep);
+               spin_unlock_irq(&epdata->dev->lock);
+               mutex_unlock(&epdata->lock);
+               return -EBADMSG;
+       }
+
+       buf = kmalloc(len, GFP_KERNEL);
+       if (unlikely(!buf)) {
+               mutex_unlock(&epdata->lock);
                return -ENOMEM;
+       }
 
-       for (i=0; i < nr_segs; i++) {
-               if (unlikely(copy_from_user(&buf[len], iov[i].iov_base,
-                               iov[i].iov_len) != 0)) {
-                       kfree(buf);
-                       return -EFAULT;
+       if (unlikely(copy_from_iter(buf, len, from) != len)) {
+               value = -EFAULT;
+               goto out;
+       }
+
+       if (unlikely(!configured)) {
+               value = ep_config(epdata, buf, len);
+       } else if (is_sync_kiocb(iocb)) {
+               value = ep_io(epdata, buf, len);
+       } else {
+               struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL);
+               value = -ENOMEM;
+               if (priv) {
+                       value = ep_aio(iocb, priv, epdata, buf, len);
+                       if (value == -EIOCBQUEUED)
+                               buf = NULL;
                }
-               len += iov[i].iov_len;
        }
-       return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
+out:
+       kfree(buf);
+       mutex_unlock(&epdata->lock);
+       return value;
 }
 
 /*----------------------------------------------------------------------*/
@@ -745,15 +693,15 @@ ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
 /* used after endpoint configuration */
 static const struct file_operations ep_io_operations = {
        .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
 
-       .read =         ep_read,
-       .write =        ep_write,
-       .unlocked_ioctl = ep_ioctl,
+       .open =         ep_open,
        .release =      ep_release,
-
-       .aio_read =     ep_aio_read,
-       .aio_write =    ep_aio_write,
+       .llseek =       no_llseek,
+       .read =         new_sync_read,
+       .write =        new_sync_write,
+       .unlocked_ioctl = ep_ioctl,
+       .read_iter =    ep_read_iter,
+       .write_iter =   ep_write_iter,
 };
 
 /* ENDPOINT INITIALIZATION
@@ -770,17 +718,12 @@ static const struct file_operations ep_io_operations = {
  * speed descriptor, then optional high speed descriptor.
  */
 static ssize_t
-ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
+ep_config (struct ep_data *data, const char *buf, size_t len)
 {
-       struct ep_data          *data = fd->private_data;
        struct usb_ep           *ep;
        u32                     tag;
        int                     value, length = len;
 
-       value = mutex_lock_interruptible(&data->lock);
-       if (value < 0)
-               return value;
-
        if (data->state != STATE_EP_READY) {
                value = -EL2HLT;
                goto fail;
@@ -791,9 +734,7 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                goto fail0;
 
        /* we might need to change message format someday */
-       if (copy_from_user (&tag, buf, 4)) {
-               goto fail1;
-       }
+       memcpy(&tag, buf, 4);
        if (tag != 1) {
                DBG(data->dev, "config %s, bad tag %d\n", data->name, tag);
                goto fail0;
@@ -806,19 +747,15 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
         */
 
        /* full/low speed descriptor, then high speed */
-       if (copy_from_user (&data->desc, buf, USB_DT_ENDPOINT_SIZE)) {
-               goto fail1;
-       }
+       memcpy(&data->desc, buf, USB_DT_ENDPOINT_SIZE);
        if (data->desc.bLength != USB_DT_ENDPOINT_SIZE
                        || data->desc.bDescriptorType != USB_DT_ENDPOINT)
                goto fail0;
        if (len != USB_DT_ENDPOINT_SIZE) {
                if (len != 2 * USB_DT_ENDPOINT_SIZE)
                        goto fail0;
-               if (copy_from_user (&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE,
-                                       USB_DT_ENDPOINT_SIZE)) {
-                       goto fail1;
-               }
+               memcpy(&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE,
+                       USB_DT_ENDPOINT_SIZE);
                if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE
                                || data->hs_desc.bDescriptorType
                                        != USB_DT_ENDPOINT) {
@@ -840,24 +777,20 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        case USB_SPEED_LOW:
        case USB_SPEED_FULL:
                ep->desc = &data->desc;
-               value = usb_ep_enable(ep);
-               if (value == 0)
-                       data->state = STATE_EP_ENABLED;
                break;
        case USB_SPEED_HIGH:
                /* fails if caller didn't provide that descriptor... */
                ep->desc = &data->hs_desc;
-               value = usb_ep_enable(ep);
-               if (value == 0)
-                       data->state = STATE_EP_ENABLED;
                break;
        default:
                DBG(data->dev, "unconnected, %s init abandoned\n",
                                data->name);
                value = -EINVAL;
+               goto gone;
        }
+       value = usb_ep_enable(ep);
        if (value == 0) {
-               fd->f_op = &ep_io_operations;
+               data->state = STATE_EP_ENABLED;
                value = length;
        }
 gone:
@@ -867,14 +800,10 @@ fail:
                data->desc.bDescriptorType = 0;
                data->hs_desc.bDescriptorType = 0;
        }
-       mutex_unlock(&data->lock);
        return value;
 fail0:
        value = -EINVAL;
        goto fail;
-fail1:
-       value = -EFAULT;
-       goto fail;
 }
 
 static int
@@ -902,15 +831,6 @@ ep_open (struct inode *inode, struct file *fd)
        return value;
 }
 
-/* used before endpoint configuration */
-static const struct file_operations ep_config_operations = {
-       .llseek =       no_llseek,
-
-       .open =         ep_open,
-       .write =        ep_config,
-       .release =      ep_release,
-};
-
 /*----------------------------------------------------------------------*/
 
 /* EP0 IMPLEMENTATION can be partly in userspace.
@@ -989,6 +909,10 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
        enum ep0_state                  state;
 
        spin_lock_irq (&dev->lock);
+       if (dev->state <= STATE_DEV_OPENED) {
+               retval = -EINVAL;
+               goto done;
+       }
 
        /* report fd mode change before acting on it */
        if (dev->setup_abort) {
@@ -1187,8 +1111,6 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        struct dev_data         *dev = fd->private_data;
        ssize_t                 retval = -ESRCH;
 
-       spin_lock_irq (&dev->lock);
-
        /* report fd mode change before acting on it */
        if (dev->setup_abort) {
                dev->setup_abort = 0;
@@ -1234,7 +1156,6 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        } else
                DBG (dev, "fail %s, state %d\n", __func__, dev->state);
 
-       spin_unlock_irq (&dev->lock);
        return retval;
 }
 
@@ -1281,6 +1202,9 @@ ep0_poll (struct file *fd, poll_table *wait)
        struct dev_data         *dev = fd->private_data;
        int                     mask = 0;
 
+       if (dev->state <= STATE_DEV_OPENED)
+               return DEFAULT_POLLMASK;
+
        poll_wait(fd, &dev->wait, wait);
 
        spin_lock_irq (&dev->lock);
@@ -1316,19 +1240,6 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
        return ret;
 }
 
-/* used after device configuration */
-static const struct file_operations ep0_io_operations = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-
-       .read =         ep0_read,
-       .write =        ep0_write,
-       .fasync =       ep0_fasync,
-       .poll =         ep0_poll,
-       .unlocked_ioctl =       dev_ioctl,
-       .release =      dev_release,
-};
-
 /*----------------------------------------------------------------------*/
 
 /* The in-kernel gadget driver handles most ep0 issues, in particular
@@ -1650,7 +1561,7 @@ static int activate_ep_files (struct dev_data *dev)
                        goto enomem1;
 
                data->dentry = gadgetfs_create_file (dev->sb, data->name,
-                               data, &ep_config_operations);
+                               data, &ep_io_operations);
                if (!data->dentry)
                        goto enomem2;
                list_add_tail (&data->epfiles, &dev->epfiles);
@@ -1852,6 +1763,14 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        u32                     tag;
        char                    *kbuf;
 
+       spin_lock_irq(&dev->lock);
+       if (dev->state > STATE_DEV_OPENED) {
+               value = ep0_write(fd, buf, len, ptr);
+               spin_unlock_irq(&dev->lock);
+               return value;
+       }
+       spin_unlock_irq(&dev->lock);
+
        if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
                return -EINVAL;
 
@@ -1925,7 +1844,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                 * on, they can work ... except in cleanup paths that
                 * kick in after the ep0 descriptor is closed.
                 */
-               fd->f_op = &ep0_io_operations;
                value = len;
        }
        return value;
@@ -1956,12 +1874,14 @@ dev_open (struct inode *inode, struct file *fd)
        return value;
 }
 
-static const struct file_operations dev_init_operations = {
+static const struct file_operations ep0_operations = {
        .llseek =       no_llseek,
 
        .open =         dev_open,
+       .read =         ep0_read,
        .write =        dev_config,
        .fasync =       ep0_fasync,
+       .poll =         ep0_poll,
        .unlocked_ioctl = dev_ioctl,
        .release =      dev_release,
 };
@@ -2077,7 +1997,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
                goto Enomem;
 
        dev->sb = sb;
-       dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &dev_init_operations);
+       dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations);
        if (!dev->dentry) {
                put_dev(dev);
                goto Enomem;
index 3a494168661e40c9f20e812bc1473620711aebb5..6e0a019aad54ae7a209f03355ae50d7c1e0cdb29 100644 (file)
@@ -1740,10 +1740,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
                goto err_session;
        }
        /*
-        * Now register the TCM vHost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
+        * Now register the TCM vHost virtual I_T Nexus as active.
         */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
        mutex_unlock(&tpg->tpg_mutex);
index ff97ac93ac03d0add447f3e3ed49301403386b53..5ee95152493c2b6b0be74257cc437bdb560f250b 100644 (file)
@@ -68,8 +68,6 @@ static struct usb_zero_options gzero_options = {
        .isoc_maxpacket = GZERO_ISOC_MAXPACKET,
        .bulk_buflen = GZERO_BULK_BUFLEN,
        .qlen = GZERO_QLEN,
-       .int_interval = GZERO_INT_INTERVAL,
-       .int_maxpacket = GZERO_INT_MAXPACKET,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -268,21 +266,6 @@ module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint,
                S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
 
-module_param_named(int_interval, gzero_options.int_interval, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_interval, "1 - 16");
-
-module_param_named(int_maxpacket, gzero_options.int_maxpacket, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
-
-module_param_named(int_mult, gzero_options.int_mult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_mult, "0 - 2 (hs/ss only)");
-
-module_param_named(int_maxburst, gzero_options.int_maxburst, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_maxburst, "0 - 15 (ss only)");
-
 static struct usb_function *func_lb;
 static struct usb_function_instance *func_inst_lb;
 
@@ -318,10 +301,6 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
        ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;
        ss_opts->isoc_mult = gzero_options.isoc_mult;
        ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
-       ss_opts->int_interval = gzero_options.int_interval;
-       ss_opts->int_maxpacket = gzero_options.int_maxpacket;
-       ss_opts->int_mult = gzero_options.int_mult;
-       ss_opts->int_maxburst = gzero_options.int_maxburst;
        ss_opts->bulk_buflen = gzero_options.bulk_buflen;
 
        func_ss = usb_get_function(func_inst_ss);
index 663f7908b15c482c9f57bc921d3c976acb04bc53..be0964a801e819fd5dbf88bcee3c1f12f14fd039 100644 (file)
@@ -34,7 +34,6 @@ static const char hcd_name[] = "ehci-atmel";
 
 struct atmel_ehci_priv {
        struct clk *iclk;
-       struct clk *fclk;
        struct clk *uclk;
        bool clocked;
 };
@@ -51,12 +50,9 @@ static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 {
        if (atmel_ehci->clocked)
                return;
-       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-               clk_set_rate(atmel_ehci->uclk, 48000000);
-               clk_prepare_enable(atmel_ehci->uclk);
-       }
+
+       clk_prepare_enable(atmel_ehci->uclk);
        clk_prepare_enable(atmel_ehci->iclk);
-       clk_prepare_enable(atmel_ehci->fclk);
        atmel_ehci->clocked = true;
 }
 
@@ -64,10 +60,9 @@ static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 {
        if (!atmel_ehci->clocked)
                return;
-       clk_disable_unprepare(atmel_ehci->fclk);
+
        clk_disable_unprepare(atmel_ehci->iclk);
-       if (IS_ENABLED(CONFIG_COMMON_CLK))
-               clk_disable_unprepare(atmel_ehci->uclk);
+       clk_disable_unprepare(atmel_ehci->uclk);
        atmel_ehci->clocked = false;
 }
 
@@ -146,20 +141,13 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
                retval = -ENOENT;
                goto fail_request_resource;
        }
-       atmel_ehci->fclk = devm_clk_get(&pdev->dev, "uhpck");
-       if (IS_ERR(atmel_ehci->fclk)) {
-               dev_err(&pdev->dev, "Error getting function clock\n");
-               retval = -ENOENT;
+
+       atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
+       if (IS_ERR(atmel_ehci->uclk)) {
+               dev_err(&pdev->dev, "failed to get uclk\n");
+               retval = PTR_ERR(atmel_ehci->uclk);
                goto fail_request_resource;
        }
-       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-               atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
-               if (IS_ERR(atmel_ehci->uclk)) {
-                       dev_err(&pdev->dev, "failed to get uclk\n");
-                       retval = PTR_ERR(atmel_ehci->uclk);
-                       goto fail_request_resource;
-               }
-       }
 
        ehci = hcd_to_ehci(hcd);
        /* registers start at offset 0x0 */
index 7f76c8a12f89db425e19c4f3a2a5200de542dbd7..fd53c9ebd662a5fb4593c99ce5dd7c2552ad83c5 100644 (file)
@@ -37,6 +37,9 @@
 
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI     0x8c31
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI  0x9c31
+#define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI            0x22b5
+#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI                0xa12f
+#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI       0x9d2f
 
 static const char hcd_name[] = "xhci_hcd";
 
@@ -133,6 +136,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) {
                xhci->quirks |= XHCI_SPURIOUS_REBOOT;
        }
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+               (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
+                pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
+                pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) {
+               xhci->quirks |= XHCI_PME_STUCK_QUIRK;
+       }
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
                        pdev->device == PCI_DEVICE_ID_EJ168) {
                xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -159,6 +168,21 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                                "QUIRK: Resetting on resume");
 }
 
+/*
+ * 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)
+{
+       u32 val;
+       void __iomem *reg;
+
+       reg = (void __iomem *) xhci->cap_regs + 0x80a4;
+       val = readl(reg);
+       writel(val | BIT(28), reg);
+       readl(reg);
+}
+
 /* called during probe() after chip reset completes */
 static int xhci_pci_setup(struct usb_hcd *hcd)
 {
@@ -283,6 +307,9 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
        if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
                pdev->no_d3cold = true;
 
+       if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
+               xhci_pme_quirk(xhci);
+
        return xhci_suspend(xhci, do_wakeup);
 }
 
@@ -313,6 +340,9 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
        if (pdev->vendor == PCI_VENDOR_ID_INTEL)
                usb_enable_intel_xhci_ports(pdev);
 
+       if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
+               xhci_pme_quirk(xhci);
+
        retval = xhci_resume(xhci, hibernated);
        return retval;
 }
index 08d402b15482d936ca36d6d20cc381d8279a35a2..0e11d61408ff3f95a3110636e858119f4037cf0c 100644 (file)
@@ -83,16 +83,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
        if (irq < 0)
                return -ENODEV;
 
-
-       if (of_device_is_compatible(pdev->dev.of_node,
-                                   "marvell,armada-375-xhci") ||
-           of_device_is_compatible(pdev->dev.of_node,
-                                   "marvell,armada-380-xhci")) {
-               ret = xhci_mvebu_mbus_init_quirk(pdev);
-               if (ret)
-                       return ret;
-       }
-
        /* Initialize dma_mask and coherent_dma_mask to 32-bits */
        ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
        if (ret)
@@ -127,6 +117,15 @@ static int xhci_plat_probe(struct platform_device *pdev)
                        goto put_hcd;
        }
 
+       if (of_device_is_compatible(pdev->dev.of_node,
+                                   "marvell,armada-375-xhci") ||
+           of_device_is_compatible(pdev->dev.of_node,
+                                   "marvell,armada-380-xhci")) {
+               ret = xhci_mvebu_mbus_init_quirk(pdev);
+               if (ret)
+                       goto disable_clk;
+       }
+
        ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (ret)
                goto disable_clk;
index 88da8d6298201fa5c7b7e4a93ff67fe303cb84b5..73485fa4372ff7d89298d4d8968fd28d5ec43265 100644 (file)
@@ -1946,7 +1946,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
        if (event_trb != ep_ring->dequeue) {
                /* The event was for the status stage */
                if (event_trb == td->last_trb) {
-                       if (td->urb->actual_length != 0) {
+                       if (td->urb_length_set) {
                                /* Don't overwrite a previously set error code
                                 */
                                if ((*status == -EINPROGRESS || *status == 0) &&
@@ -1960,7 +1960,13 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                                        td->urb->transfer_buffer_length;
                        }
                } else {
-               /* Maybe the event was for the data stage? */
+                       /*
+                        * Maybe the event was for the data stage? If so, update
+                        * already the actual_length of the URB and flag it as
+                        * set, so that it is not overwritten in the event for
+                        * the last TRB.
+                        */
+                       td->urb_length_set = true;
                        td->urb->actual_length =
                                td->urb->transfer_buffer_length -
                                EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
index 974514762a1402aee4164cf5556c9321bea49d44..8e421b89632ddaa4eaf30ee34ef60f89b7ac3e2d 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * xHCI host controller driver
  *
@@ -88,9 +89,10 @@ struct xhci_cap_regs {
 #define HCS_IST(p)             (((p) >> 0) & 0xf)
 /* bits 4:7, max number of Event Ring segments */
 #define HCS_ERST_MAX(p)                (((p) >> 4) & 0xf)
+/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */
 /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
-/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */
-#define HCS_MAX_SCRATCHPAD(p)   (((p) >> 27) & 0x1f)
+/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */
+#define HCS_MAX_SCRATCHPAD(p)   ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f))
 
 /* HCSPARAMS3 - hcs_params3 - bitmasks */
 /* bits 0:7, Max U1 to U0 latency for the roothub ports */
@@ -1288,6 +1290,8 @@ struct xhci_td {
        struct xhci_segment     *start_seg;
        union xhci_trb          *first_trb;
        union xhci_trb          *last_trb;
+       /* actual_length of the URB has already been set */
+       bool                    urb_length_set;
 };
 
 /* xHCI command default timeout value */
@@ -1560,6 +1564,7 @@ struct xhci_hcd {
 #define XHCI_SPURIOUS_WAKEUP   (1 << 18)
 /* For controllers with a broken beyond repair streams implementation */
 #define XHCI_BROKEN_STREAMS    (1 << 19)
+#define XHCI_PME_STUCK_QUIRK   (1 << 20)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
index b9827556455f74dad64adbb4e785f14330f3371a..bfa402cf3a2745492ea5d4fe4cb0f84fc9500ca4 100644 (file)
@@ -151,8 +151,7 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
        }
 
        if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
-               ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED |
-                                          IRQF_DISABLED);
+               ret = isp1760_udc_register(isp, irq, irqflags);
                if (ret < 0) {
                        isp1760_hcd_unregister(&isp->hcd);
                        return ret;
index eba9b82e2d70c19c5b75dc1b6c3d6a0182ee4d5e..3cb98b1d5d2960171bea26d4fff70e2217d9e7f0 100644 (file)
@@ -1274,7 +1274,7 @@ static void errata2_function(unsigned long data)
        for (slot = 0; slot < 32; slot++)
                if (priv->atl_slots[slot].qh && time_after(jiffies,
                                        priv->atl_slots[slot].timestamp +
-                                       SLOT_TIMEOUT * HZ / 1000)) {
+                                       msecs_to_jiffies(SLOT_TIMEOUT))) {
                        ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
                        if (!FROM_DW0_VALID(ptd.dw0) &&
                                        !FROM_DW3_ACTIVE(ptd.dw3))
@@ -1286,7 +1286,7 @@ static void errata2_function(unsigned long data)
 
        spin_unlock_irqrestore(&priv->lock, spinflags);
 
-       errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+       errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
        add_timer(&errata2_timer);
 }
 
@@ -1336,7 +1336,7 @@ static int isp1760_run(struct usb_hcd *hcd)
                return retval;
 
        setup_timer(&errata2_timer, errata2_function, (unsigned long)hcd);
-       errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+       errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
        add_timer(&errata2_timer);
 
        chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
index 9612d7990565c81a75a5310742c793e85e9b8057..f32c292cc8689d81bfce947f7c587603e95c09be 100644 (file)
@@ -1191,6 +1191,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
                             struct usb_gadget_driver *driver)
 {
        struct isp1760_udc *udc = gadget_to_udc(gadget);
+       unsigned long flags;
 
        /* The hardware doesn't support low speed. */
        if (driver->max_speed < USB_SPEED_FULL) {
@@ -1198,7 +1199,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
                return -EINVAL;
        }
 
-       spin_lock(&udc->lock);
+       spin_lock_irqsave(&udc->lock, flags);
 
        if (udc->driver) {
                dev_err(udc->isp->dev, "UDC already has a gadget driver\n");
@@ -1208,7 +1209,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
 
        udc->driver = driver;
 
-       spin_unlock(&udc->lock);
+       spin_unlock_irqrestore(&udc->lock, flags);
 
        dev_dbg(udc->isp->dev, "starting UDC with driver %s\n",
                driver->function);
@@ -1232,6 +1233,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
 static int isp1760_udc_stop(struct usb_gadget *gadget)
 {
        struct isp1760_udc *udc = gadget_to_udc(gadget);
+       unsigned long flags;
 
        dev_dbg(udc->isp->dev, "%s\n", __func__);
 
@@ -1239,9 +1241,9 @@ static int isp1760_udc_stop(struct usb_gadget *gadget)
 
        isp1760_udc_write(udc, DC_MODE, 0);
 
-       spin_lock(&udc->lock);
+       spin_lock_irqsave(&udc->lock, flags);
        udc->driver = NULL;
-       spin_unlock(&udc->lock);
+       spin_unlock_irqrestore(&udc->lock, flags);
 
        return 0;
 }
@@ -1411,7 +1413,7 @@ static int isp1760_udc_init(struct isp1760_udc *udc)
                return -ENODEV;
        }
 
-       if (chipid != 0x00011582) {
+       if (chipid != 0x00011582 && chipid != 0x00158210) {
                dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid);
                return -ENODEV;
        }
@@ -1451,8 +1453,8 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq,
 
        sprintf(udc->irqname, "%s (udc)", devname);
 
-       ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | IRQF_DISABLED |
-                         irqflags, udc->irqname, udc);
+       ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | irqflags,
+                         udc->irqname, udc);
        if (ret < 0)
                goto error;
 
index 14e1628483d9427a68b83f09e18bee8c735e4364..39db8b603627cae44b86bcbd2d9d028027cbe651 100644 (file)
@@ -79,7 +79,8 @@ config USB_MUSB_TUSB6010
 
 config USB_MUSB_OMAP2PLUS
        tristate "OMAP2430 and onwards"
-       depends on ARCH_OMAP2PLUS && USB && OMAP_CONTROL_PHY
+       depends on ARCH_OMAP2PLUS && USB
+       depends on OMAP_CONTROL_PHY || !OMAP_CONTROL_PHY
        select GENERIC_PHY
 
 config USB_MUSB_AM35X
index e6f4cbfeed9736006e852c306aed7f4839987a95..067920f2d570fb77be332cf16e885bf63e0a352c 100644 (file)
@@ -1969,10 +1969,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                goto fail0;
        }
 
-       pm_runtime_use_autosuspend(musb->controller);
-       pm_runtime_set_autosuspend_delay(musb->controller, 200);
-       pm_runtime_enable(musb->controller);
-
        spin_lock_init(&musb->lock);
        musb->board_set_power = plat->set_power;
        musb->min_power = plat->min_power;
@@ -1991,6 +1987,12 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        musb_readl = musb_default_readl;
        musb_writel = musb_default_writel;
 
+       /* We need musb_read/write functions initialized for PM */
+       pm_runtime_use_autosuspend(musb->controller);
+       pm_runtime_set_autosuspend_delay(musb->controller, 200);
+       pm_runtime_irq_safe(musb->controller);
+       pm_runtime_enable(musb->controller);
+
        /* The musb_platform_init() call:
         *   - adjusts musb->mregs
         *   - sets the musb->isr
index 53bd0e71d19f02e3582db6ac21d0e617765c0ad1..a900c9877195ad6ef2048ddb8c2813c8e196feed 100644 (file)
@@ -457,12 +457,27 @@ static int dsps_musb_init(struct musb *musb)
        if (IS_ERR(musb->xceiv))
                return PTR_ERR(musb->xceiv);
 
+       musb->phy = devm_phy_get(dev->parent, "usb2-phy");
+
        /* Returns zero if e.g. not clocked */
        rev = dsps_readl(reg_base, wrp->revision);
        if (!rev)
                return -ENODEV;
 
        usb_phy_init(musb->xceiv);
+       if (IS_ERR(musb->phy))  {
+               musb->phy = NULL;
+       } else {
+               ret = phy_init(musb->phy);
+               if (ret < 0)
+                       return ret;
+               ret = phy_power_on(musb->phy);
+               if (ret) {
+                       phy_exit(musb->phy);
+                       return ret;
+               }
+       }
+
        setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
 
        /* Reset the musb */
@@ -502,6 +517,8 @@ static int dsps_musb_exit(struct musb *musb)
 
        del_timer_sync(&glue->timer);
        usb_phy_shutdown(musb->xceiv);
+       phy_power_off(musb->phy);
+       phy_exit(musb->phy);
        debugfs_remove_recursive(glue->dbgfs_root);
 
        return 0;
@@ -610,7 +627,7 @@ static int dsps_musb_reset(struct musb *musb)
        struct device *dev = musb->controller;
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
        const struct dsps_musb_wrapper *wrp = glue->wrp;
-       int session_restart = 0;
+       int session_restart = 0, error;
 
        if (glue->sw_babble_enabled)
                session_restart = sw_babble_control(musb);
@@ -624,8 +641,14 @@ static int dsps_musb_reset(struct musb *musb)
                dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset));
                usleep_range(100, 200);
                usb_phy_shutdown(musb->xceiv);
+               error = phy_power_off(musb->phy);
+               if (error)
+                       dev_err(dev, "phy shutdown failed: %i\n", error);
                usleep_range(100, 200);
                usb_phy_init(musb->xceiv);
+               error = phy_power_on(musb->phy);
+               if (error)
+                       dev_err(dev, "phy powerup failed: %i\n", error);
                session_restart = 1;
        }
 
@@ -687,7 +710,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
        struct musb_hdrc_config *config;
        struct platform_device *musb;
        struct device_node *dn = parent->dev.of_node;
-       int ret;
+       int ret, val;
 
        memset(resources, 0, sizeof(resources));
        res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc");
@@ -739,7 +762,10 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
        pdata.mode = get_musb_port_mode(dev);
        /* DT keeps this entry in mA, musb expects it as per USB spec */
        pdata.power = get_int_prop(dn, "mentor,power") / 2;
-       config->multipoint = of_property_read_bool(dn, "mentor,multipoint");
+
+       ret = of_property_read_u32(dn, "mentor,multipoint", &val);
+       if (!ret && val)
+               config->multipoint = true;
 
        ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
        if (ret) {
index 883a9adfdfff5f0c1643036e0be7d7d22d1e73a8..c3d5fc9dfb5bd56f5adc0a3cee337ffd1c31541f 100644 (file)
@@ -2613,7 +2613,7 @@ static const struct hc_driver musb_hc_driver = {
        .description            = "musb-hcd",
        .product_desc           = "MUSB HDRC host driver",
        .hcd_priv_size          = sizeof(struct musb *),
-       .flags                  = HCD_USB2 | HCD_MEMORY,
+       .flags                  = HCD_USB2 | HCD_MEMORY | HCD_BH,
 
        /* not using irq handler or reset hooks from usbcore, since
         * those must be shared with peripheral code for OTG configs
index 763649eb4987d99cafdc8aa5d3eb77590171150d..cc752d8c7773176d1338d5927c7b7c3bf4fc5ccd 100644 (file)
@@ -516,7 +516,7 @@ static int omap2430_probe(struct platform_device *pdev)
        struct omap2430_glue            *glue;
        struct device_node              *np = pdev->dev.of_node;
        struct musb_hdrc_config         *config;
-       int                             ret = -ENOMEM;
+       int                             ret = -ENOMEM, val;
 
        glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
        if (!glue)
@@ -559,7 +559,10 @@ static int omap2430_probe(struct platform_device *pdev)
                of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
                of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
                of_property_read_u32(np, "power", (u32 *)&pdata->power);
-               config->multipoint = of_property_read_bool(np, "multipoint");
+
+               ret = of_property_read_u32(np, "multipoint", &val);
+               if (!ret && val)
+                       config->multipoint = true;
 
                pdata->board_data       = data;
                pdata->config           = config;
index 403fab772724825b16ecfd8446ab9d95386bb1cc..7b3035ff94347a519a9d54f27c45108aaaca0e9f 100644 (file)
@@ -126,6 +126,9 @@ struct phy_control *am335x_get_phy_control(struct device *dev)
                return NULL;
 
        dev = bus_find_device(&platform_bus_type, NULL, node, match);
+       if (!dev)
+               return NULL;
+
        ctrl_usb = dev_get_drvdata(dev);
        if (!ctrl_usb)
                return NULL;
index de83b9d0cd5c39449eb71e237ecd2dfa272cdf8c..ebc99ee076ce337275bbea3869abaa830b007111 100644 (file)
@@ -6,6 +6,7 @@ config USB_RENESAS_USBHS
        tristate 'Renesas USBHS controller'
        depends on USB_GADGET
        depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
+       depends on EXTCON || !EXTCON # if EXTCON=m, USBHS cannot be built-in
        default n
        help
          Renesas USBHS is a discrete USB host and peripheral controller chip
index 9374bd2aba20759f4bb4b03d2a9d51058aead9fd..8936a83c96cd60c8a226e0c96a9908c06d356773 100644 (file)
@@ -38,56 +38,51 @@ static int usb_serial_device_match(struct device *dev,
        return 0;
 }
 
-static ssize_t port_number_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct usb_serial_port *port = to_usb_serial_port(dev);
-
-       return sprintf(buf, "%d\n", port->port_number);
-}
-static DEVICE_ATTR_RO(port_number);
-
 static int usb_serial_device_probe(struct device *dev)
 {
        struct usb_serial_driver *driver;
        struct usb_serial_port *port;
+       struct device *tty_dev;
        int retval = 0;
        int minor;
 
        port = to_usb_serial_port(dev);
-       if (!port) {
-               retval = -ENODEV;
-               goto exit;
-       }
+       if (!port)
+               return -ENODEV;
 
        /* make sure suspend/resume doesn't race against port_probe */
        retval = usb_autopm_get_interface(port->serial->interface);
        if (retval)
-               goto exit;
+               return retval;
 
        driver = port->serial->type;
        if (driver->port_probe) {
                retval = driver->port_probe(port);
                if (retval)
-                       goto exit_with_autopm;
+                       goto err_autopm_put;
        }
 
-       retval = device_create_file(dev, &dev_attr_port_number);
-       if (retval) {
-               if (driver->port_remove)
-                       retval = driver->port_remove(port);
-               goto exit_with_autopm;
+       minor = port->minor;
+       tty_dev = tty_register_device(usb_serial_tty_driver, minor, dev);
+       if (IS_ERR(tty_dev)) {
+               retval = PTR_ERR(tty_dev);
+               goto err_port_remove;
        }
 
-       minor = port->minor;
-       tty_register_device(usb_serial_tty_driver, minor, dev);
+       usb_autopm_put_interface(port->serial->interface);
+
        dev_info(&port->serial->dev->dev,
                 "%s converter now attached to ttyUSB%d\n",
                 driver->description, minor);
 
-exit_with_autopm:
+       return 0;
+
+err_port_remove:
+       if (driver->port_remove)
+               driver->port_remove(port);
+err_autopm_put:
        usb_autopm_put_interface(port->serial->interface);
-exit:
+
        return retval;
 }
 
@@ -114,8 +109,6 @@ static int usb_serial_device_remove(struct device *dev)
        minor = port->minor;
        tty_unregister_device(usb_serial_tty_driver, minor);
 
-       device_remove_file(&port->dev, &dev_attr_port_number);
-
        driver = port->serial->type;
        if (driver->port_remove)
                retval = driver->port_remove(port);
index 2d72aa3564a31e9eeade77423ec16de3d743c706..ede4f5fcfadda11dcdb7ab954769f827bd3c312a 100644 (file)
@@ -84,6 +84,10 @@ struct ch341_private {
        u8 line_status; /* active status of modem control inputs */
 };
 
+static void ch341_set_termios(struct tty_struct *tty,
+                             struct usb_serial_port *port,
+                             struct ktermios *old_termios);
+
 static int ch341_control_out(struct usb_device *dev, u8 request,
                             u16 value, u16 index)
 {
@@ -309,19 +313,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct ch341_private *priv = usb_get_serial_port_data(port);
        int r;
 
-       priv->baud_rate = DEFAULT_BAUD_RATE;
-
        r = ch341_configure(serial->dev, priv);
        if (r)
                goto out;
 
-       r = ch341_set_handshake(serial->dev, priv->line_control);
-       if (r)
-               goto out;
-
-       r = ch341_set_baudrate(serial->dev, priv);
-       if (r)
-               goto out;
+       if (tty)
+               ch341_set_termios(tty, port, NULL);
 
        dev_dbg(&port->dev, "%s - submitting interrupt urb\n", __func__);
        r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
index 29fa1c3d0089bee738ed4f54a8b65d4f82dd0c03..3806e7014199d13c892f32e8a03c1b37e286bddb 100644 (file)
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/tty.h>
 #include <linux/console.h>
@@ -144,6 +145,7 @@ static int usb_console_setup(struct console *co, char *options)
                        init_ldsem(&tty->ldisc_sem);
                        INIT_LIST_HEAD(&tty->tty_files);
                        kref_get(&tty->driver->kref);
+                       __module_get(tty->driver->owner);
                        tty->ops = &usb_console_fake_tty_ops;
                        if (tty_init_termios(tty)) {
                                retval = -ENOMEM;
index f40c856ff758d959318ae4d251eea6cd96f5819a..84ce2d74894c9c3b25c7bcf0185f23887492eb94 100644 (file)
@@ -147,6 +147,8 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */
        { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */
        { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */
+       { USB_DEVICE(0x16C0, 0x09B0) }, /* Lunatico Seletek */
+       { USB_DEVICE(0x16C0, 0x09B1) }, /* Lunatico Seletek */
        { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
        { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
        { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
index 1ebb351b9e9a59c9dbd90ffda56cae1769de764e..3086dec0ef53bbd5d5d3d21087b91469983492fb 100644 (file)
@@ -799,6 +799,8 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },
+       { USB_DEVICE(FTDI_VID, CYBER_CORTEX_AV_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID),
@@ -978,6 +980,23 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) },
        /* GE Healthcare devices */
        { USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) },
+       /* Active Research (Actisense) devices */
+       { USB_DEVICE(FTDI_VID, ACTISENSE_NDC_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_USG_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_NGT_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_NGW_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_D9AC_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_D9AD_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_D9AE_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_D9AF_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEAGAUGE_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASWITCH_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_NMEA2000_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ETHERNET_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_WIFI_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_DISPLAY_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_LITE_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ANALOG_PID) },
        { }                                     /* Terminating entry */
 };
 
index e52409c9be999f817cbdb627f4be8ec6f127cbe6..56b1b55c4751696b2e89633ea90bfe1c2940c436 100644 (file)
@@ -38,6 +38,9 @@
 
 #define FTDI_LUMEL_PD12_PID    0x6002
 
+/* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */
+#define CYBER_CORTEX_AV_PID    0x8698
+
 /*
  * Marvell OpenRD Base, Client
  * http://www.open-rd.org
  */
 #define GE_HEALTHCARE_VID              0x1901
 #define GE_HEALTHCARE_NEMO_TRACKER_PID 0x0015
+
+/*
+ * Active Research (Actisense) devices
+ */
+#define ACTISENSE_NDC_PID              0xD9A8 /* NDC USB Serial Adapter */
+#define ACTISENSE_USG_PID              0xD9A9 /* USG USB Serial Adapter */
+#define ACTISENSE_NGT_PID              0xD9AA /* NGT NMEA2000 Interface */
+#define ACTISENSE_NGW_PID              0xD9AB /* NGW NMEA2000 Gateway */
+#define ACTISENSE_D9AC_PID             0xD9AC /* Actisense Reserved */
+#define ACTISENSE_D9AD_PID             0xD9AD /* Actisense Reserved */
+#define ACTISENSE_D9AE_PID             0xD9AE /* Actisense Reserved */
+#define ACTISENSE_D9AF_PID             0xD9AF /* Actisense Reserved */
+#define CHETCO_SEAGAUGE_PID            0xA548 /* SeaGauge USB Adapter */
+#define CHETCO_SEASWITCH_PID           0xA549 /* SeaSwitch USB Adapter */
+#define CHETCO_SEASMART_NMEA2000_PID   0xA54A /* SeaSmart NMEA2000 Gateway */
+#define CHETCO_SEASMART_ETHERNET_PID   0xA54B /* SeaSmart Ethernet Gateway */
+#define CHETCO_SEASMART_WIFI_PID       0xA5AC /* SeaSmart Wifi Gateway */
+#define CHETCO_SEASMART_DISPLAY_PID    0xA5AD /* SeaSmart NMEA2000 Display */
+#define CHETCO_SEASMART_LITE_PID       0xA5AE /* SeaSmart Lite USB Adapter */
+#define CHETCO_SEASMART_ANALOG_PID     0xA5AF /* SeaSmart Analog Adapter */
index ccf1df7c4b80f3f7a596fa3d1d8904eb64a78db6..54e170dd3dad0cec058e29674b98f685f90274df 100644 (file)
@@ -258,7 +258,8 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout)
         * character or at least one jiffy.
         */
        period = max_t(unsigned long, (10 * HZ / bps), 1);
-       period = min_t(unsigned long, period, timeout);
+       if (timeout)
+               period = min_t(unsigned long, period, timeout);
 
        dev_dbg(&port->dev, "%s - timeout = %u ms, period = %u ms\n",
                                        __func__, jiffies_to_msecs(timeout),
@@ -268,7 +269,7 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout)
                schedule_timeout_interruptible(period);
                if (signal_pending(current))
                        break;
-               if (time_after(jiffies, expire))
+               if (timeout && time_after(jiffies, expire))
                        break;
        }
 }
index ab1d690274ae52b3230f04acbd8194a49f68b7ba..460a40669967855cfeea7c6cc911064822c6882a 100644 (file)
@@ -1284,7 +1284,8 @@ static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port)
        }
 
        /* Initial port termios */
-       mxuport_set_termios(tty, port, NULL);
+       if (tty)
+               mxuport_set_termios(tty, port, NULL);
 
        /*
         * TODO: use RQ_VENDOR_GET_MSR, once we know what it
index 0f872e6b2c878f9b8de56fc6ae0cddda56468589..829604d11f3fa72a6b5bec5580f150c27c513cbf 100644 (file)
@@ -132,6 +132,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define UART_OVERRUN_ERROR             0x40
 #define UART_CTS                       0x80
 
+static void pl2303_set_break(struct usb_serial_port *port, bool enable);
 
 enum pl2303_type {
        TYPE_01,        /* Type 0 and 1 (difference unknown) */
@@ -615,6 +616,7 @@ static void pl2303_close(struct usb_serial_port *port)
 {
        usb_serial_generic_close(port);
        usb_kill_urb(port->interrupt_in_urb);
+       pl2303_set_break(port, false);
 }
 
 static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -741,17 +743,16 @@ static int pl2303_ioctl(struct tty_struct *tty,
        return -ENOIOCTLCMD;
 }
 
-static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
+static void pl2303_set_break(struct usb_serial_port *port, bool enable)
 {
-       struct usb_serial_port *port = tty->driver_data;
        struct usb_serial *serial = port->serial;
        u16 state;
        int result;
 
-       if (break_state == 0)
-               state = BREAK_OFF;
-       else
+       if (enable)
                state = BREAK_ON;
+       else
+               state = BREAK_OFF;
 
        dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
                        state == BREAK_OFF ? "off" : "on");
@@ -763,6 +764,13 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
                dev_err(&port->dev, "error sending break = %d\n", result);
 }
 
+static void pl2303_break_ctl(struct tty_struct *tty, int state)
+{
+       struct usb_serial_port *port = tty->driver_data;
+
+       pl2303_set_break(port, state);
+}
+
 static void pl2303_update_line_status(struct usb_serial_port *port,
                                      unsigned char *data,
                                      unsigned int actual_length)
index 475723c006f955923d255be9abc408c7fd29027d..529066bbc7e81be1bb67e398f58425febef6a8eb 100644 (file)
@@ -687,6 +687,21 @@ static void serial_port_dtr_rts(struct tty_port *port, int on)
                drv->dtr_rts(p, on);
 }
 
+static ssize_t port_number_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct usb_serial_port *port = to_usb_serial_port(dev);
+
+       return sprintf(buf, "%u\n", port->port_number);
+}
+static DEVICE_ATTR_RO(port_number);
+
+static struct attribute *usb_serial_port_attrs[] = {
+       &dev_attr_port_number.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(usb_serial_port);
+
 static const struct tty_port_operations serial_port_ops = {
        .carrier_raised         = serial_port_carrier_raised,
        .dtr_rts                = serial_port_dtr_rts,
@@ -902,6 +917,7 @@ static int usb_serial_probe(struct usb_interface *interface,
                port->dev.driver = NULL;
                port->dev.bus = &usb_serial_bus_type;
                port->dev.release = &usb_serial_port_release;
+               port->dev.groups = usb_serial_port_groups;
                device_initialize(&port->dev);
        }
 
@@ -940,8 +956,9 @@ static int usb_serial_probe(struct usb_interface *interface,
                port = serial->port[i];
                if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
                        goto probe_error;
-               buffer_size = max_t(int, serial->type->bulk_out_size,
-                                               usb_endpoint_maxp(endpoint));
+               buffer_size = serial->type->bulk_out_size;
+               if (!buffer_size)
+                       buffer_size = usb_endpoint_maxp(endpoint);
                port->bulk_out_size = buffer_size;
                port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
 
index dbc00e56c7f5c106a67028e1b6da7dfee2c39e5e..c85ea530085f12d86ca691d82122f04e9f2166ae 100644 (file)
@@ -113,6 +113,20 @@ UNUSUAL_DEV(0x0bc2, 0xab2a, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_ATA_1X),
 
+/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
+UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
+               "Initio Corporation",
+               "",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_ATA_1X),
+
+/* Reported-by: Tom Arild Naess <tanaess@gmail.com> */
+UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999,
+               "JMicron",
+               "JMS539",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_REPORT_OPCODES),
+
 /* Reported-by: Claudio Bizzarri <claudio.bizzarri@gmail.com> */
 UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999,
                "JMicron",
index d468d02179f4707d308192ed3578665a41ee96f9..5600c33fcadb219e52e8f985bf692c6ff3a1025e 100644 (file)
@@ -889,6 +889,12 @@ static void usb_stor_scan_dwork(struct work_struct *work)
            !(us->fflags & US_FL_SCM_MULT_TARG)) {
                mutex_lock(&us->dev_mutex);
                us->max_lun = usb_stor_Bulk_max_lun(us);
+               /*
+                * Allow proper scanning of devices that present more than 8 LUNs
+                * While not affecting other devices that may need the previous behavior
+                */
+               if (us->max_lun >= 8)
+                       us_to_host(us)->max_lun = us->max_lun+1;
                mutex_unlock(&us->dev_mutex);
        }
        scsi_scan_host(us_to_host(us));
index f88bfdf5b6a036a6bf1aae3b8abe3ec6d944ffe0..2027a27546ef4f7a816c08f7598e9c796e6c5ad7 100644 (file)
@@ -868,12 +868,14 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
                                func = vfio_pci_set_err_trigger;
                        break;
                }
+               break;
        case VFIO_PCI_REQ_IRQ_INDEX:
                switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
                case VFIO_IRQ_SET_ACTION_TRIGGER:
                        func = vfio_pci_set_req_trigger;
                        break;
                }
+               break;
        }
 
        if (!func)
index afa06d28725dad3960aed1df9dd4f9e9ddc53493..2bbfc25e582cb8b334a1ef4083b22da56c48cc65 100644 (file)
@@ -591,11 +591,6 @@ static void handle_rx(struct vhost_net *net)
                         * TODO: support TSO.
                         */
                        iov_iter_advance(&msg.msg_iter, vhost_hlen);
-               } else {
-                       /* It'll come from socket; we'll need to patch
-                        * ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF
-                        */
-                       iov_iter_advance(&fixup, sizeof(hdr));
                }
                err = sock->ops->recvmsg(NULL, sock, &msg,
                                         sock_len, MSG_DONTWAIT | MSG_TRUNC);
@@ -609,17 +604,25 @@ static void handle_rx(struct vhost_net *net)
                        continue;
                }
                /* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */
-               if (unlikely(vhost_hlen) &&
-                   copy_to_iter(&hdr, sizeof(hdr), &fixup) != sizeof(hdr)) {
-                       vq_err(vq, "Unable to write vnet_hdr at addr %p\n",
-                              vq->iov->iov_base);
-                       break;
+               if (unlikely(vhost_hlen)) {
+                       if (copy_to_iter(&hdr, sizeof(hdr),
+                                        &fixup) != sizeof(hdr)) {
+                               vq_err(vq, "Unable to write vnet_hdr "
+                                      "at addr %p\n", vq->iov->iov_base);
+                               break;
+                       }
+               } else {
+                       /* Header came from socket; we'll need to patch
+                        * ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF
+                        */
+                       iov_iter_advance(&fixup, sizeof(hdr));
                }
                /* TODO: Should check and handle checksum. */
 
                num_buffers = cpu_to_vhost16(vq, headcount);
                if (likely(mergeable) &&
-                   copy_to_iter(&num_buffers, 2, &fixup) != 2) {
+                   copy_to_iter(&num_buffers, sizeof num_buffers,
+                                &fixup) != sizeof num_buffers) {
                        vq_err(vq, "Failed num_buffers write");
                        vhost_discard_vq_desc(vq, headcount);
                        break;
index 8d4f3f1ff799fb1d7b4bb5a2184144b515676a2c..71df240a467a10bef98c6314ba8d6031fa8e3bf6 100644 (file)
@@ -1956,10 +1956,9 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
                goto out;
        }
        /*
-        * Now register the TCM vhost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
+        * Now register the TCM vhost virtual I_T Nexus as active.
         */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
 
index 32c0b6b28097f115f5a701d7a7d59f50d92d147d..9362424c2340490585fe02e4dfe950f53f2097af 100644 (file)
@@ -599,6 +599,9 @@ static int clcdfb_of_get_mode(struct device *dev, struct device_node *endpoint,
 
        len = clcdfb_snprintf_mode(NULL, 0, mode);
        name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
        clcdfb_snprintf_mode(name, len + 1, mode);
        mode->name = name;
 
index 95338593ebf4bc8bfc280bf1567c5fa90d712916..868facdec6384da049eb130097eaf76c994b95d0 100644 (file)
@@ -624,9 +624,6 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
        int num = 0, i, first = 1;
        int ver, rev;
 
-       ver = edid[EDID_STRUCT_VERSION];
-       rev = edid[EDID_STRUCT_REVISION];
-
        mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
        if (mode == NULL)
                return NULL;
@@ -637,6 +634,9 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
                return NULL;
        }
 
+       ver = edid[EDID_STRUCT_VERSION];
+       rev = edid[EDID_STRUCT_REVISION];
+
        *dbsize = 0;
 
        DPRINTK("   Detailed Timings\n");
index 5a2095a98ed868016f0f5283c431b012bf2eac08..12186557a9d4d5030d23dd91453029a3d2cc8a3c 100644 (file)
 #include <video/omapdss.h>
 #include "dss.h"
 
-static struct omap_dss_device *to_dss_device_sysfs(struct device *dev)
+static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = NULL;
-
-       for_each_dss_dev(dssdev) {
-               if (dssdev->dev == dev) {
-                       omap_dss_put_device(dssdev);
-                       return dssdev;
-               }
-       }
-
-       return NULL;
-}
-
-static ssize_t display_name_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
-
        return snprintf(buf, PAGE_SIZE, "%s\n",
                        dssdev->name ?
                        dssdev->name : "");
 }
 
-static ssize_t display_enabled_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
-
        return snprintf(buf, PAGE_SIZE, "%d\n",
                        omapdss_device_is_enabled(dssdev));
 }
 
-static ssize_t display_enabled_store(struct device *dev,
-               struct device_attribute *attr,
+static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
                const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int r;
        bool enable;
 
@@ -90,19 +68,16 @@ static ssize_t display_enabled_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_tear_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        return snprintf(buf, PAGE_SIZE, "%d\n",
                        dssdev->driver->get_te ?
                        dssdev->driver->get_te(dssdev) : 0);
 }
 
-static ssize_t display_tear_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_tear_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int r;
        bool te;
 
@@ -120,10 +95,8 @@ static ssize_t display_tear_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_timings_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_timings_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        struct omap_video_timings t;
 
        if (!dssdev->driver->get_timings)
@@ -137,10 +110,9 @@ static ssize_t display_timings_show(struct device *dev,
                        t.y_res, t.vfp, t.vbp, t.vsw);
 }
 
-static ssize_t display_timings_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_timings_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        struct omap_video_timings t = dssdev->panel.timings;
        int r, found;
 
@@ -176,10 +148,8 @@ static ssize_t display_timings_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_rotate_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_rotate_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int rotate;
        if (!dssdev->driver->get_rotate)
                return -ENOENT;
@@ -187,10 +157,9 @@ static ssize_t display_rotate_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
 }
 
-static ssize_t display_rotate_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_rotate_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int rot, r;
 
        if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
@@ -207,10 +176,8 @@ static ssize_t display_rotate_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_mirror_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_mirror_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int mirror;
        if (!dssdev->driver->get_mirror)
                return -ENOENT;
@@ -218,10 +185,9 @@ static ssize_t display_mirror_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
 }
 
-static ssize_t display_mirror_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_mirror_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int r;
        bool mirror;
 
@@ -239,10 +205,8 @@ static ssize_t display_mirror_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_wss_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_wss_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        unsigned int wss;
 
        if (!dssdev->driver->get_wss)
@@ -253,10 +217,9 @@ static ssize_t display_wss_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
 }
 
-static ssize_t display_wss_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_wss_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        u32 wss;
        int r;
 
@@ -277,50 +240,94 @@ static ssize_t display_wss_store(struct device *dev,
        return size;
 }
 
-static DEVICE_ATTR(display_name, S_IRUGO, display_name_show, NULL);
-static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
+struct display_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct omap_dss_device *, char *);
+       ssize_t (*store)(struct omap_dss_device *, const char *, size_t);
+};
+
+#define DISPLAY_ATTR(_name, _mode, _show, _store) \
+       struct display_attribute display_attr_##_name = \
+       __ATTR(_name, _mode, _show, _store)
+
+static DISPLAY_ATTR(name, S_IRUGO, display_name_show, NULL);
+static DISPLAY_ATTR(display_name, S_IRUGO, display_name_show, NULL);
+static DISPLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
                display_enabled_show, display_enabled_store);
-static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(tear_elim, S_IRUGO|S_IWUSR,
                display_tear_show, display_tear_store);
-static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(timings, S_IRUGO|S_IWUSR,
                display_timings_show, display_timings_store);
-static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(rotate, S_IRUGO|S_IWUSR,
                display_rotate_show, display_rotate_store);
-static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(mirror, S_IRUGO|S_IWUSR,
                display_mirror_show, display_mirror_store);
-static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(wss, S_IRUGO|S_IWUSR,
                display_wss_show, display_wss_store);
 
-static const struct attribute *display_sysfs_attrs[] = {
-       &dev_attr_display_name.attr,
-       &dev_attr_enabled.attr,
-       &dev_attr_tear_elim.attr,
-       &dev_attr_timings.attr,
-       &dev_attr_rotate.attr,
-       &dev_attr_mirror.attr,
-       &dev_attr_wss.attr,
+static struct attribute *display_sysfs_attrs[] = {
+       &display_attr_name.attr,
+       &display_attr_display_name.attr,
+       &display_attr_enabled.attr,
+       &display_attr_tear_elim.attr,
+       &display_attr_timings.attr,
+       &display_attr_rotate.attr,
+       &display_attr_mirror.attr,
+       &display_attr_wss.attr,
        NULL
 };
 
+static ssize_t display_attr_show(struct kobject *kobj, struct attribute *attr,
+               char *buf)
+{
+       struct omap_dss_device *dssdev;
+       struct display_attribute *display_attr;
+
+       dssdev = container_of(kobj, struct omap_dss_device, kobj);
+       display_attr = container_of(attr, struct display_attribute, attr);
+
+       if (!display_attr->show)
+               return -ENOENT;
+
+       return display_attr->show(dssdev, buf);
+}
+
+static ssize_t display_attr_store(struct kobject *kobj, struct attribute *attr,
+               const char *buf, size_t size)
+{
+       struct omap_dss_device *dssdev;
+       struct display_attribute *display_attr;
+
+       dssdev = container_of(kobj, struct omap_dss_device, kobj);
+       display_attr = container_of(attr, struct display_attribute, attr);
+
+       if (!display_attr->store)
+               return -ENOENT;
+
+       return display_attr->store(dssdev, buf, size);
+}
+
+static const struct sysfs_ops display_sysfs_ops = {
+       .show = display_attr_show,
+       .store = display_attr_store,
+};
+
+static struct kobj_type display_ktype = {
+       .sysfs_ops = &display_sysfs_ops,
+       .default_attrs = display_sysfs_attrs,
+};
+
 int display_init_sysfs(struct platform_device *pdev)
 {
        struct omap_dss_device *dssdev = NULL;
        int r;
 
        for_each_dss_dev(dssdev) {
-               struct kobject *kobj = &dssdev->dev->kobj;
-
-               r = sysfs_create_files(kobj, display_sysfs_attrs);
+               r = kobject_init_and_add(&dssdev->kobj, &display_ktype,
+                       &pdev->dev.kobj, dssdev->alias);
                if (r) {
                        DSSERR("failed to create sysfs files\n");
-                       goto err;
-               }
-
-               r = sysfs_create_link(&pdev->dev.kobj, kobj, dssdev->alias);
-               if (r) {
-                       sysfs_remove_files(kobj, display_sysfs_attrs);
-
-                       DSSERR("failed to create sysfs display link\n");
+                       omap_dss_put_device(dssdev);
                        goto err;
                }
        }
@@ -338,8 +345,12 @@ void display_uninit_sysfs(struct platform_device *pdev)
        struct omap_dss_device *dssdev = NULL;
 
        for_each_dss_dev(dssdev) {
-               sysfs_remove_link(&pdev->dev.kobj, dssdev->alias);
-               sysfs_remove_files(&dssdev->dev->kobj,
-                               display_sysfs_attrs);
+               if (kobject_name(&dssdev->kobj) == NULL)
+                       continue;
+
+               kobject_del(&dssdev->kobj);
+               kobject_put(&dssdev->kobj);
+
+               memset(&dssdev->kobj, 0, sizeof(dssdev->kobj));
        }
 }
index 0413157f3b49c230aaa7a775564086144977803f..6a356e344f82c3d5b594abeeb47c453e868c4f9f 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/balloon_compaction.h>
 #include <linux/oom.h>
+#include <linux/wait.h>
 
 /*
  * Balloon device works in 4K page units.  So each page is pointed to by
@@ -334,17 +335,25 @@ static int virtballoon_oom_notify(struct notifier_block *self,
 static int balloon(void *_vballoon)
 {
        struct virtio_balloon *vb = _vballoon;
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
 
        set_freezable();
        while (!kthread_should_stop()) {
                s64 diff;
 
                try_to_freeze();
-               wait_event_interruptible(vb->config_change,
-                                        (diff = towards_target(vb)) != 0
-                                        || vb->need_stats_update
-                                        || kthread_should_stop()
-                                        || freezing(current));
+
+               add_wait_queue(&vb->config_change, &wait);
+               for (;;) {
+                       if ((diff = towards_target(vb)) != 0 ||
+                           vb->need_stats_update ||
+                           kthread_should_stop() ||
+                           freezing(current))
+                               break;
+                       wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
+               }
+               remove_wait_queue(&vb->config_change, &wait);
+
                if (vb->need_stats_update)
                        stats_handle_request(vb);
                if (diff > 0)
@@ -499,6 +508,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
        if (err < 0)
                goto out_oom_notify;
 
+       virtio_device_ready(vdev);
+
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
                err = PTR_ERR(vb->thread);
index cad569890908de40ba4d72edd6562fb87b6e14b5..6010d7ec0a0f899b7b7690d202e9b57c6dbc7193 100644 (file)
@@ -156,22 +156,95 @@ static void vm_get(struct virtio_device *vdev, unsigned offset,
                   void *buf, unsigned len)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
-       u8 *ptr = buf;
-       int i;
+       void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
+       u8 b;
+       __le16 w;
+       __le32 l;
 
-       for (i = 0; i < len; i++)
-               ptr[i] = readb(vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
+       if (vm_dev->version == 1) {
+               u8 *ptr = buf;
+               int i;
+
+               for (i = 0; i < len; i++)
+                       ptr[i] = readb(base + offset + i);
+               return;
+       }
+
+       switch (len) {
+       case 1:
+               b = readb(base + offset);
+               memcpy(buf, &b, sizeof b);
+               break;
+       case 2:
+               w = cpu_to_le16(readw(base + offset));
+               memcpy(buf, &w, sizeof w);
+               break;
+       case 4:
+               l = cpu_to_le32(readl(base + offset));
+               memcpy(buf, &l, sizeof l);
+               break;
+       case 8:
+               l = cpu_to_le32(readl(base + offset));
+               memcpy(buf, &l, sizeof l);
+               l = cpu_to_le32(ioread32(base + offset + sizeof l));
+               memcpy(buf + sizeof l, &l, sizeof l);
+               break;
+       default:
+               BUG();
+       }
 }
 
 static void vm_set(struct virtio_device *vdev, unsigned offset,
                   const void *buf, unsigned len)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
-       const u8 *ptr = buf;
-       int i;
+       void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
+       u8 b;
+       __le16 w;
+       __le32 l;
 
-       for (i = 0; i < len; i++)
-               writeb(ptr[i], vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
+       if (vm_dev->version == 1) {
+               const u8 *ptr = buf;
+               int i;
+
+               for (i = 0; i < len; i++)
+                       writeb(ptr[i], base + offset + i);
+
+               return;
+       }
+
+       switch (len) {
+       case 1:
+               memcpy(&b, buf, sizeof b);
+               writeb(b, base + offset);
+               break;
+       case 2:
+               memcpy(&w, buf, sizeof w);
+               writew(le16_to_cpu(w), base + offset);
+               break;
+       case 4:
+               memcpy(&l, buf, sizeof l);
+               writel(le32_to_cpu(l), base + offset);
+               break;
+       case 8:
+               memcpy(&l, buf, sizeof l);
+               writel(le32_to_cpu(l), base + offset);
+               memcpy(&l, buf + sizeof l, sizeof l);
+               writel(le32_to_cpu(l), base + offset + sizeof l);
+               break;
+       default:
+               BUG();
+       }
+}
+
+static u32 vm_generation(struct virtio_device *vdev)
+{
+       struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+
+       if (vm_dev->version == 1)
+               return 0;
+       else
+               return readl(vm_dev->base + VIRTIO_MMIO_CONFIG_GENERATION);
 }
 
 static u8 vm_get_status(struct virtio_device *vdev)
@@ -440,6 +513,7 @@ static const char *vm_bus_name(struct virtio_device *vdev)
 static const struct virtio_config_ops virtio_mmio_config_ops = {
        .get            = vm_get,
        .set            = vm_set,
+       .generation     = vm_generation,
        .get_status     = vm_get_status,
        .set_status     = vm_set_status,
        .reset          = vm_reset,
index 6df940528fd21b0cef8524004645fe472b7f7061..1443b3c391de497c05fe332f1c4cdd067bc5f5c9 100644 (file)
@@ -208,7 +208,8 @@ static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
 
        if ((tmp & AT91_WDT_WDFIEN) && wdt->irq) {
                err = request_irq(wdt->irq, wdt_interrupt,
-                                 IRQF_SHARED | IRQF_IRQPOLL,
+                                 IRQF_SHARED | IRQF_IRQPOLL |
+                                 IRQF_NO_SUSPEND,
                                  pdev->name, wdt);
                if (err)
                        return err;
index c8def68d9e4cf30c391fabc36981f96b4cb9d72a..0deaa4f971f5ff1fdfde6d063314a45bd99b9707 100644 (file)
 #define PDC_WDT_MIN_TIMEOUT            1
 #define PDC_WDT_DEF_TIMEOUT            64
 
-static int heartbeat;
+static int heartbeat = PDC_WDT_DEF_TIMEOUT;
 module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
-       "(default = " __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds "
+       "(default=" __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
@@ -191,6 +191,7 @@ static int pdc_wdt_probe(struct platform_device *pdev)
        pdc_wdt->wdt_dev.ops = &pdc_wdt_ops;
        pdc_wdt->wdt_dev.max_timeout = 1 << PDC_WDT_CONFIG_DELAY_MASK;
        pdc_wdt->wdt_dev.parent = &pdev->dev;
+       watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
 
        ret = watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev);
        if (ret < 0) {
@@ -232,7 +233,6 @@ static int pdc_wdt_probe(struct platform_device *pdev)
        watchdog_set_nowayout(&pdc_wdt->wdt_dev, nowayout);
 
        platform_set_drvdata(pdev, pdc_wdt);
-       watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
 
        ret = watchdog_register_device(&pdc_wdt->wdt_dev);
        if (ret)
index a87f6df6e85f32993db3907d66f3066c8820a91d..938b987de551bdea7615a701007d0125f9a10d8b 100644 (file)
@@ -133,7 +133,7 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
        u32 reg;
        struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
        void __iomem *wdt_base = mtk_wdt->wdt_base;
-       u32 ret;
+       int ret;
 
        ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
        if (ret < 0)
index 2140398a2a8c6b5f521c6250bb56a56ad41c9df7..2ccd3592d41f549967f7597ed86bd77aef8556bf 100644 (file)
@@ -2,7 +2,7 @@ ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),)
 obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
 endif
 obj-$(CONFIG_X86)                      += fallback.o
-obj-y  += grant-table.o features.o balloon.o manage.o
+obj-y  += grant-table.o features.o balloon.o manage.o preempt.o
 obj-y  += events/
 obj-y  += xenbus/
 
index b4bca2d4a7e53c7675b25d632b560e1369b19020..70fba973a107165c2c29b2104d8f4d438faddc2b 100644 (file)
@@ -526,20 +526,26 @@ static unsigned int __startup_pirq(unsigned int irq)
        pirq_query_unmask(irq);
 
        rc = set_evtchn_to_irq(evtchn, irq);
-       if (rc != 0) {
-               pr_err("irq%d: Failed to set port to irq mapping (%d)\n",
-                      irq, rc);
-               xen_evtchn_close(evtchn);
-               return 0;
-       }
+       if (rc)
+               goto err;
+
        bind_evtchn_to_cpu(evtchn, 0);
        info->evtchn = evtchn;
 
+       rc = xen_evtchn_port_setup(info);
+       if (rc)
+               goto err;
+
 out:
        unmask_evtchn(evtchn);
        eoi_pirq(irq_get_irq_data(irq));
 
        return 0;
+
+err:
+       pr_err("irq%d: Failed to set port to irq mapping (%d)\n", irq, rc);
+       xen_evtchn_close(evtchn);
+       return 0;
 }
 
 static unsigned int startup_pirq(struct irq_data *data)
diff --git a/drivers/xen/preempt.c b/drivers/xen/preempt.c
new file mode 100644 (file)
index 0000000..a1800c1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Preemptible hypercalls
+ *
+ * Copyright (C) 2014 Citrix Systems R&D ltd.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <xen/xen-ops.h>
+
+#ifndef CONFIG_PREEMPT
+
+/*
+ * Some hypercalls issued by the toolstack can take many 10s of
+ * seconds. Allow tasks running hypercalls via the privcmd driver to
+ * be voluntarily preempted even if full kernel preemption is
+ * disabled.
+ *
+ * Such preemptible hypercalls are bracketed by
+ * xen_preemptible_hcall_begin() and xen_preemptible_hcall_end()
+ * calls.
+ */
+
+DEFINE_PER_CPU(bool, xen_in_preemptible_hcall);
+EXPORT_SYMBOL_GPL(xen_in_preemptible_hcall);
+
+asmlinkage __visible void xen_maybe_preempt_hcall(void)
+{
+       if (unlikely(__this_cpu_read(xen_in_preemptible_hcall)
+                    && should_resched())) {
+               /*
+                * Clear flag as we may be rescheduled on a different
+                * cpu.
+                */
+               __this_cpu_write(xen_in_preemptible_hcall, false);
+               _cond_resched();
+               __this_cpu_write(xen_in_preemptible_hcall, true);
+       }
+}
+#endif /* CONFIG_PREEMPT */
index 569a13b9e856de5c3900050d583844f401243e96..59ac71c4a04352d055f40435444e7ccc46debf31 100644 (file)
@@ -56,10 +56,12 @@ static long privcmd_ioctl_hypercall(void __user *udata)
        if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
                return -EFAULT;
 
+       xen_preemptible_hcall_begin();
        ret = privcmd_call(hypercall.op,
                           hypercall.arg[0], hypercall.arg[1],
                           hypercall.arg[2], hypercall.arg[3],
                           hypercall.arg[4]);
+       xen_preemptible_hcall_end();
 
        return ret;
 }
index 46ae0f9f02adcca044734c58f56a93ca12801f85..75fe3d466515a08cf8ec8da7eebafd8c5b903895 100644 (file)
@@ -16,7 +16,7 @@
 #include "conf_space.h"
 #include "conf_space_quirks.h"
 
-static bool permissive;
+bool permissive;
 module_param(permissive, bool, 0644);
 
 /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word,
index e56c934ad137be00ce34e5099726e31472e86a93..2e1d73d1d5d09393ebf7e2ab21a026b709e5bb5f 100644 (file)
@@ -64,6 +64,8 @@ struct config_field_entry {
        void *data;
 };
 
+extern bool permissive;
+
 #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
 
 /* Add fields to a device - the add_fields macro expects to get a pointer to
index c5ee82587e8cc3b5feb5e594763da576765fd268..2d7369391472fd572dd3f5b837be3a2625ab4a93 100644 (file)
 #include "pciback.h"
 #include "conf_space.h"
 
+struct pci_cmd_info {
+       u16 val;
+};
+
 struct pci_bar_info {
        u32 val;
        u32 len_val;
@@ -20,22 +24,36 @@ struct pci_bar_info {
 #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
 #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
 
-static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+/* Bits guests are allowed to control in permissive mode. */
+#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
+                          PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
+                          PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
+
+static void *command_init(struct pci_dev *dev, int offset)
 {
-       int i;
-       int ret;
-
-       ret = xen_pcibk_read_config_word(dev, offset, value, data);
-       if (!pci_is_enabled(dev))
-               return ret;
-
-       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
-               if (dev->resource[i].flags & IORESOURCE_IO)
-                       *value |= PCI_COMMAND_IO;
-               if (dev->resource[i].flags & IORESOURCE_MEM)
-                       *value |= PCI_COMMAND_MEMORY;
+       struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+       int err;
+
+       if (!cmd)
+               return ERR_PTR(-ENOMEM);
+
+       err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
+       if (err) {
+               kfree(cmd);
+               return ERR_PTR(err);
        }
 
+       return cmd;
+}
+
+static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+{
+       int ret = pci_read_config_word(dev, offset, value);
+       const struct pci_cmd_info *cmd = data;
+
+       *value &= PCI_COMMAND_GUEST;
+       *value |= cmd->val & ~PCI_COMMAND_GUEST;
+
        return ret;
 }
 
@@ -43,6 +61,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
 {
        struct xen_pcibk_dev_data *dev_data;
        int err;
+       u16 val;
+       struct pci_cmd_info *cmd = data;
 
        dev_data = pci_get_drvdata(dev);
        if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
@@ -83,6 +103,19 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
                }
        }
 
+       cmd->val = value;
+
+       if (!permissive && (!dev_data || !dev_data->permissive))
+               return 0;
+
+       /* Only allow the guest to control certain bits. */
+       err = pci_read_config_word(dev, offset, &val);
+       if (err || val == value)
+               return err;
+
+       value &= PCI_COMMAND_GUEST;
+       value |= val & ~PCI_COMMAND_GUEST;
+
        return pci_write_config_word(dev, offset, value);
 }
 
@@ -282,6 +315,8 @@ static const struct config_field header_common[] = {
        {
         .offset    = PCI_COMMAND,
         .size      = 2,
+        .init      = command_init,
+        .release   = bar_release,
         .u.w.read  = command_read,
         .u.w.write = command_write,
        },
index 61653a03a8f5037c12e28c5087e3fd8960342460..42bd55a6c237209c15790876911d8aa31343b043 100644 (file)
@@ -709,12 +709,11 @@ static int prepare_pending_reqs(struct vscsibk_info *info,
 static int scsiback_do_cmd_fn(struct vscsibk_info *info)
 {
        struct vscsiif_back_ring *ring = &info->ring;
-       struct vscsiif_request *ring_req;
+       struct vscsiif_request ring_req;
        struct vscsibk_pend *pending_req;
        RING_IDX rc, rp;
        int err, more_to_do;
        uint32_t result;
-       uint8_t act;
 
        rc = ring->req_cons;
        rp = ring->sring->req_prod;
@@ -735,11 +734,10 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
                if (!pending_req)
                        return 1;
 
-               ring_req = RING_GET_REQUEST(ring, rc);
+               ring_req = *RING_GET_REQUEST(ring, rc);
                ring->req_cons = ++rc;
 
-               act = ring_req->act;
-               err = prepare_pending_reqs(info, ring_req, pending_req);
+               err = prepare_pending_reqs(info, &ring_req, pending_req);
                if (err) {
                        switch (err) {
                        case -ENODEV:
@@ -755,9 +753,9 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
                        return 1;
                }
 
-               switch (act) {
+               switch (ring_req.act) {
                case VSCSIIF_ACT_SCSI_CDB:
-                       if (scsiback_gnttab_data_map(ring_req, pending_req)) {
+                       if (scsiback_gnttab_data_map(&ring_req, pending_req)) {
                                scsiback_fast_flush_area(pending_req);
                                scsiback_do_resp_with_sense(NULL,
                                        DRIVER_ERROR << 24, 0, pending_req);
@@ -768,7 +766,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
                        break;
                case VSCSIIF_ACT_SCSI_ABORT:
                        scsiback_device_action(pending_req, TMR_ABORT_TASK,
-                               ring_req->ref_rqid);
+                               ring_req.ref_rqid);
                        break;
                case VSCSIIF_ACT_SCSI_RESET:
                        scsiback_device_action(pending_req, TMR_LUN_RESET, 0);
@@ -1661,11 +1659,8 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg,
                         name);
                goto out;
        }
-       /*
-        * Now register the TCM pvscsi virtual I_T Nexus as active with the
-        * call to __transport_register_session()
-        */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       /* Now register the TCM pvscsi virtual I_T Nexus as active. */
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
 
index d2468bf95669850520a2a0dc852b1185c5234c7b..a91795e01a7ff0c0e85abf1bdf69f3d1d828b231 100644 (file)
@@ -699,8 +699,10 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
        boff = tmp % bsize;
        if (boff) {
                bh = affs_bread_ino(inode, bidx, 0);
-               if (IS_ERR(bh))
-                       return PTR_ERR(bh);
+               if (IS_ERR(bh)) {
+                       written = PTR_ERR(bh);
+                       goto err_first_bh;
+               }
                tmp = min(bsize - boff, to - from);
                BUG_ON(boff + tmp > bsize || tmp > bsize);
                memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
@@ -712,14 +714,16 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
                bidx++;
        } else if (bidx) {
                bh = affs_bread_ino(inode, bidx - 1, 0);
-               if (IS_ERR(bh))
-                       return PTR_ERR(bh);
+               if (IS_ERR(bh)) {
+                       written = PTR_ERR(bh);
+                       goto err_first_bh;
+               }
        }
        while (from + bsize <= to) {
                prev_bh = bh;
                bh = affs_getemptyblk_ino(inode, bidx);
                if (IS_ERR(bh))
-                       goto out;
+                       goto err_bh;
                memcpy(AFFS_DATA(bh), data + from, bsize);
                if (buffer_new(bh)) {
                        AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
@@ -751,7 +755,7 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
                prev_bh = bh;
                bh = affs_bread_ino(inode, bidx, 1);
                if (IS_ERR(bh))
-                       goto out;
+                       goto err_bh;
                tmp = min(bsize, to - from);
                BUG_ON(tmp > bsize);
                memcpy(AFFS_DATA(bh), data + from, tmp);
@@ -790,12 +794,13 @@ done:
        if (tmp > inode->i_size)
                inode->i_size = AFFS_I(inode)->mmu_private = tmp;
 
+err_first_bh:
        unlock_page(page);
        page_cache_release(page);
 
        return written;
 
-out:
+err_bh:
        bh = prev_bh;
        if (!written)
                written = PTR_ERR(bh);
index 993642199326a757f55c78dbc2722ecc2b409b60..6d67f32e648df72bc5f5b5d707ff39ce8fa4302b 100644 (file)
@@ -1645,14 +1645,14 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 
        parent_nritems = btrfs_header_nritems(parent);
        blocksize = root->nodesize;
-       end_slot = parent_nritems;
+       end_slot = parent_nritems - 1;
 
-       if (parent_nritems == 1)
+       if (parent_nritems <= 1)
                return 0;
 
        btrfs_set_lock_blocking(parent);
 
-       for (i = start_slot; i < end_slot; i++) {
+       for (i = start_slot; i <= end_slot; i++) {
                int close = 1;
 
                btrfs_node_key(parent, &disk_key, i);
@@ -1669,7 +1669,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                        other = btrfs_node_blockptr(parent, i - 1);
                        close = close_blocks(blocknr, other, blocksize);
                }
-               if (!close && i < end_slot - 2) {
+               if (!close && i < end_slot) {
                        other = btrfs_node_blockptr(parent, i + 1);
                        close = close_blocks(blocknr, other, blocksize);
                }
index 84c3b00f3de8eedf47ba3bec71939a5fba1f90a0..f9c89cae39ee41fd6ae37bbc36178f8eb9093044 100644 (file)
@@ -3387,6 +3387,8 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                    struct btrfs_root *root);
+int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root);
 int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr);
 int btrfs_free_block_groups(struct btrfs_fs_info *info);
 int btrfs_read_block_groups(struct btrfs_root *root);
@@ -3909,6 +3911,9 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
                                    loff_t actual_len, u64 *alloc_hint);
 int btrfs_inode_check_errors(struct inode *inode);
 extern const struct dentry_operations btrfs_dentry_operations;
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+void btrfs_test_inode_set_ops(struct inode *inode);
+#endif
 
 /* ioctl.c */
 long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
index f79f38542a737631e191e08aed6b50d4a940f964..639f2663ed3f8f40dc925451618702632e8b9109 100644 (file)
@@ -3921,7 +3921,7 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
        }
        if (btrfs_super_sys_array_size(sb) < sizeof(struct btrfs_disk_key)
                        + sizeof(struct btrfs_chunk)) {
-               printk(KERN_ERR "BTRFS: system chunk array too small %u < %lu\n",
+               printk(KERN_ERR "BTRFS: system chunk array too small %u < %zu\n",
                                btrfs_super_sys_array_size(sb),
                                sizeof(struct btrfs_disk_key)
                                + sizeof(struct btrfs_chunk));
index 571f402d3fc46e5f0205451e85a7b78f3cc16b50..8b353ad02f034a9307e1da5d8923aff6b43a0dcb 100644 (file)
@@ -3208,6 +3208,8 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
                return 0;
        }
 
+       if (trans->aborted)
+               return 0;
 again:
        inode = lookup_free_space_inode(root, block_group, path);
        if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
@@ -3243,6 +3245,20 @@ again:
         */
        BTRFS_I(inode)->generation = 0;
        ret = btrfs_update_inode(trans, root, inode);
+       if (ret) {
+               /*
+                * So theoretically we could recover from this, simply set the
+                * super cache generation to 0 so we know to invalidate the
+                * cache, but then we'd have to keep track of the block groups
+                * that fail this way so we know we _have_ to reset this cache
+                * before the next commit or risk reading stale cache.  So to
+                * limit our exposure to horrible edge cases lets just abort the
+                * transaction, this only happens in really bad situations
+                * anyway.
+                */
+               btrfs_abort_transaction(trans, root, ret);
+               goto out_put;
+       }
        WARN_ON(ret);
 
        if (i_size_read(inode) > 0) {
@@ -3309,6 +3325,32 @@ out:
        return ret;
 }
 
+int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root)
+{
+       struct btrfs_block_group_cache *cache, *tmp;
+       struct btrfs_transaction *cur_trans = trans->transaction;
+       struct btrfs_path *path;
+
+       if (list_empty(&cur_trans->dirty_bgs) ||
+           !btrfs_test_opt(root, SPACE_CACHE))
+               return 0;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       /* Could add new block groups, use _safe just in case */
+       list_for_each_entry_safe(cache, tmp, &cur_trans->dirty_bgs,
+                                dirty_list) {
+               if (cache->disk_cache_state == BTRFS_DC_CLEAR)
+                       cache_save_setup(cache, trans, path);
+       }
+
+       btrfs_free_path(path);
+       return 0;
+}
+
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root)
 {
@@ -5094,7 +5136,11 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        num_bytes = ALIGN(num_bytes, root->sectorsize);
 
        spin_lock(&BTRFS_I(inode)->lock);
-       BTRFS_I(inode)->outstanding_extents++;
+       nr_extents = (unsigned)div64_u64(num_bytes +
+                                        BTRFS_MAX_EXTENT_SIZE - 1,
+                                        BTRFS_MAX_EXTENT_SIZE);
+       BTRFS_I(inode)->outstanding_extents += nr_extents;
+       nr_extents = 0;
 
        if (BTRFS_I(inode)->outstanding_extents >
            BTRFS_I(inode)->reserved_extents)
@@ -5239,6 +5285,9 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
        if (dropped > 0)
                to_free += btrfs_calc_trans_metadata_size(root, dropped);
 
+       if (btrfs_test_is_dummy_root(root))
+               return;
+
        trace_btrfs_space_reservation(root->fs_info, "delalloc",
                                      btrfs_ino(inode), to_free, 0);
        if (root->fs_info->quota_enabled) {
index c7233ff1d533b653b8b9e7f29e022e9126e5f38a..d688cfe5d4962ddf626e97a36fc8136edd7922b9 100644 (file)
@@ -4968,6 +4968,12 @@ static int release_extent_buffer(struct extent_buffer *eb)
 
                /* Should be safe to release our pages at this point */
                btrfs_release_extent_buffer_page(eb);
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+               if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags))) {
+                       __free_extent_buffer(eb);
+                       return 1;
+               }
+#endif
                call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu);
                return 1;
        }
index b78bbbac900db833e54fc63bdbff8bae365225f3..30982bbd31c30c2b154836b0f51b94c37e22923c 100644 (file)
@@ -1811,22 +1811,10 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
        mutex_unlock(&inode->i_mutex);
 
        /*
-        * we want to make sure fsync finds this change
-        * but we haven't joined a transaction running right now.
-        *
-        * Later on, someone is sure to update the inode and get the
-        * real transid recorded.
-        *
-        * We set last_trans now to the fs_info generation + 1,
-        * this will either be one more than the running transaction
-        * or the generation used for the next transaction if there isn't
-        * one running right now.
-        *
         * We also have to set last_sub_trans to the current log transid,
         * otherwise subsequent syncs to a file that's been synced in this
         * transaction will appear to have already occured.
         */
-       BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
        BTRFS_I(inode)->last_sub_trans = root->log_transid;
        if (num_written > 0) {
                err = generic_write_sync(file, pos, num_written);
@@ -1959,25 +1947,37 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        atomic_inc(&root->log_batch);
 
        /*
-        * check the transaction that last modified this inode
-        * and see if its already been committed
-        */
-       if (!BTRFS_I(inode)->last_trans) {
-               mutex_unlock(&inode->i_mutex);
-               goto out;
-       }
-
-       /*
-        * if the last transaction that changed this file was before
-        * the current transaction, we can bail out now without any
-        * syncing
+        * If the last transaction that changed this file was before the current
+        * transaction and we have the full sync flag set in our inode, we can
+        * bail out now without any syncing.
+        *
+        * Note that we can't bail out if the full sync flag isn't set. This is
+        * because when the full sync flag is set we start all ordered extents
+        * and wait for them to fully complete - when they complete they update
+        * the inode's last_trans field through:
+        *
+        *     btrfs_finish_ordered_io() ->
+        *         btrfs_update_inode_fallback() ->
+        *             btrfs_update_inode() ->
+        *                 btrfs_set_inode_last_trans()
+        *
+        * So we are sure that last_trans is up to date and can do this check to
+        * bail out safely. For the fast path, when the full sync flag is not
+        * set in our inode, we can not do it because we start only our ordered
+        * extents and don't wait for them to complete (that is when
+        * btrfs_finish_ordered_io runs), so here at this point their last_trans
+        * value might be less than or equals to fs_info->last_trans_committed,
+        * and setting a speculative last_trans for an inode when a buffered
+        * write is made (such as fs_info->generation + 1 for example) would not
+        * be reliable since after setting the value and before fsync is called
+        * any number of transactions can start and commit (transaction kthread
+        * commits the current transaction periodically), and a transaction
+        * commit does not start nor waits for ordered extents to complete.
         */
        smp_mb();
        if (btrfs_inode_in_log(inode, root->fs_info->generation) ||
-           BTRFS_I(inode)->last_trans <=
-           root->fs_info->last_trans_committed) {
-               BTRFS_I(inode)->last_trans = 0;
-
+           (full_sync && BTRFS_I(inode)->last_trans <=
+            root->fs_info->last_trans_committed)) {
                /*
                 * We'v had everything committed since the last time we were
                 * modified so clear this flag in case it was set for whatever
@@ -2275,6 +2275,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        bool same_page;
        bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
        u64 ino_size;
+       bool truncated_page = false;
+       bool updated_inode = false;
 
        ret = btrfs_wait_ordered_range(inode, offset, len);
        if (ret)
@@ -2306,13 +2308,18 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
         * entire page.
         */
        if (same_page && len < PAGE_CACHE_SIZE) {
-               if (offset < ino_size)
+               if (offset < ino_size) {
+                       truncated_page = true;
                        ret = btrfs_truncate_page(inode, offset, len, 0);
+               } else {
+                       ret = 0;
+               }
                goto out_only_mutex;
        }
 
        /* zero back part of the first page */
        if (offset < ino_size) {
+               truncated_page = true;
                ret = btrfs_truncate_page(inode, offset, 0, 0);
                if (ret) {
                        mutex_unlock(&inode->i_mutex);
@@ -2348,6 +2355,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
                if (!ret) {
                        /* zero the front end of the last page */
                        if (tail_start + tail_len < ino_size) {
+                               truncated_page = true;
                                ret = btrfs_truncate_page(inode,
                                                tail_start + tail_len, 0, 1);
                                if (ret)
@@ -2357,8 +2365,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        }
 
        if (lockend < lockstart) {
-               mutex_unlock(&inode->i_mutex);
-               return 0;
+               ret = 0;
+               goto out_only_mutex;
        }
 
        while (1) {
@@ -2506,6 +2514,7 @@ out_trans:
 
        trans->block_rsv = &root->fs_info->trans_block_rsv;
        ret = btrfs_update_inode(trans, root, inode);
+       updated_inode = true;
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root);
 out_free:
@@ -2515,6 +2524,22 @@ out:
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                             &cached_state, GFP_NOFS);
 out_only_mutex:
+       if (!updated_inode && truncated_page && !ret && !err) {
+               /*
+                * If we only end up zeroing part of a page, we still need to
+                * update the inode item, so that all the time fields are
+                * updated as well as the necessary btrfs inode in memory fields
+                * for detecting, at fsync time, if the inode isn't yet in the
+                * log tree or it's there but not up to date.
+                */
+               trans = btrfs_start_transaction(root, 1);
+               if (IS_ERR(trans)) {
+                       err = PTR_ERR(trans);
+               } else {
+                       err = btrfs_update_inode(trans, root, inode);
+                       ret = btrfs_end_transaction(trans, root);
+               }
+       }
        mutex_unlock(&inode->i_mutex);
        if (ret && !err)
                err = ret;
index a85c23dfcddbcfd992069811f24b116d74e4dc21..d2e732d7af524640bc2c197da3e7123182b4537e 100644 (file)
@@ -108,6 +108,13 @@ static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
 
 static int btrfs_dirty_inode(struct inode *inode);
 
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+void btrfs_test_inode_set_ops(struct inode *inode)
+{
+       BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
+}
+#endif
+
 static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
                                     struct inode *inode,  struct inode *dir,
                                     const struct qstr *qstr)
@@ -1542,30 +1549,17 @@ static void btrfs_split_extent_hook(struct inode *inode,
                u64 new_size;
 
                /*
-                * We need the largest size of the remaining extent to see if we
-                * need to add a new outstanding extent.  Think of the following
-                * case
-                *
-                * [MEAX_EXTENT_SIZEx2 - 4k][4k]
-                *
-                * The new_size would just be 4k and we'd think we had enough
-                * outstanding extents for this if we only took one side of the
-                * split, same goes for the other direction.  We need to see if
-                * the larger size still is the same amount of extents as the
-                * original size, because if it is we need to add a new
-                * outstanding extent.  But if we split up and the larger size
-                * is less than the original then we are good to go since we've
-                * already accounted for the extra extent in our original
-                * accounting.
+                * See the explanation in btrfs_merge_extent_hook, the same
+                * applies here, just in reverse.
                 */
                new_size = orig->end - split + 1;
-               if ((split - orig->start) > new_size)
-                       new_size = split - orig->start;
-
-               num_extents = div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1,
+               num_extents = div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
                                        BTRFS_MAX_EXTENT_SIZE);
-               if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
-                             BTRFS_MAX_EXTENT_SIZE) < num_extents)
+               new_size = split - orig->start;
+               num_extents += div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
+                                       BTRFS_MAX_EXTENT_SIZE);
+               if (div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1,
+                             BTRFS_MAX_EXTENT_SIZE) >= num_extents)
                        return;
        }
 
@@ -1591,8 +1585,10 @@ static void btrfs_merge_extent_hook(struct inode *inode,
        if (!(other->state & EXTENT_DELALLOC))
                return;
 
-       old_size = other->end - other->start + 1;
-       new_size = old_size + (new->end - new->start + 1);
+       if (new->start > other->start)
+               new_size = new->end - other->start + 1;
+       else
+               new_size = other->end - new->start + 1;
 
        /* we're not bigger than the max, unreserve the space and go */
        if (new_size <= BTRFS_MAX_EXTENT_SIZE) {
@@ -1603,13 +1599,32 @@ static void btrfs_merge_extent_hook(struct inode *inode,
        }
 
        /*
-        * If we grew by another max_extent, just return, we want to keep that
-        * reserved amount.
+        * We have to add up either side to figure out how many extents were
+        * accounted for before we merged into one big extent.  If the number of
+        * extents we accounted for is <= the amount we need for the new range
+        * then we can return, otherwise drop.  Think of it like this
+        *
+        * [ 4k][MAX_SIZE]
+        *
+        * So we've grown the extent by a MAX_SIZE extent, this would mean we
+        * need 2 outstanding extents, on one side we have 1 and the other side
+        * we have 1 so they are == and we can return.  But in this case
+        *
+        * [MAX_SIZE+4k][MAX_SIZE+4k]
+        *
+        * Each range on their own accounts for 2 extents, but merged together
+        * they are only 3 extents worth of accounting, so we need to drop in
+        * this case.
         */
+       old_size = other->end - other->start + 1;
        num_extents = div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1,
                                BTRFS_MAX_EXTENT_SIZE);
+       old_size = new->end - new->start + 1;
+       num_extents += div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1,
+                                BTRFS_MAX_EXTENT_SIZE);
+
        if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
-                     BTRFS_MAX_EXTENT_SIZE) > num_extents)
+                     BTRFS_MAX_EXTENT_SIZE) >= num_extents)
                return;
 
        spin_lock(&BTRFS_I(inode)->lock);
@@ -1686,6 +1701,10 @@ static void btrfs_set_bit_hook(struct inode *inode,
                        spin_unlock(&BTRFS_I(inode)->lock);
                }
 
+               /* For sanity tests */
+               if (btrfs_test_is_dummy_root(root))
+                       return;
+
                __percpu_counter_add(&root->fs_info->delalloc_bytes, len,
                                     root->fs_info->delalloc_batch);
                spin_lock(&BTRFS_I(inode)->lock);
@@ -1741,6 +1760,10 @@ static void btrfs_clear_bit_hook(struct inode *inode,
                    root != root->fs_info->tree_root)
                        btrfs_delalloc_release_metadata(inode, len);
 
+               /* For sanity tests. */
+               if (btrfs_test_is_dummy_root(root))
+                       return;
+
                if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
                    && do_list && !(state->state & EXTENT_NORESERVE))
                        btrfs_free_reserved_data_space(inode, len);
@@ -7213,7 +7236,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
        u64 start = iblock << inode->i_blkbits;
        u64 lockstart, lockend;
        u64 len = bh_result->b_size;
-       u64 orig_len = len;
+       u64 *outstanding_extents = NULL;
        int unlock_bits = EXTENT_LOCKED;
        int ret = 0;
 
@@ -7225,6 +7248,16 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
        lockstart = start;
        lockend = start + len - 1;
 
+       if (current->journal_info) {
+               /*
+                * Need to pull our outstanding extents and set journal_info to NULL so
+                * that anything that needs to check if there's a transction doesn't get
+                * confused.
+                */
+               outstanding_extents = current->journal_info;
+               current->journal_info = NULL;
+       }
+
        /*
         * If this errors out it's because we couldn't invalidate pagecache for
         * this range and we need to fallback to buffered.
@@ -7285,7 +7318,6 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
            ((BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) &&
             em->block_start != EXTENT_MAP_HOLE)) {
                int type;
-               int ret;
                u64 block_start, orig_start, orig_block_len, ram_bytes;
 
                if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
@@ -7349,11 +7381,20 @@ unlock:
                if (start + len > i_size_read(inode))
                        i_size_write(inode, start + len);
 
-               if (len < orig_len) {
+               /*
+                * If we have an outstanding_extents count still set then we're
+                * within our reservation, otherwise we need to adjust our inode
+                * counter appropriately.
+                */
+               if (*outstanding_extents) {
+                       (*outstanding_extents)--;
+               } else {
                        spin_lock(&BTRFS_I(inode)->lock);
                        BTRFS_I(inode)->outstanding_extents++;
                        spin_unlock(&BTRFS_I(inode)->lock);
                }
+
+               current->journal_info = outstanding_extents;
                btrfs_free_reserved_data_space(inode, len);
        }
 
@@ -7377,6 +7418,8 @@ unlock:
 unlock_err:
        clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                         unlock_bits, 1, 0, &cached_state, GFP_NOFS);
+       if (outstanding_extents)
+               current->journal_info = outstanding_extents;
        return ret;
 }
 
@@ -8076,6 +8119,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
+       u64 outstanding_extents = 0;
        size_t count = 0;
        int flags = 0;
        bool wakeup = true;
@@ -8113,6 +8157,16 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                ret = btrfs_delalloc_reserve_space(inode, count);
                if (ret)
                        goto out;
+               outstanding_extents = div64_u64(count +
+                                               BTRFS_MAX_EXTENT_SIZE - 1,
+                                               BTRFS_MAX_EXTENT_SIZE);
+
+               /*
+                * We need to know how many extents we reserved so that we can
+                * do the accounting properly if we go over the number we
+                * originally calculated.  Abuse current->journal_info for this.
+                */
+               current->journal_info = &outstanding_extents;
        } else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK,
                                     &BTRFS_I(inode)->runtime_flags)) {
                inode_dio_done(inode);
@@ -8125,6 +8179,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                        iter, offset, btrfs_get_blocks_direct, NULL,
                        btrfs_submit_direct, flags);
        if (rw & WRITE) {
+               current->journal_info = NULL;
                if (ret < 0 && ret != -EIOCBQUEUED)
                        btrfs_delalloc_release_space(inode, count);
                else if (ret >= 0 && (size_t)ret < count)
index 534544e08f769486a97c3c7f3719bed982500783..157cc54fc63486e485a95bf6d8d6da692ef171ca 100644 (file)
@@ -452,9 +452,7 @@ void btrfs_get_logged_extents(struct inode *inode,
                        continue;
                if (entry_end(ordered) <= start)
                        break;
-               if (!list_empty(&ordered->log_list))
-                       continue;
-               if (test_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
+               if (test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
                        continue;
                list_add(&ordered->log_list, logged_list);
                atomic_inc(&ordered->refs);
@@ -511,8 +509,7 @@ void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans,
                wait_event(ordered->wait, test_bit(BTRFS_ORDERED_IO_DONE,
                                                   &ordered->flags));
 
-               if (!test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
-                       list_add_tail(&ordered->trans_list, &trans->ordered);
+               list_add_tail(&ordered->trans_list, &trans->ordered);
                spin_lock_irq(&log->log_extents_lock[index]);
        }
        spin_unlock_irq(&log->log_extents_lock[index]);
index 97159a8e91d40b24ca1a8f6367892ecf2ad8b960..058c79eecbfb96825918a370e3f78d926b49b098 100644 (file)
@@ -1259,7 +1259,7 @@ static int comp_oper(struct btrfs_qgroup_operation *oper1,
        if (oper1->seq < oper2->seq)
                return -1;
        if (oper1->seq > oper2->seq)
-               return -1;
+               return 1;
        if (oper1->ref_root < oper2->ref_root)
                return -1;
        if (oper1->ref_root > oper2->ref_root)
index fe5857223515d14753c1f75ce60c2c12e16a3e67..d6033f540cc75cfb49ddbe5f07689d67fdefc492 100644 (file)
@@ -230,6 +230,7 @@ struct pending_dir_move {
        u64 parent_ino;
        u64 ino;
        u64 gen;
+       bool is_orphan;
        struct list_head update_refs;
 };
 
@@ -2984,7 +2985,8 @@ static int add_pending_dir_move(struct send_ctx *sctx,
                                u64 ino_gen,
                                u64 parent_ino,
                                struct list_head *new_refs,
-                               struct list_head *deleted_refs)
+                               struct list_head *deleted_refs,
+                               const bool is_orphan)
 {
        struct rb_node **p = &sctx->pending_dir_moves.rb_node;
        struct rb_node *parent = NULL;
@@ -2999,6 +3001,7 @@ static int add_pending_dir_move(struct send_ctx *sctx,
        pm->parent_ino = parent_ino;
        pm->ino = ino;
        pm->gen = ino_gen;
+       pm->is_orphan = is_orphan;
        INIT_LIST_HEAD(&pm->list);
        INIT_LIST_HEAD(&pm->update_refs);
        RB_CLEAR_NODE(&pm->node);
@@ -3131,16 +3134,20 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
        rmdir_ino = dm->rmdir_ino;
        free_waiting_dir_move(sctx, dm);
 
-       ret = get_first_ref(sctx->parent_root, pm->ino,
-                           &parent_ino, &parent_gen, name);
-       if (ret < 0)
-               goto out;
-
-       ret = get_cur_path(sctx, parent_ino, parent_gen,
-                          from_path);
-       if (ret < 0)
-               goto out;
-       ret = fs_path_add_path(from_path, name);
+       if (pm->is_orphan) {
+               ret = gen_unique_name(sctx, pm->ino,
+                                     pm->gen, from_path);
+       } else {
+               ret = get_first_ref(sctx->parent_root, pm->ino,
+                                   &parent_ino, &parent_gen, name);
+               if (ret < 0)
+                       goto out;
+               ret = get_cur_path(sctx, parent_ino, parent_gen,
+                                  from_path);
+               if (ret < 0)
+                       goto out;
+               ret = fs_path_add_path(from_path, name);
+       }
        if (ret < 0)
                goto out;
 
@@ -3150,7 +3157,8 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
                LIST_HEAD(deleted_refs);
                ASSERT(ancestor > BTRFS_FIRST_FREE_OBJECTID);
                ret = add_pending_dir_move(sctx, pm->ino, pm->gen, ancestor,
-                                          &pm->update_refs, &deleted_refs);
+                                          &pm->update_refs, &deleted_refs,
+                                          pm->is_orphan);
                if (ret < 0)
                        goto out;
                if (rmdir_ino) {
@@ -3283,6 +3291,127 @@ out:
        return ret;
 }
 
+/*
+ * We might need to delay a directory rename even when no ancestor directory
+ * (in the send root) with a higher inode number than ours (sctx->cur_ino) was
+ * renamed. This happens when we rename a directory to the old name (the name
+ * in the parent root) of some other unrelated directory that got its rename
+ * delayed due to some ancestor with higher number that got renamed.
+ *
+ * Example:
+ *
+ * Parent snapshot:
+ * .                                       (ino 256)
+ * |---- a/                                (ino 257)
+ * |     |---- file                        (ino 260)
+ * |
+ * |---- b/                                (ino 258)
+ * |---- c/                                (ino 259)
+ *
+ * Send snapshot:
+ * .                                       (ino 256)
+ * |---- a/                                (ino 258)
+ * |---- x/                                (ino 259)
+ *       |---- y/                          (ino 257)
+ *             |----- file                 (ino 260)
+ *
+ * Here we can not rename 258 from 'b' to 'a' without the rename of inode 257
+ * from 'a' to 'x/y' happening first, which in turn depends on the rename of
+ * inode 259 from 'c' to 'x'. So the order of rename commands the send stream
+ * must issue is:
+ *
+ * 1 - rename 259 from 'c' to 'x'
+ * 2 - rename 257 from 'a' to 'x/y'
+ * 3 - rename 258 from 'b' to 'a'
+ *
+ * Returns 1 if the rename of sctx->cur_ino needs to be delayed, 0 if it can
+ * be done right away and < 0 on error.
+ */
+static int wait_for_dest_dir_move(struct send_ctx *sctx,
+                                 struct recorded_ref *parent_ref,
+                                 const bool is_orphan)
+{
+       struct btrfs_path *path;
+       struct btrfs_key key;
+       struct btrfs_key di_key;
+       struct btrfs_dir_item *di;
+       u64 left_gen;
+       u64 right_gen;
+       int ret = 0;
+
+       if (RB_EMPTY_ROOT(&sctx->waiting_dir_moves))
+               return 0;
+
+       path = alloc_path_for_send();
+       if (!path)
+               return -ENOMEM;
+
+       key.objectid = parent_ref->dir;
+       key.type = BTRFS_DIR_ITEM_KEY;
+       key.offset = btrfs_name_hash(parent_ref->name, parent_ref->name_len);
+
+       ret = btrfs_search_slot(NULL, sctx->parent_root, &key, path, 0, 0);
+       if (ret < 0) {
+               goto out;
+       } else if (ret > 0) {
+               ret = 0;
+               goto out;
+       }
+
+       di = btrfs_match_dir_item_name(sctx->parent_root, path,
+                                      parent_ref->name, parent_ref->name_len);
+       if (!di) {
+               ret = 0;
+               goto out;
+       }
+       /*
+        * di_key.objectid has the number of the inode that has a dentry in the
+        * parent directory with the same name that sctx->cur_ino is being
+        * renamed to. We need to check if that inode is in the send root as
+        * well and if it is currently marked as an inode with a pending rename,
+        * if it is, we need to delay the rename of sctx->cur_ino as well, so
+        * that it happens after that other inode is renamed.
+        */
+       btrfs_dir_item_key_to_cpu(path->nodes[0], di, &di_key);
+       if (di_key.type != BTRFS_INODE_ITEM_KEY) {
+               ret = 0;
+               goto out;
+       }
+
+       ret = get_inode_info(sctx->parent_root, di_key.objectid, NULL,
+                            &left_gen, NULL, NULL, NULL, NULL);
+       if (ret < 0)
+               goto out;
+       ret = get_inode_info(sctx->send_root, di_key.objectid, NULL,
+                            &right_gen, NULL, NULL, NULL, NULL);
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       ret = 0;
+               goto out;
+       }
+
+       /* Different inode, no need to delay the rename of sctx->cur_ino */
+       if (right_gen != left_gen) {
+               ret = 0;
+               goto out;
+       }
+
+       if (is_waiting_for_move(sctx, di_key.objectid)) {
+               ret = add_pending_dir_move(sctx,
+                                          sctx->cur_ino,
+                                          sctx->cur_inode_gen,
+                                          di_key.objectid,
+                                          &sctx->new_refs,
+                                          &sctx->deleted_refs,
+                                          is_orphan);
+               if (!ret)
+                       ret = 1;
+       }
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
 static int wait_for_parent_move(struct send_ctx *sctx,
                                struct recorded_ref *parent_ref)
 {
@@ -3349,7 +3478,8 @@ out:
                                           sctx->cur_inode_gen,
                                           ino,
                                           &sctx->new_refs,
-                                          &sctx->deleted_refs);
+                                          &sctx->deleted_refs,
+                                          false);
                if (!ret)
                        ret = 1;
        }
@@ -3372,6 +3502,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
        int did_overwrite = 0;
        int is_orphan = 0;
        u64 last_dir_ino_rm = 0;
+       bool can_rename = true;
 
 verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
 
@@ -3490,12 +3621,22 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                        }
                }
 
+               if (S_ISDIR(sctx->cur_inode_mode) && sctx->parent_root) {
+                       ret = wait_for_dest_dir_move(sctx, cur, is_orphan);
+                       if (ret < 0)
+                               goto out;
+                       if (ret == 1) {
+                               can_rename = false;
+                               *pending_move = 1;
+                       }
+               }
+
                /*
                 * link/move the ref to the new place. If we have an orphan
                 * inode, move it and update valid_path. If not, link or move
                 * it depending on the inode mode.
                 */
-               if (is_orphan) {
+               if (is_orphan && can_rename) {
                        ret = send_rename(sctx, valid_path, cur->full_path);
                        if (ret < 0)
                                goto out;
@@ -3503,7 +3644,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                        ret = fs_path_copy(valid_path, cur->full_path);
                        if (ret < 0)
                                goto out;
-               } else {
+               } else if (can_rename) {
                        if (S_ISDIR(sctx->cur_inode_mode)) {
                                /*
                                 * Dirs can't be linked, so move it. For moved
index a116b55ce7880a5e64837dfd6cd66f7412e27cec..054fc0d97131b239486a47a5b8ef4b3f120c2e6b 100644 (file)
@@ -911,6 +911,197 @@ out:
        return ret;
 }
 
+static int test_extent_accounting(void)
+{
+       struct inode *inode = NULL;
+       struct btrfs_root *root = NULL;
+       int ret = -ENOMEM;
+
+       inode = btrfs_new_test_inode();
+       if (!inode) {
+               test_msg("Couldn't allocate inode\n");
+               return ret;
+       }
+
+       root = btrfs_alloc_dummy_root();
+       if (IS_ERR(root)) {
+               test_msg("Couldn't allocate root\n");
+               goto out;
+       }
+
+       root->fs_info = btrfs_alloc_dummy_fs_info();
+       if (!root->fs_info) {
+               test_msg("Couldn't allocate dummy fs info\n");
+               goto out;
+       }
+
+       BTRFS_I(inode)->root = root;
+       btrfs_test_inode_set_ops(inode);
+
+       /* [BTRFS_MAX_EXTENT_SIZE] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, 0, BTRFS_MAX_EXTENT_SIZE - 1,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 1) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 1, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE][4k] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE,
+                                       BTRFS_MAX_EXTENT_SIZE + 4095, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE/2][4K HOLE][the rest] */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree,
+                              BTRFS_MAX_EXTENT_SIZE >> 1,
+                              (BTRFS_MAX_EXTENT_SIZE >> 1) + 4095,
+                              EXTENT_DELALLOC | EXTENT_DIRTY |
+                              EXTENT_UPTODATE | EXTENT_DO_ACCOUNTING, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE][4K] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE >> 1,
+                                       (BTRFS_MAX_EXTENT_SIZE >> 1) + 4095,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /*
+        * [BTRFS_MAX_EXTENT_SIZE+4K][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4K]
+        *
+        * I'm artificially adding 2 to outstanding_extents because in the
+        * buffered IO case we'd add things up as we go, but I don't feel like
+        * doing that here, this isn't the interesting case we want to test.
+        */
+       BTRFS_I(inode)->outstanding_extents += 2;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE + 8192,
+                                       (BTRFS_MAX_EXTENT_SIZE << 1) + 12287,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 4) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 4, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE+4k][4k][BTRFS_MAX_EXTENT_SIZE+4k] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE+4096,
+                                       BTRFS_MAX_EXTENT_SIZE+8191, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 3) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 3, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE+4k][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4k] */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree,
+                              BTRFS_MAX_EXTENT_SIZE+4096,
+                              BTRFS_MAX_EXTENT_SIZE+8191,
+                              EXTENT_DIRTY | EXTENT_DELALLOC |
+                              EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 4) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 4, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /*
+        * Refill the hole again just for good measure, because I thought it
+        * might fail and I'd rather satisfy my paranoia at this point.
+        */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE+4096,
+                                       BTRFS_MAX_EXTENT_SIZE+8191, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 3) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 3, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* Empty */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
+                              EXTENT_DIRTY | EXTENT_DELALLOC |
+                              EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 0, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+       ret = 0;
+out:
+       if (ret)
+               clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
+                                EXTENT_DIRTY | EXTENT_DELALLOC |
+                                EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                                NULL, GFP_NOFS);
+       iput(inode);
+       btrfs_free_dummy_root(root);
+       return ret;
+}
+
 int btrfs_test_inodes(void)
 {
        int ret;
@@ -924,5 +1115,9 @@ int btrfs_test_inodes(void)
        if (ret)
                return ret;
        test_msg("Running hole first btrfs_get_extent test\n");
-       return test_hole_first();
+       ret = test_hole_first();
+       if (ret)
+               return ret;
+       test_msg("Running outstanding_extents tests\n");
+       return test_extent_accounting();
 }
index 7e80f32550a663e7438d3e5fb8b1c37fcc391b64..8be4278e25e8e06e32d52b5ac412201d7b20a53c 100644 (file)
@@ -1023,17 +1023,13 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
        u64 old_root_bytenr;
        u64 old_root_used;
        struct btrfs_root *tree_root = root->fs_info->tree_root;
-       bool extent_root = (root->objectid == BTRFS_EXTENT_TREE_OBJECTID);
 
        old_root_used = btrfs_root_used(&root->root_item);
-       btrfs_write_dirty_block_groups(trans, root);
 
        while (1) {
                old_root_bytenr = btrfs_root_bytenr(&root->root_item);
                if (old_root_bytenr == root->node->start &&
-                   old_root_used == btrfs_root_used(&root->root_item) &&
-                   (!extent_root ||
-                    list_empty(&trans->transaction->dirty_bgs)))
+                   old_root_used == btrfs_root_used(&root->root_item))
                        break;
 
                btrfs_set_root_node(&root->root_item, root->node);
@@ -1044,17 +1040,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
                        return ret;
 
                old_root_used = btrfs_root_used(&root->root_item);
-               if (extent_root) {
-                       ret = btrfs_write_dirty_block_groups(trans, root);
-                       if (ret)
-                               return ret;
-               }
-               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-               if (ret)
-                       return ret;
-               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-               if (ret)
-                       return ret;
        }
 
        return 0;
@@ -1071,6 +1056,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                                         struct btrfs_root *root)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
+       struct list_head *dirty_bgs = &trans->transaction->dirty_bgs;
        struct list_head *next;
        struct extent_buffer *eb;
        int ret;
@@ -1098,11 +1084,15 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
        if (ret)
                return ret;
 
+       ret = btrfs_setup_space_cache(trans, root);
+       if (ret)
+               return ret;
+
        /* run_qgroups might have added some more refs */
        ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
        if (ret)
                return ret;
-
+again:
        while (!list_empty(&fs_info->dirty_cowonly_roots)) {
                next = fs_info->dirty_cowonly_roots.next;
                list_del_init(next);
@@ -1115,8 +1105,23 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                ret = update_cowonly_root(trans, root);
                if (ret)
                        return ret;
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               if (ret)
+                       return ret;
        }
 
+       while (!list_empty(dirty_bgs)) {
+               ret = btrfs_write_dirty_block_groups(trans, root);
+               if (ret)
+                       return ret;
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               if (ret)
+                       return ret;
+       }
+
+       if (!list_empty(&fs_info->dirty_cowonly_roots))
+               goto again;
+
        list_add_tail(&fs_info->extent_root->dirty_list,
                      &trans->transaction->switch_commits);
        btrfs_after_dev_replace_commit(fs_info);
@@ -1814,6 +1819,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
                wait_for_commit(root, cur_trans);
 
+               if (unlikely(cur_trans->aborted))
+                       ret = cur_trans->aborted;
+
                btrfs_put_transaction(cur_trans);
 
                return ret;
index 9a37f8b39bae9058a20aafe11c59793409115005..c5b8ba37f88e31fa188258af9c6e13036c2df18f 100644 (file)
@@ -1012,7 +1012,7 @@ again:
                base = btrfs_item_ptr_offset(leaf, path->slots[0]);
 
                while (cur_offset < item_size) {
-                       extref = (struct btrfs_inode_extref *)base + cur_offset;
+                       extref = (struct btrfs_inode_extref *)(base + cur_offset);
 
                        victim_name_len = btrfs_inode_extref_name_len(leaf, extref);
 
index cd4d1315aaa92d43476a9e86c521e94a04519d0e..8222f6f74147972ba1b654c12b013c55a3b60825 100644 (file)
@@ -4903,10 +4903,17 @@ static void sort_parity_stripes(struct btrfs_bio *bbio, int num_stripes)
 static struct btrfs_bio *alloc_btrfs_bio(int total_stripes, int real_stripes)
 {
        struct btrfs_bio *bbio = kzalloc(
+                /* the size of the btrfs_bio */
                sizeof(struct btrfs_bio) +
+               /* plus the variable array for the stripes */
                sizeof(struct btrfs_bio_stripe) * (total_stripes) +
+               /* plus the variable array for the tgt dev */
                sizeof(int) * (real_stripes) +
-               sizeof(u64) * (real_stripes),
+               /*
+                * plus the raid_map, which includes both the tgt dev
+                * and the stripes
+                */
+               sizeof(u64) * (total_stripes),
                GFP_NOFS);
        if (!bbio)
                return NULL;
index 47b19465f0dc64e85d00d99eaee50e88de9f1014..883b93623bc5682ecde2684bfe936bb98fd9e51d 100644 (file)
@@ -111,6 +111,8 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
                                        name, name_len, -1);
                if (!di && (flags & XATTR_REPLACE))
                        ret = -ENODATA;
+               else if (IS_ERR(di))
+                       ret = PTR_ERR(di);
                else if (di)
                        ret = btrfs_delete_one_dir_name(trans, root, path, di);
                goto out;
@@ -127,10 +129,12 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
                ASSERT(mutex_is_locked(&inode->i_mutex));
                di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode),
                                        name, name_len, 0);
-               if (!di) {
+               if (!di)
                        ret = -ENODATA;
+               else if (IS_ERR(di))
+                       ret = PTR_ERR(di);
+               if (ret)
                        goto out;
-               }
                btrfs_release_path(path);
                di = NULL;
        }
index 90d1882b306face4c53d10ed08c44e3ec77b726a..5ba029e627cc22db0648317a619685e545977316 100644 (file)
@@ -124,7 +124,7 @@ ecryptfs_get_key_payload_data(struct key *key)
 }
 
 #define ECRYPTFS_MAX_KEYSET_SIZE 1024
-#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
+#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 31
 #define ECRYPTFS_MAX_NUM_ENC_KEYS 64
 #define ECRYPTFS_MAX_IV_BYTES 16       /* 128 bits */
 #define ECRYPTFS_SALT_BYTES 2
@@ -237,7 +237,7 @@ struct ecryptfs_crypt_stat {
        struct crypto_ablkcipher *tfm;
        struct crypto_hash *hash_tfm; /* Crypto context for generating
                                       * the initialization vectors */
-       unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
+       unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
        unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
        unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];
        struct list_head keysig_list;
index b07731e68c0b4d39cf75a5840033638cf37c123f..fd39bad6f1bdf8bbcb4321a8fc8ff1934d67167c 100644 (file)
@@ -303,9 +303,22 @@ ecryptfs_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        struct file *lower_file = ecryptfs_file_to_lower(file);
        long rc = -ENOTTY;
 
-       if (lower_file->f_op->unlocked_ioctl)
+       if (!lower_file->f_op->unlocked_ioctl)
+               return rc;
+
+       switch (cmd) {
+       case FITRIM:
+       case FS_IOC_GETFLAGS:
+       case FS_IOC_SETFLAGS:
+       case FS_IOC_GETVERSION:
+       case FS_IOC_SETVERSION:
                rc = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
-       return rc;
+               fsstack_copy_attr_all(file_inode(file), file_inode(lower_file));
+
+               return rc;
+       default:
+               return rc;
+       }
 }
 
 #ifdef CONFIG_COMPAT
@@ -315,9 +328,22 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        struct file *lower_file = ecryptfs_file_to_lower(file);
        long rc = -ENOIOCTLCMD;
 
-       if (lower_file->f_op->compat_ioctl)
+       if (!lower_file->f_op->compat_ioctl)
+               return rc;
+
+       switch (cmd) {
+       case FITRIM:
+       case FS_IOC32_GETFLAGS:
+       case FS_IOC32_SETFLAGS:
+       case FS_IOC32_GETVERSION:
+       case FS_IOC32_SETVERSION:
                rc = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
-       return rc;
+               fsstack_copy_attr_all(file_inode(file), file_inode(lower_file));
+
+               return rc;
+       default:
+               return rc;
+       }
 }
 #endif
 
index 917bd5c9776aabcff5b482f59bd8d316193ead35..6bd67e2011f083e4e184e4d2d336cb15176d40ee 100644 (file)
@@ -891,7 +891,7 @@ struct ecryptfs_parse_tag_70_packet_silly_stack {
        struct blkcipher_desc desc;
        char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1];
        char iv[ECRYPTFS_MAX_IV_BYTES];
-       char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
+       char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
 };
 
 /**
index 1895d60f4122c21d0e2ee267066c6308473ba642..c095d32642599f90cf68a9437b9a10674d5cd3d9 100644 (file)
@@ -407,7 +407,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
        if (!cipher_name_set) {
                int cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);
 
-               BUG_ON(cipher_name_len >= ECRYPTFS_MAX_CIPHER_NAME_SIZE);
+               BUG_ON(cipher_name_len > ECRYPTFS_MAX_CIPHER_NAME_SIZE);
                strcpy(mount_crypt_stat->global_default_cipher_name,
                       ECRYPTFS_DEFAULT_CIPHER);
        }
index ed19a7d622fa35decaa08b10e83b8bdee8712419..39706c57ad3cb157d81594065a15f154f61d7bd8 100644 (file)
@@ -890,8 +890,8 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
 
        newpage = buf->page;
 
-       if (WARN_ON(!PageUptodate(newpage)))
-               return -EIO;
+       if (!PageUptodate(newpage))
+               SetPageUptodate(newpage);
 
        ClearPageMappedToDisk(newpage);
 
@@ -1353,6 +1353,17 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
        return err;
 }
 
+static int fuse_dev_open(struct inode *inode, struct file *file)
+{
+       /*
+        * The fuse device's file's private_data is used to hold
+        * the fuse_conn(ection) when it is mounted, and is used to
+        * keep track of whether the file has been mounted already.
+        */
+       file->private_data = NULL;
+       return 0;
+}
+
 static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
                              unsigned long nr_segs, loff_t pos)
 {
@@ -1797,6 +1808,9 @@ copy_finish:
 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
                       unsigned int size, struct fuse_copy_state *cs)
 {
+       /* Don't try to move pages (yet) */
+       cs->move_pages = 0;
+
        switch (code) {
        case FUSE_NOTIFY_POLL:
                return fuse_notify_poll(fc, size, cs);
@@ -2217,6 +2231,7 @@ static int fuse_dev_fasync(int fd, struct file *file, int on)
 
 const struct file_operations fuse_dev_operations = {
        .owner          = THIS_MODULE,
+       .open           = fuse_dev_open,
        .llseek         = no_llseek,
        .read           = do_sync_read,
        .aio_read       = fuse_dev_read,
index 6e560d56094b2ccaf7091ec784a6a039af214f43..754fdf8c6356388f16bbdc285240394b350bd90e 100644 (file)
@@ -131,13 +131,16 @@ skip:
        hfs_bnode_write(node, entry, data_off + key_len, entry_len);
        hfs_bnode_dump(node);
 
-       if (new_node) {
-               /* update parent key if we inserted a key
-                * at the start of the first node
-                */
-               if (!rec && new_node != node)
-                       hfs_brec_update_parent(fd);
+       /*
+        * update parent key if we inserted a key
+        * at the start of the node and it is not the new node
+        */
+       if (!rec && new_node != node) {
+               hfs_bnode_read_key(node, fd->search_key, data_off + size);
+               hfs_brec_update_parent(fd);
+       }
 
+       if (new_node) {
                hfs_bnode_put(fd->bnode);
                if (!new_node->parent) {
                        hfs_btree_inc_height(tree);
@@ -168,9 +171,6 @@ skip:
                goto again;
        }
 
-       if (!rec)
-               hfs_brec_update_parent(fd);
-
        return 0;
 }
 
@@ -370,6 +370,8 @@ again:
        if (IS_ERR(parent))
                return PTR_ERR(parent);
        __hfs_brec_find(parent, fd, hfs_find_rec_by_key);
+       if (fd->record < 0)
+               return -ENOENT;
        hfs_bnode_dump(parent);
        rec = fd->record;
 
index b684e8a132e6255b7f294321ccd3a2f0e5097a09..2bacb99885665f3a0fae9579a569128195d86fd4 100644 (file)
@@ -207,6 +207,7 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
                goto out_free;
        }
 
+       of->event = atomic_read(&of->kn->attr.open->event);
        ops = kernfs_ops(of->kn);
        if (ops->read)
                len = ops->read(of, buf, len, *ppos);
index 365c82e1b3a9a602057e65edc9b857c6adce6b76..528fedfda15e6432bd69b80c7bd8faceb7d1351d 100644 (file)
@@ -1665,7 +1665,8 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
        }
 
        if (my_fl != NULL) {
-               error = lease->fl_lmops->lm_change(my_fl, arg, &dispose);
+               lease = my_fl;
+               error = lease->fl_lmops->lm_change(lease, arg, &dispose);
                if (error)
                        goto out;
                goto out_setup;
@@ -1727,7 +1728,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
                        break;
                }
        }
-       trace_generic_delete_lease(inode, fl);
+       trace_generic_delete_lease(inode, victim);
        if (victim)
                error = fl->fl_lmops->lm_change(victim, F_UNLCK, &dispose);
        spin_unlock(&ctx->flc_lock);
index f9f4845db989e58b7e09f3e46b185f5ff5d2d9e4..19874151e95c9908660132e6a3e2e6d7d2d3c8e4 100644 (file)
@@ -433,7 +433,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
 
 static bool nfs_client_init_is_complete(const struct nfs_client *clp)
 {
-       return clp->cl_cons_state != NFS_CS_INITING;
+       return clp->cl_cons_state <= NFS_CS_READY;
 }
 
 int nfs_wait_client_init_complete(const struct nfs_client *clp)
index a1f0685b42ff7d2e42eed249e178ecdbbee7befc..a6ad688658803424d726afae85597ad2ace80044 100644 (file)
@@ -181,8 +181,8 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
                        clear_bit(NFS_DELEGATION_NEED_RECLAIM,
                                  &delegation->flags);
                        spin_unlock(&delegation->lock);
-                       put_rpccred(oldcred);
                        rcu_read_unlock();
+                       put_rpccred(oldcred);
                        trace_nfs4_reclaim_delegation(inode, res->delegation_type);
                } else {
                        /* We appear to have raced with a delegation return. */
@@ -370,7 +370,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
                        delegation = NULL;
                        goto out;
                }
-               freeme = nfs_detach_delegation_locked(nfsi, 
+               if (test_and_set_bit(NFS_DELEGATION_RETURNING,
+                                       &old_delegation->flags))
+                       goto out;
+               freeme = nfs_detach_delegation_locked(nfsi,
                                old_delegation, clp);
                if (freeme == NULL)
                        goto out;
@@ -433,6 +436,8 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
 {
        bool ret = false;
 
+       if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
+               goto out;
        if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
                ret = true;
        if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) {
@@ -444,6 +449,7 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
                        ret = true;
                spin_unlock(&delegation->lock);
        }
+out:
        return ret;
 }
 
@@ -471,14 +477,20 @@ restart:
                                                                super_list) {
                        if (!nfs_delegation_need_return(delegation))
                                continue;
-                       inode = nfs_delegation_grab_inode(delegation);
-                       if (inode == NULL)
+                       if (!nfs_sb_active(server->super))
                                continue;
+                       inode = nfs_delegation_grab_inode(delegation);
+                       if (inode == NULL) {
+                               rcu_read_unlock();
+                               nfs_sb_deactive(server->super);
+                               goto restart;
+                       }
                        delegation = nfs_start_delegation_return_locked(NFS_I(inode));
                        rcu_read_unlock();
 
                        err = nfs_end_delegation_return(inode, delegation, 0);
                        iput(inode);
+                       nfs_sb_deactive(server->super);
                        if (!err)
                                goto restart;
                        set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
@@ -809,19 +821,30 @@ restart:
        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
                list_for_each_entry_rcu(delegation, &server->delegations,
                                                                super_list) {
+                       if (test_bit(NFS_DELEGATION_RETURNING,
+                                               &delegation->flags))
+                               continue;
                        if (test_bit(NFS_DELEGATION_NEED_RECLAIM,
                                                &delegation->flags) == 0)
                                continue;
-                       inode = nfs_delegation_grab_inode(delegation);
-                       if (inode == NULL)
+                       if (!nfs_sb_active(server->super))
                                continue;
-                       delegation = nfs_detach_delegation(NFS_I(inode),
-                                       delegation, server);
+                       inode = nfs_delegation_grab_inode(delegation);
+                       if (inode == NULL) {
+                               rcu_read_unlock();
+                               nfs_sb_deactive(server->super);
+                               goto restart;
+                       }
+                       delegation = nfs_start_delegation_return_locked(NFS_I(inode));
                        rcu_read_unlock();
-
-                       if (delegation != NULL)
-                               nfs_free_delegation(delegation);
+                       if (delegation != NULL) {
+                               delegation = nfs_detach_delegation(NFS_I(inode),
+                                       delegation, server);
+                               if (delegation != NULL)
+                                       nfs_free_delegation(delegation);
+                       }
                        iput(inode);
+                       nfs_sb_deactive(server->super);
                        goto restart;
                }
        }
index 9b0c55cb2a2eaa9166670258ef7bf2b87824a0b7..c19e16f0b2d049f972acee413a287d9f73759ba3 100644 (file)
@@ -408,14 +408,22 @@ static int xdr_decode(nfs_readdir_descriptor_t *desc,
        return 0;
 }
 
+/* Match file and dirent using either filehandle or fileid
+ * Note: caller is responsible for checking the fsid
+ */
 static
 int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
 {
+       struct nfs_inode *nfsi;
+
        if (dentry->d_inode == NULL)
                goto different;
-       if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0)
-               goto different;
-       return 1;
+
+       nfsi = NFS_I(dentry->d_inode);
+       if (entry->fattr->fileid == nfsi->fileid)
+               return 1;
+       if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0)
+               return 1;
 different:
        return 0;
 }
@@ -469,6 +477,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
        struct inode *inode;
        int status;
 
+       if (!(entry->fattr->valid & NFS_ATTR_FATTR_FILEID))
+               return;
+       if (!(entry->fattr->valid & NFS_ATTR_FATTR_FSID))
+               return;
        if (filename.name[0] == '.') {
                if (filename.len == 1)
                        return;
@@ -479,6 +491,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
 
        dentry = d_lookup(parent, &filename);
        if (dentry != NULL) {
+               /* Is there a mountpoint here? If so, just exit */
+               if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid,
+                                       &entry->fattr->fsid))
+                       goto out;
                if (nfs_same_file(dentry, entry)) {
                        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                        status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
index 94712fc781fa58fa162c8399c6b9427aa242f5ce..e679d24c39d3a57d5ef510a22d5ccbe2832c5335 100644 (file)
@@ -178,7 +178,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
                iocb->ki_filp,
                iov_iter_count(to), (unsigned long) iocb->ki_pos);
 
-       result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
+       result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping);
        if (!result) {
                result = generic_file_read_iter(iocb, to);
                if (result > 0)
@@ -199,7 +199,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
        dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n",
                filp, (unsigned long) count, (unsigned long long) *ppos);
 
-       res = nfs_revalidate_mapping(inode, filp->f_mapping);
+       res = nfs_revalidate_mapping_protected(inode, filp->f_mapping);
        if (!res) {
                res = generic_file_splice_read(filp, ppos, pipe, count, flags);
                if (res > 0)
@@ -372,6 +372,10 @@ start:
                                 nfs_wait_bit_killable, TASK_KILLABLE);
        if (ret)
                return ret;
+       /*
+        * Wait for O_DIRECT to complete
+        */
+       nfs_inode_dio_wait(mapping->host);
 
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page)
@@ -619,6 +623,9 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        /* make sure the cache has finished storing the page */
        nfs_fscache_wait_on_page_write(NFS_I(inode), page);
 
+       wait_on_bit_action(&NFS_I(inode)->flags, NFS_INO_INVALIDATING,
+                       nfs_wait_bit_killable, TASK_KILLABLE);
+
        lock_page(page);
        mapping = page_file_mapping(page);
        if (mapping != inode->i_mapping)
index 83107be3dd0109ab54c5f2b0c72fa59c64dd8d57..d42dff6d5e983f65c2e2f299e12d5353f54236c7 100644 (file)
@@ -556,6 +556,7 @@ EXPORT_SYMBOL_GPL(nfs_setattr);
  * This is a copy of the common vmtruncate, but with the locking
  * corrected to take into account the fact that NFS requires
  * inode->i_size to be updated under the inode->i_lock.
+ * Note: must be called with inode->i_lock held!
  */
 static int nfs_vmtruncate(struct inode * inode, loff_t offset)
 {
@@ -565,14 +566,14 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset)
        if (err)
                goto out;
 
-       spin_lock(&inode->i_lock);
        i_size_write(inode, offset);
        /* Optimisation */
        if (offset == 0)
                NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA;
-       spin_unlock(&inode->i_lock);
 
+       spin_unlock(&inode->i_lock);
        truncate_pagecache(inode, offset);
+       spin_lock(&inode->i_lock);
 out:
        return err;
 }
@@ -585,10 +586,15 @@ out:
  * Note: we do this in the *proc.c in order to ensure that
  *       it works for things like exclusive creates too.
  */
-void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
+void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
+               struct nfs_fattr *fattr)
 {
+       /* Barrier: bump the attribute generation count. */
+       nfs_fattr_set_barrier(fattr);
+
+       spin_lock(&inode->i_lock);
+       NFS_I(inode)->attr_gencount = fattr->gencount;
        if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
-               spin_lock(&inode->i_lock);
                if ((attr->ia_valid & ATTR_MODE) != 0) {
                        int mode = attr->ia_mode & S_IALLUGO;
                        mode |= inode->i_mode & ~S_IALLUGO;
@@ -600,12 +606,13 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
                        inode->i_gid = attr->ia_gid;
                nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS
                                | NFS_INO_INVALID_ACL);
-               spin_unlock(&inode->i_lock);
        }
        if ((attr->ia_valid & ATTR_SIZE) != 0) {
                nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
                nfs_vmtruncate(inode, attr->ia_size);
        }
+       nfs_update_inode(inode, fattr);
+       spin_unlock(&inode->i_lock);
 }
 EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
 
@@ -1028,6 +1035,7 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
 
        if (mapping->nrpages != 0) {
                if (S_ISREG(inode->i_mode)) {
+                       unmap_mapping_range(mapping, 0, 0, 0);
                        ret = nfs_sync_mapping(mapping);
                        if (ret < 0)
                                return ret;
@@ -1060,11 +1068,14 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
 }
 
 /**
- * nfs_revalidate_mapping - Revalidate the pagecache
+ * __nfs_revalidate_mapping - Revalidate the pagecache
  * @inode - pointer to host inode
  * @mapping - pointer to mapping
+ * @may_lock - take inode->i_mutex?
  */
-int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+static int __nfs_revalidate_mapping(struct inode *inode,
+               struct address_space *mapping,
+               bool may_lock)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        unsigned long *bitlock = &nfsi->flags;
@@ -1113,7 +1124,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
        nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
        spin_unlock(&inode->i_lock);
        trace_nfs_invalidate_mapping_enter(inode);
-       ret = nfs_invalidate_mapping(inode, mapping);
+       if (may_lock) {
+               mutex_lock(&inode->i_mutex);
+               ret = nfs_invalidate_mapping(inode, mapping);
+               mutex_unlock(&inode->i_mutex);
+       } else
+               ret = nfs_invalidate_mapping(inode, mapping);
        trace_nfs_invalidate_mapping_exit(inode, ret);
 
        clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
@@ -1123,6 +1139,29 @@ out:
        return ret;
 }
 
+/**
+ * nfs_revalidate_mapping - Revalidate the pagecache
+ * @inode - pointer to host inode
+ * @mapping - pointer to mapping
+ */
+int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+{
+       return __nfs_revalidate_mapping(inode, mapping, false);
+}
+
+/**
+ * nfs_revalidate_mapping_protected - Revalidate the pagecache
+ * @inode - pointer to host inode
+ * @mapping - pointer to mapping
+ *
+ * Differs from nfs_revalidate_mapping() in that it grabs the inode->i_mutex
+ * while invalidating the mapping.
+ */
+int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping)
+{
+       return __nfs_revalidate_mapping(inode, mapping, true);
+}
+
 static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -1231,13 +1270,6 @@ static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fat
        return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
 }
 
-static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
-{
-       if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
-               return 0;
-       return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
-}
-
 static atomic_long_t nfs_attr_generation_counter;
 
 static unsigned long nfs_read_attr_generation_counter(void)
@@ -1249,6 +1281,7 @@ unsigned long nfs_inc_attr_generation_counter(void)
 {
        return atomic_long_inc_return(&nfs_attr_generation_counter);
 }
+EXPORT_SYMBOL_GPL(nfs_inc_attr_generation_counter);
 
 void nfs_fattr_init(struct nfs_fattr *fattr)
 {
@@ -1260,6 +1293,22 @@ void nfs_fattr_init(struct nfs_fattr *fattr)
 }
 EXPORT_SYMBOL_GPL(nfs_fattr_init);
 
+/**
+ * nfs_fattr_set_barrier
+ * @fattr: attributes
+ *
+ * Used to set a barrier after an attribute was updated. This
+ * barrier ensures that older attributes from RPC calls that may
+ * have raced with our update cannot clobber these new values.
+ * Note that you are still responsible for ensuring that other
+ * operations which change the attribute on the server do not
+ * collide.
+ */
+void nfs_fattr_set_barrier(struct nfs_fattr *fattr)
+{
+       fattr->gencount = nfs_inc_attr_generation_counter();
+}
+
 struct nfs_fattr *nfs_alloc_fattr(void)
 {
        struct nfs_fattr *fattr;
@@ -1370,7 +1419,6 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
 
        return ((long)fattr->gencount - (long)nfsi->attr_gencount) > 0 ||
                nfs_ctime_need_update(inode, fattr) ||
-               nfs_size_need_update(inode, fattr) ||
                ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
 }
 
@@ -1460,6 +1508,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        int status;
 
        spin_lock(&inode->i_lock);
+       nfs_fattr_set_barrier(fattr);
        status = nfs_post_op_update_inode_locked(inode, fattr);
        spin_unlock(&inode->i_lock);
 
@@ -1468,7 +1517,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
 
 /**
- * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
+ * nfs_post_op_update_inode_force_wcc_locked - update the inode attribute cache
  * @inode - pointer to inode
  * @fattr - updated attributes
  *
@@ -1478,11 +1527,10 @@ EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
  *
  * This function is mainly designed to be used by the ->write_done() functions.
  */
-int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr)
 {
        int status;
 
-       spin_lock(&inode->i_lock);
        /* Don't do a WCC update if these attributes are already stale */
        if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
                        !nfs_inode_attrs_need_update(inode, fattr)) {
@@ -1514,6 +1562,27 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
        }
 out_noforce:
        status = nfs_post_op_update_inode_locked(inode, fattr);
+       return status;
+}
+
+/**
+ * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
+ * @inode - pointer to inode
+ * @fattr - updated attributes
+ *
+ * After an operation that has changed the inode metadata, mark the
+ * attribute cache as being invalid, then try to update it. Fake up
+ * weak cache consistency data, if none exist.
+ *
+ * This function is mainly designed to be used by the ->write_done() functions.
+ */
+int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
+{
+       int status;
+
+       spin_lock(&inode->i_lock);
+       nfs_fattr_set_barrier(fattr);
+       status = nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
        spin_unlock(&inode->i_lock);
        return status;
 }
@@ -1715,6 +1784,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
                nfsi->attrtimeo_timestamp = now;
+               /* Set barrier to be more recent than all outstanding updates */
                nfsi->attr_gencount = nfs_inc_attr_generation_counter();
        } else {
                if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
@@ -1722,6 +1792,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                                nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
                        nfsi->attrtimeo_timestamp = now;
                }
+               /* Set the barrier to be more recent than this fattr */
+               if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0)
+                       nfsi->attr_gencount = fattr->gencount;
        }
        invalid &= ~NFS_INO_INVALID_ATTR;
        /* Don't invalidate the data if we were to blame */
index b802fb3a2d99ffd76a57aecc6ce6739ca104e515..9e6475bc5ba22be7293c687d78dda1a626d3024b 100644 (file)
@@ -459,6 +459,7 @@ void nfs_mark_request_commit(struct nfs_page *req,
                             struct nfs_commit_info *cinfo,
                             u32 ds_commit_idx);
 int nfs_write_need_commit(struct nfs_pgio_header *);
+void nfs_writeback_update_inode(struct nfs_pgio_header *hdr);
 int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
                            int how, struct nfs_commit_info *cinfo);
 void nfs_retry_commit(struct list_head *page_list,
index 78e557c3ab87d014694e6e4098faefb20553f579..1f11d2533ee4107bd9ae3f8de460b38ecdbaae74 100644 (file)
@@ -138,7 +138,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        nfs_fattr_init(fattr);
        status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
        if (status == 0)
-               nfs_setattr_update_inode(inode, sattr);
+               nfs_setattr_update_inode(inode, sattr, fattr);
        dprintk("NFS reply setattr: %d\n", status);
        return status;
 }
@@ -834,7 +834,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
        if (nfs3_async_handle_jukebox(task, inode))
                return -EAGAIN;
        if (task->tk_status >= 0)
-               nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr);
+               nfs_writeback_update_inode(hdr);
        return 0;
 }
 
index 2a932fdc57cb37b2676e08dcb33838c9aecd2a9a..53852a4bd88be68781bb9dd8a39760fd497d1d61 100644 (file)
@@ -1987,6 +1987,11 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
                        entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
 
+               if (entry->fattr->fileid != entry->ino) {
+                       entry->fattr->mounted_on_fileid = entry->ino;
+                       entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
+               }
+
                /* In fact, a post_op_fh3: */
                p = xdr_inline_decode(xdr, 4);
                if (unlikely(p == NULL))
index 8646af9b11d2e1b866f1c1e789a5b6001a36c882..86d6214ea022fee66f16f976a17451590edde7b8 100644 (file)
@@ -621,6 +621,9 @@ int nfs41_walk_client_list(struct nfs_client *new,
        spin_lock(&nn->nfs_client_lock);
        list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
 
+               if (pos == new)
+                       goto found;
+
                if (pos->rpc_ops != new->rpc_ops)
                        continue;
 
@@ -639,10 +642,6 @@ int nfs41_walk_client_list(struct nfs_client *new,
                        prev = pos;
 
                        status = nfs_wait_client_init_complete(pos);
-                       if (pos->cl_cons_state == NFS_CS_SESSION_INITING) {
-                               nfs4_schedule_lease_recovery(pos);
-                               status = nfs4_wait_clnt_recover(pos);
-                       }
                        spin_lock(&nn->nfs_client_lock);
                        if (status < 0)
                                break;
@@ -668,7 +667,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
                 */
                if (!nfs4_match_client_owner_id(pos, new))
                        continue;
-
+found:
                atomic_inc(&pos->cl_count);
                *result = pos;
                status = 0;
index 88180ac5ea0eebdf34aa333130e69d7a7b49c38e..627f37c44456752d6bd90a8882ae373ec6d70718 100644 (file)
@@ -901,6 +901,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
        if (!cinfo->atomic || cinfo->before != dir->i_version)
                nfs_force_lookup_revalidate(dir);
        dir->i_version = cinfo->after;
+       nfsi->attr_gencount = nfs_inc_attr_generation_counter();
        nfs_fscache_invalidate(dir);
        spin_unlock(&dir->i_lock);
 }
@@ -1552,6 +1553,9 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod
 
        opendata->o_arg.open_flags = 0;
        opendata->o_arg.fmode = fmode;
+       opendata->o_arg.share_access = nfs4_map_atomic_open_share(
+                       NFS_SB(opendata->dentry->d_sb),
+                       fmode, 0);
        memset(&opendata->o_res, 0, sizeof(opendata->o_res));
        memset(&opendata->c_res, 0, sizeof(opendata->c_res));
        nfs4_init_opendata_res(opendata);
@@ -2413,8 +2417,8 @@ static int _nfs4_do_open(struct inode *dir,
                                opendata->o_res.f_attr, sattr,
                                state, label, olabel);
                if (status == 0) {
-                       nfs_setattr_update_inode(state->inode, sattr);
-                       nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
+                       nfs_setattr_update_inode(state->inode, sattr,
+                                       opendata->o_res.f_attr);
                        nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
                }
        }
@@ -2651,7 +2655,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                case -NFS4ERR_BAD_STATEID:
                case -NFS4ERR_EXPIRED:
                        if (!nfs4_stateid_match(&calldata->arg.stateid,
-                                               &state->stateid)) {
+                                               &state->open_stateid)) {
                                rpc_restart_call_prepare(task);
                                goto out_release;
                        }
@@ -2687,7 +2691,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
        is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
        is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
-       nfs4_stateid_copy(&calldata->arg.stateid, &state->stateid);
+       nfs4_stateid_copy(&calldata->arg.stateid, &state->open_stateid);
        /* Calculate the change in open mode */
        calldata->arg.fmode = 0;
        if (state->n_rdwr == 0) {
@@ -3288,7 +3292,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 
        status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label);
        if (status == 0) {
-               nfs_setattr_update_inode(inode, sattr);
+               nfs_setattr_update_inode(inode, sattr, fattr);
                nfs_setsecurity(inode, fattr, label);
        }
        nfs4_label_free(label);
@@ -4234,7 +4238,7 @@ static int nfs4_write_done_cb(struct rpc_task *task,
        }
        if (task->tk_status >= 0) {
                renew_lease(NFS_SERVER(inode), hdr->timestamp);
-               nfs_post_op_update_inode_force_wcc(inode, &hdr->fattr);
+               nfs_writeback_update_inode(hdr);
        }
        return 0;
 }
@@ -6893,9 +6897,13 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
 
        if (status == 0) {
                clp->cl_clientid = res.clientid;
-               clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R);
-               if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R))
+               clp->cl_exchange_flags = res.flags;
+               /* Client ID is not confirmed */
+               if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R)) {
+                       clear_bit(NFS4_SESSION_ESTABLISHED,
+                                       &clp->cl_session->session_state);
                        clp->cl_seqid = res.seqid;
+               }
 
                kfree(clp->cl_serverowner);
                clp->cl_serverowner = res.server_owner;
@@ -7227,6 +7235,9 @@ static void nfs4_update_session(struct nfs4_session *session,
                struct nfs41_create_session_res *res)
 {
        nfs4_copy_sessionid(&session->sess_id, &res->sessionid);
+       /* Mark client id and session as being confirmed */
+       session->clp->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
+       set_bit(NFS4_SESSION_ESTABLISHED, &session->session_state);
        session->flags = res->flags;
        memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs));
        if (res->flags & SESSION4_BACK_CHAN)
@@ -7322,8 +7333,8 @@ int nfs4_proc_destroy_session(struct nfs4_session *session,
        dprintk("--> nfs4_proc_destroy_session\n");
 
        /* session is still being setup */
-       if (session->clp->cl_cons_state != NFS_CS_READY)
-               return status;
+       if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state))
+               return 0;
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        trace_nfs4_destroy_session(session->clp, status);
index fc46c745589863425bff271942b76f7812db5aea..e3ea2c5324d68e92591058e896bf478538302a5a 100644 (file)
@@ -70,6 +70,7 @@ struct nfs4_session {
 
 enum nfs4_session_state {
        NFS4_SESSION_INITING,
+       NFS4_SESSION_ESTABLISHED,
 };
 
 extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
index 5ad908e9ce9c332696ed52a85a5c4324a45d8b02..f95e3b58bbc304ae381df2a5f1721d8074789c51 100644 (file)
@@ -346,9 +346,23 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
        status = nfs4_proc_exchange_id(clp, cred);
        if (status != NFS4_OK)
                return status;
-       set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
 
-       return nfs41_walk_client_list(clp, result, cred);
+       status = nfs41_walk_client_list(clp, result, cred);
+       if (status < 0)
+               return status;
+       if (clp != *result)
+               return 0;
+
+       /* Purge state if the client id was established in a prior instance */
+       if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R)
+               set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
+       else
+               set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+       nfs4_schedule_state_manager(clp);
+       status = nfs_wait_client_init_complete(clp);
+       if (status < 0)
+               nfs_put_client(clp);
+       return status;
 }
 
 #endif /* CONFIG_NFS_V4_1 */
index b09cc23d6f433bc5ea8aff6cfe68c3910c4f8319..c63189acd0523cf733ab494dc85c1acf0cdb8f33 100644 (file)
@@ -139,7 +139,7 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        nfs_fattr_init(fattr);
        status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
        if (status == 0)
-               nfs_setattr_update_inode(inode, sattr);
+               nfs_setattr_update_inode(inode, sattr, fattr);
        dprintk("NFS reply setattr: %d\n", status);
        return status;
 }
@@ -609,10 +609,8 @@ static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task,
 
 static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
 {
-       struct inode *inode = hdr->inode;
-
        if (task->tk_status >= 0)
-               nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr);
+               nfs_writeback_update_inode(hdr);
        return 0;
 }
 
index 595d81e354d18950a21615862b134ca8993f4c6e..849ed784d6ac1fc6b923c32278e089f87575b8db 100644 (file)
@@ -1377,6 +1377,36 @@ static int nfs_should_remove_suid(const struct inode *inode)
        return 0;
 }
 
+static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
+               struct nfs_fattr *fattr)
+{
+       struct nfs_pgio_args *argp = &hdr->args;
+       struct nfs_pgio_res *resp = &hdr->res;
+
+       if (!(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))
+               return;
+       /* Set attribute barrier */
+       nfs_fattr_set_barrier(fattr);
+}
+
+void nfs_writeback_update_inode(struct nfs_pgio_header *hdr)
+{
+       struct nfs_fattr *fattr = hdr->res.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);
+       spin_unlock(&inode->i_lock);
+}
+EXPORT_SYMBOL_GPL(nfs_writeback_update_inode);
+
 /*
  * This function is called when the WRITE call is complete.
  */
index 3c1bfa15557116d0e78c87b191a5842bdeca9417..1028a062954357c06005dc7b0d6f61a10ea6f418 100644 (file)
@@ -587,8 +587,6 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
 
        rpc_ntop((struct sockaddr *)&clp->cl_addr, addr_str, sizeof(addr_str));
 
-       nfsd4_cb_layout_fail(ls);
-
        printk(KERN_WARNING
                "nfsd: client %s failed to respond to layout recall. "
                "  Fencing..\n", addr_str);
index f6b2a09f793f453e5b6c40e80ceb383a12af7616..d2f2c37dc2dbd2649399fe2ddad4032a5025d337 100644 (file)
@@ -1638,7 +1638,7 @@ __destroy_client(struct nfs4_client *clp)
                nfs4_put_stid(&dp->dl_stid);
        }
        while (!list_empty(&clp->cl_revoked)) {
-               dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
+               dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru);
                list_del_init(&dp->dl_recall_lru);
                nfs4_put_stid(&dp->dl_stid);
        }
index b2e3ff34762070a4b37085c051223809b59e4a6c..ecdbae19a766d914e7d68c005c14356455dc83af 100644 (file)
@@ -31,6 +31,8 @@
 #include "alloc.h"
 #include "dat.h"
 
+static void __nilfs_btree_init(struct nilfs_bmap *bmap);
+
 static struct nilfs_btree_path *nilfs_btree_alloc_path(void)
 {
        struct nilfs_btree_path *path;
@@ -368,6 +370,34 @@ static int nilfs_btree_node_broken(const struct nilfs_btree_node *node,
        return ret;
 }
 
+/**
+ * nilfs_btree_root_broken - verify consistency of btree root node
+ * @node: btree root node to be examined
+ * @ino: inode number
+ *
+ * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned.
+ */
+static int nilfs_btree_root_broken(const struct nilfs_btree_node *node,
+                                  unsigned long ino)
+{
+       int level, flags, nchildren;
+       int ret = 0;
+
+       level = nilfs_btree_node_get_level(node);
+       flags = nilfs_btree_node_get_flags(node);
+       nchildren = nilfs_btree_node_get_nchildren(node);
+
+       if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN ||
+                    level > NILFS_BTREE_LEVEL_MAX ||
+                    nchildren < 0 ||
+                    nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) {
+               pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n",
+                       ino, level, flags, nchildren);
+               ret = 1;
+       }
+       return ret;
+}
+
 int nilfs_btree_broken_node_block(struct buffer_head *bh)
 {
        int ret;
@@ -1713,7 +1743,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *btree,
 
        /* convert and insert */
        dat = NILFS_BMAP_USE_VBN(btree) ? nilfs_bmap_get_dat(btree) : NULL;
-       nilfs_btree_init(btree);
+       __nilfs_btree_init(btree);
        if (nreq != NULL) {
                nilfs_bmap_commit_alloc_ptr(btree, dreq, dat);
                nilfs_bmap_commit_alloc_ptr(btree, nreq, dat);
@@ -2294,12 +2324,23 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = {
        .bop_gather_data        =       NULL,
 };
 
-int nilfs_btree_init(struct nilfs_bmap *bmap)
+static void __nilfs_btree_init(struct nilfs_bmap *bmap)
 {
        bmap->b_ops = &nilfs_btree_ops;
        bmap->b_nchildren_per_block =
                NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(bmap));
-       return 0;
+}
+
+int nilfs_btree_init(struct nilfs_bmap *bmap)
+{
+       int ret = 0;
+
+       __nilfs_btree_init(bmap);
+
+       if (nilfs_btree_root_broken(nilfs_btree_get_root(bmap),
+                                   bmap->b_inode->i_ino))
+               ret = -EIO;
+       return ret;
 }
 
 void nilfs_btree_init_gc(struct nilfs_bmap *bmap)
index 469086b9f99bc8e20053e492237d48a3373bdb37..0c3f303baf32f196af9360f8f78773f29a31e139 100644 (file)
@@ -1907,6 +1907,7 @@ static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci,
                                             struct the_nilfs *nilfs)
 {
        struct nilfs_inode_info *ii, *n;
+       int during_mount = !(sci->sc_super->s_flags & MS_ACTIVE);
        int defer_iput = false;
 
        spin_lock(&nilfs->ns_inode_lock);
@@ -1919,10 +1920,10 @@ static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci,
                brelse(ii->i_bh);
                ii->i_bh = NULL;
                list_del_init(&ii->i_dirty);
-               if (!ii->vfs_inode.i_nlink) {
+               if (!ii->vfs_inode.i_nlink || during_mount) {
                        /*
-                        * Defer calling iput() to avoid a deadlock
-                        * over I_SYNC flag for inodes with i_nlink == 0
+                        * Defer calling iput() to avoid deadlocks if
+                        * i_nlink == 0 or mount is not yet finished.
                         */
                        list_add_tail(&ii->i_dirty, &sci->sc_iput_queue);
                        defer_iput = true;
index 9a66ff79ff2781d1c7992dbd3d4ec42a82008f59..d2f97ecca6a5dfe6091d56da09871449574524bf 100644 (file)
@@ -143,7 +143,8 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
            !(marks_mask & FS_ISDIR & ~marks_ignored_mask))
                return false;
 
-       if (event_mask & marks_mask & ~marks_ignored_mask)
+       if (event_mask & FAN_ALL_OUTGOING_EVENTS & marks_mask &
+                                ~marks_ignored_mask)
                return true;
 
        return false;
index 8490c64d34fef4fd0421c4bb7e7c7ea9f6d87bca..460c6c37e683f844bd9612d51e6b89224cabb22b 100644 (file)
@@ -502,7 +502,7 @@ static inline int ocfs2_writes_unwritten_extents(struct ocfs2_super *osb)
 
 static inline int ocfs2_supports_append_dio(struct ocfs2_super *osb)
 {
-       if (osb->s_feature_ro_compat & OCFS2_FEATURE_RO_COMPAT_APPEND_DIO)
+       if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_APPEND_DIO)
                return 1;
        return 0;
 }
index 20e37a3ed26f3eb721ad45c2699a6332a098cee8..db64ce2d4667be86ca27aecc304c1125667906f6 100644 (file)
                                         | OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS \
                                         | OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE \
                                         | OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG  \
-                                        | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO)
+                                        | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO \
+                                        | OCFS2_FEATURE_INCOMPAT_APPEND_DIO)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP   (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \
                                         | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \
-                                        | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA \
-                                        | OCFS2_FEATURE_RO_COMPAT_APPEND_DIO)
+                                        | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)
 
 /*
  * Heartbeat-only devices are missing journals and other files.  The
  */
 #define OCFS2_FEATURE_INCOMPAT_CLUSTERINFO     0x4000
 
+/*
+ * Append Direct IO support
+ */
+#define OCFS2_FEATURE_INCOMPAT_APPEND_DIO      0x8000
+
 /*
  * backup superblock flag is used to indicate that this volume
  * has backup superblocks.
 #define OCFS2_FEATURE_RO_COMPAT_USRQUOTA       0x0002
 #define OCFS2_FEATURE_RO_COMPAT_GRPQUOTA       0x0004
 
-/*
- * Append Direct IO support
- */
-#define OCFS2_FEATURE_RO_COMPAT_APPEND_DIO     0x0008
 
 /* The byte offset of the first backup block will be 1G.
  * The following will be 4G, 16G, 64G, 256G and 1T.
index b90952f528b1cdf7414e49b5613e439d6b89fb7a..5f0d1993e6e3952bda9352d231e8fce7dee838e8 100644 (file)
@@ -529,8 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data)
 {
        struct ovl_fs *ufs = sb->s_fs_info;
 
-       if (!(*flags & MS_RDONLY) &&
-           (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY)))
+       if (!(*flags & MS_RDONLY) && !ufs->upper_mnt)
                return -EROFS;
 
        return 0;
@@ -615,9 +614,19 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
                        break;
 
                default:
+                       pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p);
                        return -EINVAL;
                }
        }
+
+       /* Workdir is useless in non-upper mount */
+       if (!config->upperdir && config->workdir) {
+               pr_info("overlayfs: option \"workdir=%s\" is useless in a non-upper mount, ignore\n",
+                       config->workdir);
+               kfree(config->workdir);
+               config->workdir = NULL;
+       }
+
        return 0;
 }
 
@@ -837,7 +846,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_stack_depth = 0;
        if (ufs->config.upperdir) {
-               /* FIXME: workdir is not needed for a R/O mount */
                if (!ufs->config.workdir) {
                        pr_err("overlayfs: missing 'workdir'\n");
                        goto out_free_config;
@@ -847,6 +855,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                if (err)
                        goto out_free_config;
 
+               /* Upper fs should not be r/o */
+               if (upperpath.mnt->mnt_sb->s_flags & MS_RDONLY) {
+                       pr_err("overlayfs: upper fs is r/o, try multi-lower layers mount\n");
+                       err = -EINVAL;
+                       goto out_put_upperpath;
+               }
+
                err = ovl_mount_dir(ufs->config.workdir, &workpath);
                if (err)
                        goto out_put_upperpath;
@@ -869,8 +884,14 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        err = -EINVAL;
        stacklen = ovl_split_lowerdirs(lowertmp);
-       if (stacklen > OVL_MAX_STACK)
+       if (stacklen > OVL_MAX_STACK) {
+               pr_err("overlayfs: too many lower directries, limit is %d\n",
+                      OVL_MAX_STACK);
                goto out_free_lowertmp;
+       } else if (!ufs->config.upperdir && stacklen == 1) {
+               pr_err("overlayfs: at least 2 lowerdir are needed while upperdir nonexistent\n");
+               goto out_free_lowertmp;
+       }
 
        stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL);
        if (!stack)
@@ -932,8 +953,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                ufs->numlower++;
        }
 
-       /* If the upper fs is r/o or nonexistent, we mark overlayfs r/o too */
-       if (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY))
+       /* If the upper fs is nonexistent, we mark overlayfs r/o too */
+       if (!ufs->upper_mnt)
                sb->s_flags |= MS_RDONLY;
 
        sb->s_d_op = &ovl_dentry_operations;
index 956b75d61809f06cdf433411456bb08278726eb5..6dee68d013ffa69f1f6c9d49873f17f19eb3874d 100644 (file)
@@ -1325,6 +1325,9 @@ out:
 
 static int pagemap_open(struct inode *inode, struct file *file)
 {
+       /* do not disclose physical addresses: attack vector */
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
        pr_warn_once("Bits 55-60 of /proc/PID/pagemap entries are about "
                        "to stop being page-shift some time soon. See the "
                        "linux/Documentation/vm/pagemap.txt for details.\n");
index ce615d12fb44cfae0d6bf344cbf0b3d2e4f43e1d..a2e1cb8a568bf9d45e32c43539a2e6f8b56d83f4 100644 (file)
@@ -397,7 +397,8 @@ STATIC int                          /* error (positive) */
 xfs_zero_last_block(
        struct xfs_inode        *ip,
        xfs_fsize_t             offset,
-       xfs_fsize_t             isize)
+       xfs_fsize_t             isize,
+       bool                    *did_zeroing)
 {
        struct xfs_mount        *mp = ip->i_mount;
        xfs_fileoff_t           last_fsb = XFS_B_TO_FSBT(mp, isize);
@@ -425,6 +426,7 @@ xfs_zero_last_block(
        zero_len = mp->m_sb.sb_blocksize - zero_offset;
        if (isize + zero_len > offset)
                zero_len = offset - isize;
+       *did_zeroing = true;
        return xfs_iozero(ip, isize, zero_len);
 }
 
@@ -443,7 +445,8 @@ int                                 /* error (positive) */
 xfs_zero_eof(
        struct xfs_inode        *ip,
        xfs_off_t               offset,         /* starting I/O offset */
-       xfs_fsize_t             isize)          /* current inode size */
+       xfs_fsize_t             isize,          /* current inode size */
+       bool                    *did_zeroing)
 {
        struct xfs_mount        *mp = ip->i_mount;
        xfs_fileoff_t           start_zero_fsb;
@@ -465,7 +468,7 @@ xfs_zero_eof(
         * We only zero a part of that block so it is handled specially.
         */
        if (XFS_B_FSB_OFFSET(mp, isize) != 0) {
-               error = xfs_zero_last_block(ip, offset, isize);
+               error = xfs_zero_last_block(ip, offset, isize, did_zeroing);
                if (error)
                        return error;
        }
@@ -525,6 +528,7 @@ xfs_zero_eof(
                if (error)
                        return error;
 
+               *did_zeroing = true;
                start_zero_fsb = imap.br_startoff + imap.br_blockcount;
                ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
        }
@@ -567,13 +571,15 @@ restart:
         * having to redo all checks before.
         */
        if (*pos > i_size_read(inode)) {
+               bool    zero = false;
+
                if (*iolock == XFS_IOLOCK_SHARED) {
                        xfs_rw_iunlock(ip, *iolock);
                        *iolock = XFS_IOLOCK_EXCL;
                        xfs_rw_ilock(ip, *iolock);
                        goto restart;
                }
-               error = xfs_zero_eof(ip, *pos, i_size_read(inode));
+               error = xfs_zero_eof(ip, *pos, i_size_read(inode), &zero);
                if (error)
                        return error;
        }
index daafa1f6d2607722b338c8b5da458a979558d9b3..6163767aa8562f6d611a1442ed4f299aa85bceea 100644 (file)
@@ -2867,6 +2867,10 @@ xfs_rename(
         * Handle RENAME_EXCHANGE flags
         */
        if (flags & RENAME_EXCHANGE) {
+               if (target_ip == NULL) {
+                       error = -EINVAL;
+                       goto error_return;
+               }
                error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
                                         target_dp, target_name, target_ip,
                                         &free_list, &first_block, spaceres);
index 86cd6b39bed7be1dc4bd72be82e9a40b9c8b9825..a1cd55f3f351e1361e2a3ea790f88f5f5070e7e3 100644 (file)
@@ -384,10 +384,11 @@ enum xfs_prealloc_flags {
        XFS_PREALLOC_INVISIBLE  = (1 << 4),
 };
 
-int            xfs_update_prealloc_flags(struct xfs_inode *,
-                       enum xfs_prealloc_flags);
-int            xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);
-int            xfs_iozero(struct xfs_inode *, loff_t, size_t);
+int    xfs_update_prealloc_flags(struct xfs_inode *ip,
+                                 enum xfs_prealloc_flags flags);
+int    xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset,
+                    xfs_fsize_t isize, bool *did_zeroing);
+int    xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count);
 
 
 #define IHOLD(ip) \
index d919ad7b16bf9acbe01c6531a9254b372426911a..e53a903314225c030c45f694b4ffdaa509fa1ce8 100644 (file)
@@ -751,6 +751,7 @@ xfs_setattr_size(
        int                     error;
        uint                    lock_flags = 0;
        uint                    commit_flags = 0;
+       bool                    did_zeroing = false;
 
        trace_xfs_setattr(ip);
 
@@ -794,20 +795,16 @@ xfs_setattr_size(
                return error;
 
        /*
-        * Now we can make the changes.  Before we join the inode to the
-        * transaction, take care of the part of the truncation that must be
-        * done without the inode lock.  This needs to be done before joining
-        * the inode to the transaction, because the inode cannot be unlocked
-        * once it is a part of the transaction.
+        * File data changes must be complete before we start the transaction to
+        * modify the inode.  This needs to be done before joining the inode to
+        * the transaction because the inode cannot be unlocked once it is a
+        * part of the transaction.
+        *
+        * Start with zeroing any data block beyond EOF that we may expose on
+        * file extension.
         */
        if (newsize > oldsize) {
-               /*
-                * Do the first part of growing a file: zero any data in the
-                * last block that is beyond the old EOF.  We need to do this
-                * before the inode is joined to the transaction to modify
-                * i_size.
-                */
-               error = xfs_zero_eof(ip, newsize, oldsize);
+               error = xfs_zero_eof(ip, newsize, oldsize, &did_zeroing);
                if (error)
                        return error;
        }
@@ -817,23 +814,18 @@ xfs_setattr_size(
         * any previous writes that are beyond the on disk EOF and the new
         * EOF that have not been written out need to be written here.  If we
         * do not write the data out, we expose ourselves to the null files
-        * problem.
-        *
-        * Only flush from the on disk size to the smaller of the in memory
-        * file size or the new size as that's the range we really care about
-        * here and prevents waiting for other data not within the range we
-        * care about here.
+        * problem. Note that this includes any block zeroing we did above;
+        * otherwise those blocks may not be zeroed after a crash.
         */
-       if (oldsize != ip->i_d.di_size && newsize > ip->i_d.di_size) {
+       if (newsize > ip->i_d.di_size &&
+           (oldsize != ip->i_d.di_size || did_zeroing)) {
                error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
                                                      ip->i_d.di_size, newsize);
                if (error)
                        return error;
        }
 
-       /*
-        * Wait for all direct I/O to complete.
-        */
+       /* Now wait for all direct I/O to complete. */
        inode_dio_wait(inode);
 
        /*
index 4b33ef112400cc01507b96632d93775839573d99..365dd57ea760ddd5beaa87d78dc6a1f31d7feb94 100644 (file)
@@ -300,8 +300,10 @@ xfs_fs_commit_blocks(
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
        error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
-       if (error)
+       if (error) {
+               xfs_trans_cancel(tp, 0);
                goto out_drop_iolock;
+       }
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
index 53cc2aaf8d2bdfedc12247ae5055feaa95ae31a6..fbbb9e62e274b525a03e7cb1373cae35b49ace1b 100644 (file)
@@ -836,6 +836,11 @@ xfs_qm_reset_dqcounts(
                 */
                xfs_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR,
                            "xfs_quotacheck");
+               /*
+                * Reset type in case we are reusing group quota file for
+                * project quotas or vice versa
+                */
+               ddq->d_flags = type;
                ddq->d_bcount = 0;
                ddq->d_icount = 0;
                ddq->d_rtbcount = 0;
index e928625a9da0be41b7b03508a19f3df2cfb8acb5..62c40777c009798319a49235af42d040ffc654d6 100644 (file)
@@ -104,6 +104,9 @@ struct dma_buf_attachment;
  * PRIME: used in the prime code.
  *       This is the category used by the DRM_DEBUG_PRIME() macro.
  *
+ * ATOMIC: used in the atomic code.
+ *       This is the category used by the DRM_DEBUG_ATOMIC() macro.
+ *
  * Enabling verbose debug messages is done through the drm.debug parameter,
  * each category being enabled by a bit.
  *
@@ -121,6 +124,7 @@ struct dma_buf_attachment;
 #define DRM_UT_DRIVER          0x02
 #define DRM_UT_KMS             0x04
 #define DRM_UT_PRIME           0x08
+#define DRM_UT_ATOMIC          0x10
 
 extern __printf(2, 3)
 void drm_ut_debug_printk(const char *function_name,
@@ -207,6 +211,11 @@ void drm_err(const char *format, ...);
                if (unlikely(drm_debug & DRM_UT_PRIME))                 \
                        drm_ut_debug_printk(__func__, fmt, ##args);     \
        } while (0)
+#define DRM_DEBUG_ATOMIC(fmt, args...)                                 \
+       do {                                                            \
+               if (unlikely(drm_debug & DRM_UT_ATOMIC))                \
+                       drm_ut_debug_printk(__func__, fmt, ##args);     \
+       } while (0)
 
 /*@}*/
 
@@ -244,7 +253,6 @@ struct drm_ioctl_desc {
        unsigned int cmd;
        int flags;
        drm_ioctl_t *func;
-       unsigned int cmd_drv;
        const char *name;
 };
 
@@ -253,8 +261,13 @@ struct drm_ioctl_desc {
  * ioctl, for use by drm_ioctl().
  */
 
-#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags)                        \
-       [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl, .name = #ioctl}
+#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags)                                \
+       [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {        \
+               .cmd = DRM_IOCTL_##ioctl,                               \
+               .func = _func,                                          \
+               .flags = _flags,                                        \
+               .name = #ioctl                                          \
+        }
 
 /* Event queued up for userspace to read */
 struct drm_pending_event {
@@ -922,6 +935,7 @@ extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
 extern void drm_vblank_off(struct drm_device *dev, int crtc);
 extern void drm_vblank_on(struct drm_device *dev, int crtc);
 extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
+extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
 extern void drm_vblank_cleanup(struct drm_device *dev);
 
index 8039d54a7441276f8fb529d42c0c0bfc35bfb192..d665781eb54293deb008d89d7a5a43c575243d60 100644 (file)
@@ -43,9 +43,9 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 void drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
                                        struct drm_atomic_state *old_state);
 
-void drm_atomic_helper_commit_pre_planes(struct drm_device *dev,
-                                        struct drm_atomic_state *state);
-void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
+void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
+                                              struct drm_atomic_state *state);
+void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
                                          struct drm_atomic_state *old_state);
 
 int drm_atomic_helper_prepare_planes(struct drm_device *dev,
@@ -87,20 +87,34 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
 
 /* default implementations for state handling */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
+void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
+                                             struct drm_crtc_state *state);
 struct drm_crtc_state *
 drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
+void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+                                           struct drm_crtc_state *state);
 void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
                                          struct drm_crtc_state *state);
 
 void drm_atomic_helper_plane_reset(struct drm_plane *plane);
+void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
+                                              struct drm_plane_state *state);
 struct drm_plane_state *
 drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
+void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+                                            struct drm_plane_state *state);
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
                                          struct drm_plane_state *state);
 
 void drm_atomic_helper_connector_reset(struct drm_connector *connector);
+void
+__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
+                                          struct drm_connector_state *state);
 struct drm_connector_state *
 drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
+void
+__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+                                           struct drm_connector_state *state);
 void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
                                          struct drm_connector_state *state);
 
index f924b81d48fff1ca4ba79a33856552f21c18b707..2e80ad1aea84a770189b918e2686c99031984bcf 100644 (file)
@@ -201,6 +201,7 @@ struct drm_framebuffer {
        const struct drm_framebuffer_funcs *funcs;
        unsigned int pitches[4];
        unsigned int offsets[4];
+       uint64_t modifier[4];
        unsigned int width;
        unsigned int height;
        /* depth can be 15 or 16 */
@@ -828,6 +829,7 @@ enum drm_plane_type {
  * @possible_crtcs: pipes this plane can be bound to
  * @format_types: array of formats supported by this plane
  * @format_count: number of formats supported
+ * @format_default: driver hasn't supplied supported formats for the plane
  * @crtc: currently bound CRTC
  * @fb: currently bound fb
  * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by
@@ -848,6 +850,7 @@ struct drm_plane {
        uint32_t possible_crtcs;
        uint32_t *format_types;
        uint32_t format_count;
+       bool format_default;
 
        struct drm_crtc *crtc;
        struct drm_framebuffer *fb;
@@ -911,7 +914,7 @@ struct drm_bridge {
 };
 
 /**
- * struct struct drm_atomic_state - the global state object for atomic updates
+ * struct drm_atomic_state - the global state object for atomic updates
  * @dev: parent DRM device
  * @allow_modeset: allow full modeset
  * @legacy_cursor_update: hint to enforce legacy cursor ioctl semantics
@@ -1154,6 +1157,9 @@ struct drm_mode_config {
        /* whether async page flip is supported or not */
        bool async_page_flip;
 
+       /* whether the driver supports fb modifiers */
+       bool allow_fb_modifiers;
+
        /* cursor size */
        uint32_t cursor_width, cursor_height;
 };
@@ -1258,6 +1264,8 @@ extern int drm_plane_init(struct drm_device *dev,
 extern void drm_plane_cleanup(struct drm_plane *plane);
 extern unsigned int drm_plane_index(struct drm_plane *plane);
 extern void drm_plane_force_disable(struct drm_plane *plane);
+extern int drm_plane_check_pixel_format(const struct drm_plane *plane,
+                                       u32 format);
 extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
                                   int *hdisplay, int *vdisplay);
 extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
index c250a22b39aba09a58aa4d7843e6ae4e7033c524..92d5135b55d214e54cdff5bf83a33ceea7e83e2f 100644 (file)
@@ -89,6 +89,7 @@ struct drm_crtc_helper_funcs {
        int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
                        struct drm_display_mode *adjusted_mode, int x, int y,
                        struct drm_framebuffer *old_fb);
+       /* Actually set the mode for atomic helpers, optional */
        void (*mode_set_nofb)(struct drm_crtc *crtc);
 
        /* Move the crtc on the current fb to the given position *optional* */
@@ -119,7 +120,7 @@ struct drm_crtc_helper_funcs {
  * @mode_fixup: try to fixup proposed mode for this connector
  * @prepare: part of the disable sequence, called before the CRTC modeset
  * @commit: called after the CRTC modeset
- * @mode_set: set this mode
+ * @mode_set: set this mode, optional for atomic helpers
  * @get_crtc: return CRTC that the encoder is currently attached to
  * @detect: connection status detection
  * @disable: disable encoder when not in use (overrides DPMS off)
index 7e25030a6aa296e0eae8968e784abf963b7b5aa3..523f04c90dea45826af4a3de70a43d54896f6043 100644 (file)
@@ -42,6 +42,8 @@
  * 1.2 formally includes both eDP and DPI definitions.
  */
 
+#define DP_AUX_MAX_PAYLOAD_BYTES       16
+
 #define DP_AUX_I2C_WRITE               0x0
 #define DP_AUX_I2C_READ                        0x1
 #define DP_AUX_I2C_STATUS              0x2
 # define DP_MSA_TIMING_PAR_IGNORED         (1 << 6) /* eDP */
 # define DP_OUI_SUPPORT                            (1 << 7)
 
+#define DP_RECEIVE_PORT_0_CAP_0                    0x008
+# define DP_LOCAL_EDID_PRESENT             (1 << 1)
+# define DP_ASSOCIATED_TO_PRECEDING_PORT    (1 << 2)
+
+#define DP_RECEIVE_PORT_0_BUFFER_SIZE      0x009
+
+#define DP_RECEIVE_PORT_1_CAP_0                    0x00a
+#define DP_RECEIVE_PORT_1_BUFFER_SIZE       0x00b
+
 #define DP_I2C_SPEED_CAP                   0x00c    /* DPI */
 # define DP_I2C_SPEED_1K                   0x01
 # define DP_I2C_SPEED_5K                   0x02
 # define DP_I2C_SPEED_1M                   0x20
 
 #define DP_EDP_CONFIGURATION_CAP            0x00d   /* XXX 1.2? */
+# define DP_ALTERNATE_SCRAMBLER_RESET_CAP   (1 << 0)
+# define DP_FRAMING_CHANGE_CAP             (1 << 1)
+# define DP_DPCD_DISPLAY_CONTROL_CAPABLE     (1 << 3) /* edp v1.2 or higher */
+
 #define DP_TRAINING_AUX_RD_INTERVAL         0x00e   /* XXX 1.2? */
 
+#define DP_ADAPTER_CAP                     0x00f   /* 1.2 */
+# define DP_FORCE_LOAD_SENSE_CAP           (1 << 0)
+# define DP_ALTERNATE_I2C_PATTERN_CAP      (1 << 1)
+
+#define DP_SUPPORTED_LINK_RATES                    0x010 /* eDP 1.4 */
+# define DP_MAX_SUPPORTED_RATES                     8      /* 16-bit little-endian */
+
 /* Multiple stream transport */
 #define DP_FAUX_CAP                        0x020   /* 1.2 */
 # define DP_FAUX_CAP_1                     (1 << 0)
 #define DP_MSTM_CAP                        0x021   /* 1.2 */
 # define DP_MST_CAP                        (1 << 0)
 
+#define DP_NUMBER_OF_AUDIO_ENDPOINTS       0x022   /* 1.2 */
+
+/* AV_SYNC_DATA_BLOCK                                  1.2 */
+#define DP_AV_GRANULARITY                  0x023
+# define DP_AG_FACTOR_MASK                 (0xf << 0)
+# define DP_AG_FACTOR_3MS                  (0 << 0)
+# define DP_AG_FACTOR_2MS                  (1 << 0)
+# define DP_AG_FACTOR_1MS                  (2 << 0)
+# define DP_AG_FACTOR_500US                (3 << 0)
+# define DP_AG_FACTOR_200US                (4 << 0)
+# define DP_AG_FACTOR_100US                (5 << 0)
+# define DP_AG_FACTOR_10US                 (6 << 0)
+# define DP_AG_FACTOR_1US                  (7 << 0)
+# define DP_VG_FACTOR_MASK                 (0xf << 4)
+# define DP_VG_FACTOR_3MS                  (0 << 4)
+# define DP_VG_FACTOR_2MS                  (1 << 4)
+# define DP_VG_FACTOR_1MS                  (2 << 4)
+# define DP_VG_FACTOR_500US                (3 << 4)
+# define DP_VG_FACTOR_200US                (4 << 4)
+# define DP_VG_FACTOR_100US                (5 << 4)
+
+#define DP_AUD_DEC_LAT0                            0x024
+#define DP_AUD_DEC_LAT1                            0x025
+
+#define DP_AUD_PP_LAT0                     0x026
+#define DP_AUD_PP_LAT1                     0x027
+
+#define DP_VID_INTER_LAT                   0x028
+
+#define DP_VID_PROG_LAT                            0x029
+
+#define DP_REP_LAT                         0x02a
+
+#define DP_AUD_DEL_INS0                            0x02b
+#define DP_AUD_DEL_INS1                            0x02c
+#define DP_AUD_DEL_INS2                            0x02d
+/* End of AV_SYNC_DATA_BLOCK */
+
+#define DP_RECEIVER_ALPM_CAP               0x02e   /* eDP 1.4 */
+# define DP_ALPM_CAP                       (1 << 0)
+
+#define DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP   0x02f   /* eDP 1.4 */
+# define DP_AUX_FRAME_SYNC_CAP             (1 << 0)
+
 #define DP_GUID                                    0x030   /* 1.2 */
 
 #define DP_PSR_SUPPORT                      0x070   /* XXX 1.2? */
 # define DP_PSR_IS_SUPPORTED                1
+# define DP_PSR2_IS_SUPPORTED              2       /* eDP 1.4 */
+
 #define DP_PSR_CAPS                         0x071   /* XXX 1.2? */
 # define DP_PSR_NO_TRAIN_ON_EXIT            1
 # define DP_PSR_SETUP_TIME_330              (0 << 1)
 
 /* link configuration */
 #define        DP_LINK_BW_SET                      0x100
+# define DP_LINK_RATE_TABLE                0x00    /* eDP 1.4 */
 # define DP_LINK_BW_1_62                   0x06
 # define DP_LINK_BW_2_7                            0x0a
 # define DP_LINK_BW_5_4                            0x14    /* 1.2 */
 # define DP_TRAINING_PATTERN_3             3       /* 1.2 */
 # define DP_TRAINING_PATTERN_MASK          0x3
 
-# define DP_LINK_QUAL_PATTERN_DISABLE      (0 << 2)
-# define DP_LINK_QUAL_PATTERN_D10_2        (1 << 2)
-# define DP_LINK_QUAL_PATTERN_ERROR_RATE    (2 << 2)
-# define DP_LINK_QUAL_PATTERN_PRBS7        (3 << 2)
-# define DP_LINK_QUAL_PATTERN_MASK         (3 << 2)
+/* DPCD 1.1 only. For DPCD >= 1.2 see per-lane DP_LINK_QUAL_LANEn_SET */
+# define DP_LINK_QUAL_PATTERN_11_DISABLE    (0 << 2)
+# define DP_LINK_QUAL_PATTERN_11_D10_2     (1 << 2)
+# define DP_LINK_QUAL_PATTERN_11_ERROR_RATE (2 << 2)
+# define DP_LINK_QUAL_PATTERN_11_PRBS7     (3 << 2)
+# define DP_LINK_QUAL_PATTERN_11_MASK      (3 << 2)
 
 # define DP_RECOVERED_CLOCK_OUT_EN         (1 << 4)
 # define DP_LINK_SCRAMBLING_DISABLE        (1 << 5)
 /* bitmask as for DP_I2C_SPEED_CAP */
 
 #define DP_EDP_CONFIGURATION_SET            0x10a   /* XXX 1.2? */
+# define DP_ALTERNATE_SCRAMBLER_RESET_ENABLE (1 << 0)
+# define DP_FRAMING_CHANGE_ENABLE          (1 << 1)
+# define DP_PANEL_SELF_TEST_ENABLE         (1 << 7)
+
+#define DP_LINK_QUAL_LANE0_SET             0x10b   /* DPCD >= 1.2 */
+#define DP_LINK_QUAL_LANE1_SET             0x10c
+#define DP_LINK_QUAL_LANE2_SET             0x10d
+#define DP_LINK_QUAL_LANE3_SET             0x10e
+# define DP_LINK_QUAL_PATTERN_DISABLE      0
+# define DP_LINK_QUAL_PATTERN_D10_2        1
+# define DP_LINK_QUAL_PATTERN_ERROR_RATE    2
+# define DP_LINK_QUAL_PATTERN_PRBS7        3
+# define DP_LINK_QUAL_PATTERN_80BIT_CUSTOM  4
+# define DP_LINK_QUAL_PATTERN_HBR2_EYE      5
+# define DP_LINK_QUAL_PATTERN_MASK         7
+
+#define DP_TRAINING_LANE0_1_SET2           0x10f
+#define DP_TRAINING_LANE2_3_SET2           0x110
+# define DP_LANE02_POST_CURSOR2_SET_MASK    (3 << 0)
+# define DP_LANE02_MAX_POST_CURSOR2_REACHED (1 << 2)
+# define DP_LANE13_POST_CURSOR2_SET_MASK    (3 << 4)
+# define DP_LANE13_MAX_POST_CURSOR2_REACHED (1 << 6)
 
 #define DP_MSTM_CTRL                       0x111   /* 1.2 */
 # define DP_MST_EN                         (1 << 0)
 # define DP_UP_REQ_EN                      (1 << 1)
 # define DP_UPSTREAM_IS_SRC                (1 << 2)
 
+#define DP_AUDIO_DELAY0                            0x112   /* 1.2 */
+#define DP_AUDIO_DELAY1                            0x113
+#define DP_AUDIO_DELAY2                            0x114
+
+#define DP_LINK_RATE_SET                   0x115   /* eDP 1.4 */
+# define DP_LINK_RATE_SET_SHIFT                    0
+# define DP_LINK_RATE_SET_MASK             (7 << 0)
+
+#define DP_RECEIVER_ALPM_CONFIG                    0x116   /* eDP 1.4 */
+# define DP_ALPM_ENABLE                            (1 << 0)
+# define DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE  (1 << 1)
+
+#define DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF  0x117   /* eDP 1.4 */
+# define DP_AUX_FRAME_SYNC_ENABLE          (1 << 0)
+# define DP_IRQ_HPD_ENABLE                 (1 << 1)
+
+#define DP_UPSTREAM_DEVICE_DP_PWR_NEED     0x118   /* 1.2 */
+# define DP_PWR_NOT_NEEDED                 (1 << 0)
+
+#define DP_AUX_FRAME_SYNC_VALUE                    0x15c   /* eDP 1.4 */
+# define DP_AUX_FRAME_SYNC_VALID           (1 << 0)
+
 #define DP_PSR_EN_CFG                      0x170   /* XXX 1.2? */
 # define DP_PSR_ENABLE                     (1 << 0)
 # define DP_PSR_MAIN_LINK_ACTIVE           (1 << 1)
 # define DP_PSR_CRC_VERIFICATION           (1 << 2)
 # define DP_PSR_FRAME_CAPTURE              (1 << 3)
+# define DP_PSR_SELECTIVE_UPDATE           (1 << 4)
+# define DP_PSR_IRQ_HPD_WITH_CRC_ERRORS     (1 << 5)
 
 #define DP_ADAPTER_CTRL                            0x1a0
 # define DP_ADAPTER_CTRL_FORCE_LOAD_SENSE   (1 << 0)
 # define DP_SET_POWER_D3                    0x2
 # define DP_SET_POWER_MASK                  0x3
 
+#define DP_EDP_DPCD_REV                            0x700    /* eDP 1.2 */
+# define DP_EDP_11                         0x00
+# define DP_EDP_12                         0x01
+# define DP_EDP_13                         0x02
+# define DP_EDP_14                         0x03
+
+#define DP_EDP_GENERAL_CAP_1               0x701
+
+#define DP_EDP_BACKLIGHT_ADJUSTMENT_CAP     0x702
+
+#define DP_EDP_GENERAL_CAP_2               0x703
+
+#define DP_EDP_GENERAL_CAP_3               0x704    /* eDP 1.4 */
+
+#define DP_EDP_DISPLAY_CONTROL_REGISTER     0x720
+
+#define DP_EDP_BACKLIGHT_MODE_SET_REGISTER  0x721
+
+#define DP_EDP_BACKLIGHT_BRIGHTNESS_MSB     0x722
+#define DP_EDP_BACKLIGHT_BRIGHTNESS_LSB     0x723
+
+#define DP_EDP_PWMGEN_BIT_COUNT             0x724
+#define DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN     0x725
+#define DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX     0x726
+
+#define DP_EDP_BACKLIGHT_CONTROL_STATUS     0x727
+
+#define DP_EDP_BACKLIGHT_FREQ_SET           0x728
+
+#define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_MSB   0x72a
+#define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_MID   0x72b
+#define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_LSB   0x72c
+
+#define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_MSB   0x72d
+#define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_MID   0x72e
+#define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_LSB   0x72f
+
+#define DP_EDP_DBC_MINIMUM_BRIGHTNESS_SET   0x732
+#define DP_EDP_DBC_MAXIMUM_BRIGHTNESS_SET   0x733
+
+#define DP_EDP_REGIONAL_BACKLIGHT_BASE      0x740    /* eDP 1.4 */
+#define DP_EDP_REGIONAL_BACKLIGHT_0        0x741    /* eDP 1.4 */
+
 #define DP_SIDEBAND_MSG_DOWN_REQ_BASE      0x1000   /* 1.2 MST */
 #define DP_SIDEBAND_MSG_UP_REP_BASE        0x1200   /* 1.2 MST */
 #define DP_SIDEBAND_MSG_DOWN_REP_BASE      0x1400   /* 1.2 MST */
 #define DP_PSR_ERROR_STATUS                 0x2006  /* XXX 1.2? */
 # define DP_PSR_LINK_CRC_ERROR              (1 << 0)
 # define DP_PSR_RFB_STORAGE_ERROR           (1 << 1)
+# define DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR (1 << 2) /* eDP 1.4 */
 
 #define DP_PSR_ESI                          0x2007  /* XXX 1.2? */
 # define DP_PSR_CAPS_CHANGE                 (1 << 0)
 # define DP_PSR_SINK_INTERNAL_ERROR         7
 # define DP_PSR_SINK_STATE_MASK             0x07
 
+#define DP_RECEIVER_ALPM_STATUS                    0x200b  /* eDP 1.4 */
+# define DP_ALPM_LOCK_TIMEOUT_ERROR        (1 << 0)
+
 /* DP 1.2 Sideband message defines */
 /* peer device type - DP 1.2a Table 2-92 */
 #define DP_PEER_DEVICE_NONE            0x0
@@ -519,6 +682,9 @@ struct drm_dp_aux_msg {
  * transactions. The drm_dp_aux_register_i2c_bus() function registers an
  * I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers
  * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter.
+ * The I2C adapter uses long transfers by default; if a partial response is
+ * received, the adapter will drop down to the size given by the partial
+ * response for this transaction only.
  *
  * Note that the aux helper code assumes that the .transfer() function
  * only modifies the reply field of the drm_dp_aux_msg structure.  The
index 00c1da9272456e8e9bdec207affa286028664421..a2507817be4196606abe1cc038be09c612d6afd6 100644 (file)
@@ -486,6 +486,8 @@ int drm_dp_calc_pbn_mode(int clock, int bpp);
 
 bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int *slots);
 
+int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
+
 
 void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
 
index 21b944c456f69dceb9c4762384d04717d82b41ff..0dfd94def593526eaa7d5e414a85634f37509385 100644 (file)
@@ -44,6 +44,25 @@ struct drm_fb_helper_crtc {
        int x, y;
 };
 
+/**
+ * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
+ * @fb_width: fbdev width
+ * @fb_height: fbdev height
+ * @surface_width: scanout buffer width
+ * @surface_height: scanout buffer height
+ * @surface_bpp: scanout buffer bpp
+ * @surface_depth: scanout buffer depth
+ *
+ * Note that the scanout surface width/height may be larger than the fbdev
+ * width/height.  In case of multiple displays, the scanout surface is sized
+ * according to the largest width/height (so it is large enough for all CRTCs
+ * to scanout).  But the fbdev width/height is sized to the minimum width/
+ * height of all the displays.  This ensures that fbcon fits on the smallest
+ * of the attached displays.
+ *
+ * So what is passed to drm_fb_helper_fill_var() should be fb_width/fb_height,
+ * rather than the surface size.
+ */
 struct drm_fb_helper_surface_size {
        u32 fb_width;
        u32 fb_height;
index a24addfdfcec5568015e4e358402d6afa002e37a..0de6290df4da65f1511658c0ae0bc60bf24679fa 100644 (file)
@@ -68,8 +68,8 @@ struct drm_mm_node {
        unsigned scanned_preceeds_hole : 1;
        unsigned allocated : 1;
        unsigned long color;
-       unsigned long start;
-       unsigned long size;
+       u64 start;
+       u64 size;
        struct drm_mm *mm;
 };
 
@@ -82,16 +82,16 @@ struct drm_mm {
        unsigned int scan_check_range : 1;
        unsigned scan_alignment;
        unsigned long scan_color;
-       unsigned long scan_size;
-       unsigned long scan_hit_start;
-       unsigned long scan_hit_end;
+       u64 scan_size;
+       u64 scan_hit_start;
+       u64 scan_hit_end;
        unsigned scanned_blocks;
-       unsigned long scan_start;
-       unsigned long scan_end;
+       u64 scan_start;
+       u64 scan_end;
        struct drm_mm_node *prev_scanned_node;
 
        void (*color_adjust)(struct drm_mm_node *node, unsigned long color,
-                            unsigned long *start, unsigned long *end);
+                            u64 *start, u64 *end);
 };
 
 /**
@@ -124,7 +124,7 @@ static inline bool drm_mm_initialized(struct drm_mm *mm)
        return mm->hole_stack.next;
 }
 
-static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_node)
+static inline u64 __drm_mm_hole_node_start(struct drm_mm_node *hole_node)
 {
        return hole_node->start + hole_node->size;
 }
@@ -140,13 +140,13 @@ static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_no
  * Returns:
  * Start of the subsequent hole.
  */
-static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
+static inline u64 drm_mm_hole_node_start(struct drm_mm_node *hole_node)
 {
        BUG_ON(!hole_node->hole_follows);
        return __drm_mm_hole_node_start(hole_node);
 }
 
-static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
+static inline u64 __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
 {
        return list_entry(hole_node->node_list.next,
                          struct drm_mm_node, node_list)->start;
@@ -163,7 +163,7 @@ static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node
  * Returns:
  * End of the subsequent hole.
  */
-static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
+static inline u64 drm_mm_hole_node_end(struct drm_mm_node *hole_node)
 {
        return __drm_mm_hole_node_end(hole_node);
 }
@@ -222,7 +222,7 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node);
 
 int drm_mm_insert_node_generic(struct drm_mm *mm,
                               struct drm_mm_node *node,
-                              unsigned long size,
+                              u64 size,
                               unsigned alignment,
                               unsigned long color,
                               enum drm_mm_search_flags sflags,
@@ -245,7 +245,7 @@ int drm_mm_insert_node_generic(struct drm_mm *mm,
  */
 static inline int drm_mm_insert_node(struct drm_mm *mm,
                                     struct drm_mm_node *node,
-                                    unsigned long size,
+                                    u64 size,
                                     unsigned alignment,
                                     enum drm_mm_search_flags flags)
 {
@@ -255,11 +255,11 @@ static inline int drm_mm_insert_node(struct drm_mm *mm,
 
 int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
                                        struct drm_mm_node *node,
-                                       unsigned long size,
+                                       u64 size,
                                        unsigned alignment,
                                        unsigned long color,
-                                       unsigned long start,
-                                       unsigned long end,
+                                       u64 start,
+                                       u64 end,
                                        enum drm_mm_search_flags sflags,
                                        enum drm_mm_allocator_flags aflags);
 /**
@@ -282,10 +282,10 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
  */
 static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
                                              struct drm_mm_node *node,
-                                             unsigned long size,
+                                             u64 size,
                                              unsigned alignment,
-                                             unsigned long start,
-                                             unsigned long end,
+                                             u64 start,
+                                             u64 end,
                                              enum drm_mm_search_flags flags)
 {
        return drm_mm_insert_node_in_range_generic(mm, node, size, alignment,
@@ -296,21 +296,21 @@ static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
 void drm_mm_remove_node(struct drm_mm_node *node);
 void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);
 void drm_mm_init(struct drm_mm *mm,
-                unsigned long start,
-                unsigned long size);
+                u64 start,
+                u64 size);
 void drm_mm_takedown(struct drm_mm *mm);
 bool drm_mm_clean(struct drm_mm *mm);
 
 void drm_mm_init_scan(struct drm_mm *mm,
-                     unsigned long size,
+                     u64 size,
                      unsigned alignment,
                      unsigned long color);
 void drm_mm_init_scan_with_range(struct drm_mm *mm,
-                                unsigned long size,
+                                u64 size,
                                 unsigned alignment,
                                 unsigned long color,
-                                unsigned long start,
-                                unsigned long end);
+                                u64 start,
+                                u64 end);
 bool drm_mm_scan_add_block(struct drm_mm_node *node);
 bool drm_mm_scan_remove_block(struct drm_mm_node *node);
 
index d92f6dd1fb11fdfc5f1f648e21b9a8e9dc6f9322..0616188c7801c1f90e07bbd94f380a8233afb48d 100644 (file)
@@ -92,7 +92,7 @@ enum drm_mode_status {
 #define CRTC_STEREO_DOUBLE     (1 << 1) /* adjust timings for stereo modes */
 #define CRTC_NO_DBLSCAN                (1 << 2) /* don't adjust doublescan */
 #define CRTC_NO_VSCAN          (1 << 3) /* don't adjust doublescan */
-#define CRTC_STEREO_DOUBLE_ONLY        (CRTC_NO_DBLSCAN | CRTC_NO_VSCAN)
+#define CRTC_STEREO_DOUBLE_ONLY        (CRTC_STEREO_DOUBLE | CRTC_NO_DBLSCAN | CRTC_NO_VSCAN)
 
 #define DRM_MODE_FLAG_3D_MAX   DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF
 
index 31c11d36fae6e1ca285f56111bcc8ff93770db51..e48157a5a59ccad82ab8498a4876c7fe208c3dfc 100644 (file)
@@ -59,9 +59,11 @@ extern int drm_crtc_init(struct drm_device *dev,
  */
 struct drm_plane_helper_funcs {
        int (*prepare_fb)(struct drm_plane *plane,
-                         struct drm_framebuffer *fb);
+                         struct drm_framebuffer *fb,
+                         const struct drm_plane_state *new_state);
        void (*cleanup_fb)(struct drm_plane *plane,
-                          struct drm_framebuffer *fb);
+                          struct drm_framebuffer *fb,
+                          const struct drm_plane_state *old_state);
 
        int (*atomic_check)(struct drm_plane *plane,
                            struct drm_plane_state *state);
@@ -98,10 +100,6 @@ extern int drm_primary_helper_update(struct drm_plane *plane,
 extern int drm_primary_helper_disable(struct drm_plane *plane);
 extern void drm_primary_helper_destroy(struct drm_plane *plane);
 extern const struct drm_plane_funcs drm_primary_helper_funcs;
-extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
-                                                        const uint32_t *formats,
-                                                        int num_formats);
-
 
 int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
                            struct drm_framebuffer *fb,
index 180ad0e6de21dd3f0332335f90c122692a553838..613372375adac0b66028446d9de0f752986daf2e 100644 (file)
 #define INTEL_VLV_D_IDS(info) \
        INTEL_VGA_DEVICE(0x0155, info)
 
-#define _INTEL_BDW_M(gt, id, info) \
-       INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info)
-#define _INTEL_BDW_D(gt, id, info) \
-       INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info)
-
-#define _INTEL_BDW_M_IDS(gt, info) \
-       _INTEL_BDW_M(gt, 0x1602, info), /* ULT */ \
-       _INTEL_BDW_M(gt, 0x1606, info), /* ULT */ \
-       _INTEL_BDW_M(gt, 0x160B, info), /* Iris */ \
-       _INTEL_BDW_M(gt, 0x160E, info) /* ULX */
-
-#define _INTEL_BDW_D_IDS(gt, info) \
-       _INTEL_BDW_D(gt, 0x160A, info), /* Server */ \
-       _INTEL_BDW_D(gt, 0x160D, info) /* Workstation */
-
-#define INTEL_BDW_GT12M_IDS(info) \
-       _INTEL_BDW_M_IDS(1, info), \
-       _INTEL_BDW_M_IDS(2, info)
+#define INTEL_BDW_GT12M_IDS(info)  \
+       INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \
+       INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \
+       INTEL_VGA_DEVICE(0x160B, info), /* GT1 Iris */ \
+       INTEL_VGA_DEVICE(0x160E, info), /* GT1 ULX */ \
+       INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */ \
+       INTEL_VGA_DEVICE(0x1616, info), /* GT2 ULT */ \
+       INTEL_VGA_DEVICE(0x161B, info), /* GT2 ULT */ \
+       INTEL_VGA_DEVICE(0x161E, info)  /* GT2 ULX */
 
 #define INTEL_BDW_GT12D_IDS(info) \
-       _INTEL_BDW_D_IDS(1, info), \
-       _INTEL_BDW_D_IDS(2, info)
+       INTEL_VGA_DEVICE(0x160A, info), /* GT1 Server */ \
+       INTEL_VGA_DEVICE(0x160D, info), /* GT1 Workstation */ \
+       INTEL_VGA_DEVICE(0x161A, info), /* GT2 Server */ \
+       INTEL_VGA_DEVICE(0x161D, info)  /* GT2 Workstation */
 
 #define INTEL_BDW_GT3M_IDS(info) \
-       _INTEL_BDW_M_IDS(3, info)
+       INTEL_VGA_DEVICE(0x1622, info), /* ULT */ \
+       INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \
+       INTEL_VGA_DEVICE(0x162B, info), /* Iris */ \
+       INTEL_VGA_DEVICE(0x162E, info)  /* ULX */
 
 #define INTEL_BDW_GT3D_IDS(info) \
-       _INTEL_BDW_D_IDS(3, info)
+       INTEL_VGA_DEVICE(0x162A, info), /* Server */ \
+       INTEL_VGA_DEVICE(0x162D, info)  /* Workstation */
 
 #define INTEL_BDW_RSVDM_IDS(info) \
-       _INTEL_BDW_M_IDS(4, info)
+       INTEL_VGA_DEVICE(0x1632, info), /* ULT */ \
+       INTEL_VGA_DEVICE(0x1636, info), /* ULT */ \
+       INTEL_VGA_DEVICE(0x163B, info), /* Iris */ \
+       INTEL_VGA_DEVICE(0x163E, info)  /* ULX */
 
 #define INTEL_BDW_RSVDD_IDS(info) \
-       _INTEL_BDW_D_IDS(4, info)
+       INTEL_VGA_DEVICE(0x163A, info), /* Server */ \
+       INTEL_VGA_DEVICE(0x163D, info)  /* Workstation */
 
 #define INTEL_BDW_M_IDS(info) \
        INTEL_BDW_GT12M_IDS(info), \
        INTEL_VGA_DEVICE(0x22b2, info), \
        INTEL_VGA_DEVICE(0x22b3, info)
 
-#define INTEL_SKL_IDS(info) \
-       INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \
+#define INTEL_SKL_GT1_IDS(info)        \
        INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */ \
-       INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
-       INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \
        INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */ \
+       INTEL_VGA_DEVICE(0x1902, info), /* DT  GT1 */ \
+       INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \
+       INTEL_VGA_DEVICE(0x190A, info) /* SRV GT1 */
+
+#define INTEL_SKL_GT2_IDS(info)        \
+       INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \
+       INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \
        INTEL_VGA_DEVICE(0x191E, info), /* ULX GT2 */ \
        INTEL_VGA_DEVICE(0x1912, info), /* DT  GT2 */ \
-       INTEL_VGA_DEVICE(0x1902, info), /* DT  GT1 */ \
        INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */ \
-       INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
-       INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \
        INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */ \
-       INTEL_VGA_DEVICE(0x192A, info), /* SRV GT3 */ \
-       INTEL_VGA_DEVICE(0x190A, info), /* SRV GT1 */ \
        INTEL_VGA_DEVICE(0x191D, info)  /* WKS GT2 */
 
+#define INTEL_SKL_GT3_IDS(info) \
+       INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
+       INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
+       INTEL_VGA_DEVICE(0x192A, info) /* SRV GT3 */ \
+
+#define INTEL_SKL_IDS(info) \
+       INTEL_SKL_GT1_IDS(info), \
+       INTEL_SKL_GT2_IDS(info), \
+       INTEL_SKL_GT3_IDS(info)
+
+
 #endif /* _I915_PCIIDS_H */
index 0ccf7f267ff94408387d71da446cc89ab1caf6fa..c768ddfbe53ccbbfeedd92809a9d4036adfc1fe2 100644 (file)
@@ -249,7 +249,7 @@ struct ttm_buffer_object {
         * either of these locks held.
         */
 
-       unsigned long offset;
+       uint64_t offset; /* GPU address space is independent of CPU word size */
        uint32_t cur_placement;
 
        struct sg_table *sg;
index 142d752fc450b74b60e964dd6a5c3d12ba38b163..813042cede5728a1bc3e8d463006217d49f35483 100644 (file)
@@ -277,7 +277,7 @@ struct ttm_mem_type_manager {
        bool has_type;
        bool use_type;
        uint32_t flags;
-       unsigned long gpu_offset;
+       uint64_t gpu_offset; /* GPU address space is independent of CPU word size */
        uint64_t size;
        uint32_t available_caching;
        uint32_t default_caching;
index 2fbc804e1a45cea943c9241309601f941abd5d14..226f77246a70c689f34c6720f1796cf59b4b8a3b 100644 (file)
@@ -13,7 +13,8 @@
 
 #define PULL_DISABLE           (1 << 3)
 #define INPUT_EN               (1 << 5)
-#define SLEWCTRL_FAST          (1 << 6)
+#define SLEWCTRL_SLOW          (1 << 6)
+#define SLEWCTRL_FAST          0
 
 /* update macro depending on INPUT_EN and PULL_ENA */
 #undef PIN_OUTPUT
index 9c2e4f82381e8abc7b21ac59447fefb84d5a1ea3..5f4d01898c9c153ff73feebd46930524a2d50a4d 100644 (file)
@@ -18,7 +18,8 @@
 #define PULL_DISABLE           (1 << 16)
 #define PULL_UP                        (1 << 17)
 #define INPUT_EN               (1 << 18)
-#define SLEWCTRL_FAST          (1 << 19)
+#define SLEWCTRL_SLOW          (1 << 19)
+#define SLEWCTRL_FAST          0
 #define DS0_PULL_UP_DOWN_EN    (1 << 27)
 
 #define PIN_OUTPUT             (PULL_DISABLE)
index 7c55dd5dd2c9faf2202692ca5f669f064c173ed4..66203b268984ebedd72d5bd1b2f54440e56011bc 100644 (file)
@@ -114,6 +114,7 @@ struct vgic_ops {
        void    (*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr);
        u64     (*get_elrsr)(const struct kvm_vcpu *vcpu);
        u64     (*get_eisr)(const struct kvm_vcpu *vcpu);
+       void    (*clear_eisr)(struct kvm_vcpu *vcpu);
        u32     (*get_interrupt_status)(const struct kvm_vcpu *vcpu);
        void    (*enable_underflow)(struct kvm_vcpu *vcpu);
        void    (*disable_underflow)(struct kvm_vcpu *vcpu);
index 8381bbfbc3085bcde157c02ea7234826f757a1e8..68c16a6bedb36462c3cec290c9eee81abe2072f9 100644 (file)
@@ -125,6 +125,19 @@ int clk_set_phase(struct clk *clk, int degrees);
  */
 int clk_get_phase(struct clk *clk);
 
+/**
+ * clk_is_match - check if two clk's point to the same hardware clock
+ * @p: clk compared against q
+ * @q: clk compared against p
+ *
+ * Returns true if the two struct clk pointers both point to the same hardware
+ * clock node. Put differently, returns true if struct clk *p and struct clk *q
+ * share the same struct clk_core object.
+ *
+ * Returns false otherwise. Note that two NULL clks are treated as matching.
+ */
+bool clk_is_match(const struct clk *p, const struct clk *q);
+
 #else
 
 static inline long clk_get_accuracy(struct clk *clk)
@@ -142,6 +155,11 @@ static inline long clk_get_phase(struct clk *clk)
        return -ENOTSUPP;
 }
 
+static inline bool clk_is_match(const struct clk *p, const struct clk *q)
+{
+       return p == q;
+}
+
 #endif
 
 /**
index f551a9299ac987c5121a6f58383a953a8704d729..306178d7309f193cb32443f49c888297ffa9573e 100644 (file)
@@ -126,6 +126,8 @@ struct cpuidle_driver {
 
 #ifdef CONFIG_CPU_IDLE
 extern void disable_cpuidle(void);
+extern bool cpuidle_not_available(struct cpuidle_driver *drv,
+                                 struct cpuidle_device *dev);
 
 extern int cpuidle_select(struct cpuidle_driver *drv,
                          struct cpuidle_device *dev);
@@ -150,11 +152,17 @@ extern void cpuidle_resume(void);
 extern int cpuidle_enable_device(struct cpuidle_device *dev);
 extern void cpuidle_disable_device(struct cpuidle_device *dev);
 extern int cpuidle_play_dead(void);
-extern void cpuidle_enter_freeze(void);
+extern int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
+                                     struct cpuidle_device *dev);
+extern int cpuidle_enter_freeze(struct cpuidle_driver *drv,
+                               struct cpuidle_device *dev);
 
 extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev);
 #else
 static inline void disable_cpuidle(void) { }
+static inline bool cpuidle_not_available(struct cpuidle_driver *drv,
+                                        struct cpuidle_device *dev)
+{return true; }
 static inline int cpuidle_select(struct cpuidle_driver *drv,
                                 struct cpuidle_device *dev)
 {return -ENODEV; }
@@ -183,7 +191,12 @@ static inline int cpuidle_enable_device(struct cpuidle_device *dev)
 {return -ENODEV; }
 static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
 static inline int cpuidle_play_dead(void) {return -ENODEV; }
-static inline void cpuidle_enter_freeze(void) { }
+static inline int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
+                                            struct cpuidle_device *dev)
+{return -ENODEV; }
+static inline int cpuidle_enter_freeze(struct cpuidle_driver *drv,
+                                      struct cpuidle_device *dev)
+{return -ENODEV; }
 static inline struct cpuidle_driver *cpuidle_get_cpu_driver(
        struct cpuidle_device *dev) {return NULL; }
 #endif
index 2646aed1d3fedad16a773eaa366edad3ab44bad5..fd23978d93fe35a91afab5f56d3611c0324d9ceb 100644 (file)
@@ -375,6 +375,7 @@ int dm_create(int minor, struct mapped_device **md);
  */
 struct mapped_device *dm_get_md(dev_t dev);
 void dm_get(struct mapped_device *md);
+int dm_hold(struct mapped_device *md);
 void dm_put(struct mapped_device *md);
 
 /*
index 51f7ccadf923c337ddb5627491a958c5e74fa610..4173a8fdad9efd052870b8738547ac1fa1962526 100644 (file)
@@ -33,6 +33,8 @@
  * @units:             Measurment unit for this attribute.
  * @unit_expo:         Exponent used in the data.
  * @size:              Size in bytes for data size.
+ * @logical_minimum:   Logical minimum value for this attribute.
+ * @logical_maximum:   Logical maximum value for this attribute.
  */
 struct hid_sensor_hub_attribute_info {
        u32 usage_id;
@@ -146,6 +148,7 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
 
 /**
 * sensor_hub_input_attr_get_raw_value() - Synchronous read request
+* @hsdev:      Hub device instance.
 * @usage_id:   Attribute usage id of parent physical device as per spec
 * @attr_usage_id:      Attribute usage id as per spec
 * @report_id:  Report id to look for
@@ -160,6 +163,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
                        u32 attr_usage_id, u32 report_id);
 /**
 * sensor_hub_set_feature() - Feature set request
+* @hsdev:      Hub device instance.
 * @report_id:  Report id to look for
 * @field_index:        Field index inside a report
 * @value:      Value to set
@@ -172,6 +176,7 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
 
 /**
 * sensor_hub_get_feature() - Feature get request
+* @hsdev:      Hub device instance.
 * @report_id:  Report id to look for
 * @field_index:        Field index inside a report
 * @value:      Place holder for return value
index 464f33814a94d0ccf82f20b69041188fedb96b59..d2ba7d334039ec2f7660eaabfb94fd4446a65018 100644 (file)
@@ -135,6 +135,7 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id);
 u32 host1x_syncpt_id(struct host1x_syncpt *sp);
 u32 host1x_syncpt_read_min(struct host1x_syncpt *sp);
 u32 host1x_syncpt_read_max(struct host1x_syncpt *sp);
+u32 host1x_syncpt_read(struct host1x_syncpt *sp);
 int host1x_syncpt_incr(struct host1x_syncpt *sp);
 u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
 int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
index d9b05b5bf8c7954f63ace548e0a6348f5fa0e327..2e88580194f0238430de1255c5a63f99bf975e0a 100644 (file)
  * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
  *                Used by threaded interrupts which need to keep the
  *                irq line disabled until the threaded handler has been run.
- * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
+ * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend.  Does not guarantee
+ *                   that this interrupt will wake the system from a suspended
+ *                   state.  See Documentation/power/suspend-and-interrupts.txt
  * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
  * IRQF_NO_THREAD - Interrupt cannot be threaded
  * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device
  *                resume time.
+ * IRQF_COND_SUSPEND - If the IRQ is shared with a NO_SUSPEND user, execute this
+ *                interrupt handler after suspending interrupts. For system
+ *                wakeup devices users need to implement wakeup detection in
+ *                their interrupt handlers.
  */
 #define IRQF_DISABLED          0x00000020
 #define IRQF_SHARED            0x00000080
@@ -70,6 +76,7 @@
 #define IRQF_FORCE_RESUME      0x00008000
 #define IRQF_NO_THREAD         0x00010000
 #define IRQF_EARLY_RESUME      0x00020000
+#define IRQF_COND_SUSPEND      0x00040000
 
 #define IRQF_TIMER             (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
 
index 800544bc7bfdd7f0fdda6fb96e6be104870d9d9a..781974afff9f14e576a7912039a5fb68009cdb25 100644 (file)
 
 #define GITS_TRANSLATER                        0x10040
 
+#define GITS_CTLR_ENABLE               (1U << 0)
+#define GITS_CTLR_QUIESCENT            (1U << 31)
+
+#define GITS_TYPER_DEVBITS_SHIFT       13
+#define GITS_TYPER_DEVBITS(r)          ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
 #define GITS_TYPER_PTA                 (1UL << 19)
 
 #define GITS_CBASER_VALID              (1UL << 63)
index faf433af425e41e2da532939af63ec258f8fd619..dd1109fb241e42263e5851ddbc325f469c42a87c 100644 (file)
@@ -78,6 +78,7 @@ struct irq_desc {
 #ifdef CONFIG_PM_SLEEP
        unsigned int            nr_actions;
        unsigned int            no_suspend_depth;
+       unsigned int            cond_suspend_depth;
        unsigned int            force_resume_depth;
 #endif
 #ifdef CONFIG_PROC_FS
index 72ba725ddf9c73054533256a7246f5425c95771b..5bb074431eb0ce571b32d785b45ad85ee8c22b34 100644 (file)
@@ -5,6 +5,7 @@
 
 struct kmem_cache;
 struct page;
+struct vm_struct;
 
 #ifdef CONFIG_KASAN
 
@@ -49,15 +50,11 @@ void kasan_krealloc(const void *object, size_t new_size);
 void kasan_slab_alloc(struct kmem_cache *s, void *object);
 void kasan_slab_free(struct kmem_cache *s, void *object);
 
-#define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
-
 int kasan_module_alloc(void *addr, size_t size);
-void kasan_module_free(void *addr);
+void kasan_free_shadow(const struct vm_struct *vm);
 
 #else /* CONFIG_KASAN */
 
-#define MODULE_ALIGN 1
-
 static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
 
 static inline void kasan_enable_current(void) {}
@@ -82,7 +79,7 @@ static inline void kasan_slab_alloc(struct kmem_cache *s, void *object) {}
 static inline void kasan_slab_free(struct kmem_cache *s, void *object) {}
 
 static inline int kasan_module_alloc(void *addr, size_t size) { return 0; }
-static inline void kasan_module_free(void *addr) {}
+static inline void kasan_free_shadow(const struct vm_struct *vm) {}
 
 #endif /* CONFIG_KASAN */
 
index fc03efa64ffe58ae9aa81e77bf60e5d7b4acc6c7..6b08cc106c218dc06d60988663c4bcac3eaba5fe 100644 (file)
@@ -232,6 +232,7 @@ enum {
                                              * led */
        ATA_FLAG_NO_DIPM        = (1 << 23), /* host not happy with DIPM */
        ATA_FLAG_LOWTAG         = (1 << 24), /* host wants lowest available tag */
+       ATA_FLAG_SAS_HOST       = (1 << 25), /* SAS host */
 
        /* bits 24:31 of ap->flags are reserved for LLD specific flags */
 
index fb0390a1a498f29df135bbe7500c1dfcc00a27d7..ee7b1ce7a6f8f42280abcc3d1411f7bcdebb6ac2 100644 (file)
@@ -2999,6 +2999,9 @@ enum usb_irq_events {
 #define PALMAS_GPADC_TRIM15                                    0x0E
 #define PALMAS_GPADC_TRIM16                                    0x0F
 
+/* TPS659038 regen2_ctrl offset iss different from palmas */
+#define TPS659038_REGEN2_CTRL                                  0x12
+
 /* TPS65917 Interrupt registers */
 
 /* Registers for function INTERRUPT */
index 2bbc62aa818a374d1c488f2eecf4232230bd3f4e..551f85456c11574a144bf64d1c38ec8031313b3e 100644 (file)
@@ -427,7 +427,7 @@ struct mlx4_wqe_inline_seg {
 
 enum mlx4_update_qp_attr {
        MLX4_UPDATE_QP_SMAC             = 1 << 0,
-       MLX4_UPDATE_QP_VSD              = 1 << 2,
+       MLX4_UPDATE_QP_VSD              = 1 << 1,
        MLX4_UPDATE_QP_SUPPORTED_ATTRS  = (1 << 2) - 1
 };
 
index 42999fe2dbd0fb8ec057dbd07d4c2143d6225c65..b03485bcb82a0a4d1f6ebbbac8b30f37beb722a2 100644 (file)
@@ -344,6 +344,10 @@ struct module {
        unsigned long *ftrace_callsites;
 #endif
 
+#ifdef CONFIG_LIVEPATCH
+       bool klp_alive;
+#endif
+
 #ifdef CONFIG_MODULE_UNLOAD
        /* What modules depend on me? */
        struct list_head source_list;
index f7556261fe3c54adb52b28789b7cb7b19b280b13..4d0cb9bba93e4650d76b314cc50160e5b8e7e65d 100644 (file)
@@ -84,4 +84,12 @@ void module_arch_cleanup(struct module *mod);
 
 /* Any cleanup before freeing mod->module_init */
 void module_arch_freeing_init(struct module *mod);
+
+#ifdef CONFIG_KASAN
+#include <linux/kasan.h>
+#define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
+#else
+#define MODULE_ALIGN PAGE_SIZE
+#endif
+
 #endif
index 5897b4ea5a3f9e0f07f511f57d8fa8bfe7019205..dcf6ec27739b1d8bfb98c82e8902ca0b697df5f8 100644 (file)
@@ -965,9 +965,12 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  *     Used to add FDB entries to dump requests. Implementers should add
  *     entries to skb and update idx with the number of entries.
  *
- * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh)
+ * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh,
+ *                          u16 flags)
  * int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq,
  *                          struct net_device *dev, u32 filter_mask)
+ * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
+ *                          u16 flags);
  *
  * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
  *     Called to change device carrier. Soft-devices (like dummy, team, etc)
@@ -2342,6 +2345,7 @@ struct gro_remcsum {
 
 static inline void skb_gro_remcsum_init(struct gro_remcsum *grc)
 {
+       grc->offset = 0;
        grc->delta = 0;
 }
 
index 2f77e0c651c89874a641c8a04a723aaf60dd2837..b01ccf371fdcaf229f07bddbd2f12f9bbb5c53b0 100644 (file)
@@ -343,6 +343,7 @@ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
 extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
+extern int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
 extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
@@ -355,8 +356,9 @@ extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
 extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
+extern int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping);
 extern int nfs_setattr(struct dentry *, struct iattr *);
-extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
+extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *);
 extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
                                struct nfs4_label *label);
 extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
@@ -369,6 +371,7 @@ extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ct
 extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx);
 extern u64 nfs_compat_user_ino64(u64 fileid);
 extern void nfs_fattr_init(struct nfs_fattr *fattr);
+extern void nfs_fattr_set_barrier(struct nfs_fattr *fattr);
 extern unsigned long nfs_inc_attr_generation_counter(void);
 
 extern struct nfs_fattr *nfs_alloc_fattr(void);
index 8a860f096c351fa93267dabaebab8f3c7605ac18..611a691145c48d7c38c370daa63b047b5c68c17a 100644 (file)
@@ -84,7 +84,7 @@ static inline int of_platform_populate(struct device_node *root,
 static inline void of_platform_depopulate(struct device *parent) { }
 #endif
 
-#ifdef CONFIG_OF_DYNAMIC
+#if defined(CONFIG_OF_DYNAMIC) && defined(CONFIG_OF_ADDRESS)
 extern void of_platform_register_reconfig_notifier(void);
 #else
 static inline void of_platform_register_reconfig_notifier(void) { }
index 72c0415d6c21758d31fcd2ab80c33751e41489d5..18eccefea06e40a0ea10f77e857105c6feaf4ff9 100644 (file)
@@ -82,7 +82,7 @@ static inline int pinctrl_gpio_direction_output(unsigned gpio)
 
 static inline struct pinctrl * __must_check pinctrl_get(struct device *dev)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline void pinctrl_put(struct pinctrl *p)
@@ -93,7 +93,7 @@ static inline struct pinctrl_state * __must_check pinctrl_lookup_state(
                                                        struct pinctrl *p,
                                                        const char *name)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline int pinctrl_select_state(struct pinctrl *p,
@@ -104,7 +104,7 @@ static inline int pinctrl_select_state(struct pinctrl *p,
 
 static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline void devm_pinctrl_put(struct pinctrl *p)
index d4ad5b5a02bb478a422b349406efba00997bab76..045f709cb89b52c5e2381635b0bea10101030120 100644 (file)
@@ -316,7 +316,7 @@ struct regulator_desc {
  * @driver_data: private regulator data
  * @of_node: OpenFirmware node to parse for device tree bindings (may be
  *           NULL).
- * @regmap: regmap to use for core regmap helpers if dev_get_regulator() is
+ * @regmap: regmap to use for core regmap helpers if dev_get_regmap() is
  *          insufficient.
  * @ena_gpio_initialized: GPIO controlling regulator enable was properly
  *                        initialized, meaning that >= 0 is a valid gpio
index 58851275fed98c352fdd4995e95f1ebe806649e7..d438eeb08bff407043b32d5f52f58d08fac8838f 100644 (file)
@@ -54,10 +54,11 @@ struct rhash_head {
  * @buckets: size * hash buckets
  */
 struct bucket_table {
-       size_t                          size;
-       unsigned int                    locks_mask;
-       spinlock_t                      *locks;
-       struct rhash_head __rcu         *buckets[];
+       size_t                  size;
+       unsigned int            locks_mask;
+       spinlock_t              *locks;
+
+       struct rhash_head __rcu *buckets[] ____cacheline_aligned_in_smp;
 };
 
 typedef u32 (*rht_hashfn_t)(const void *data, u32 len, u32 seed);
@@ -78,12 +79,6 @@ struct rhashtable;
  * @locks_mul: Number of bucket locks to allocate per cpu (default: 128)
  * @hashfn: Function to hash key
  * @obj_hashfn: Function to hash object
- * @grow_decision: If defined, may return true if table should expand
- * @shrink_decision: If defined, may return true if table should shrink
- *
- * Note: when implementing the grow and shrink decision function, min/max
- * shift must be enforced, otherwise, resizing watermarks they set may be
- * useless.
  */
 struct rhashtable_params {
        size_t                  nelem_hint;
@@ -97,10 +92,6 @@ struct rhashtable_params {
        size_t                  locks_mul;
        rht_hashfn_t            hashfn;
        rht_obj_hashfn_t        obj_hashfn;
-       bool                    (*grow_decision)(const struct rhashtable *ht,
-                                                size_t new_size);
-       bool                    (*shrink_decision)(const struct rhashtable *ht,
-                                                  size_t new_size);
 };
 
 /**
@@ -192,9 +183,6 @@ int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params);
 void rhashtable_insert(struct rhashtable *ht, struct rhash_head *node);
 bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *node);
 
-bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size);
-bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size);
-
 int rhashtable_expand(struct rhashtable *ht);
 int rhashtable_shrink(struct rhashtable *ht);
 
index 6d77432e14ff971bffd4ca211dccb917768b2c8c..a419b65770d669c3a51c88a86a145abbcd3db339 100644 (file)
@@ -1625,11 +1625,11 @@ struct task_struct {
 
        /*
         * numa_faults_locality tracks if faults recorded during the last
-        * scan window were remote/local. The task scan period is adapted
-        * based on the locality of the faults with different weights
-        * depending on whether they were shared or private faults
+        * scan window were remote/local or failed to migrate. The task scan
+        * period is adapted based on the locality of the faults with different
+        * weights depending on whether they were shared or private faults
         */
-       unsigned long numa_faults_locality[2];
+       unsigned long numa_faults_locality[3];
 
        unsigned long numa_pages_migrated;
 #endif /* CONFIG_NUMA_BALANCING */
@@ -1719,6 +1719,7 @@ struct task_struct {
 #define TNF_NO_GROUP   0x02
 #define TNF_SHARED     0x04
 #define TNF_FAULT_LOCAL        0x08
+#define TNF_MIGRATE_FAIL 0x10
 
 #ifdef CONFIG_NUMA_BALANCING
 extern void task_numa_fault(int last_node, int node, int pages, int flags);
index baf3e1d08416faaf34edd51bca72c2801e7e7e06..d10965f0d8a4af6526a07046ba040ae9708279a4 100644 (file)
@@ -143,13 +143,13 @@ struct uart_port {
        unsigned char           iotype;                 /* io access style */
        unsigned char           unused1;
 
-#define UPIO_PORT              (0)                     /* 8b I/O port access */
-#define UPIO_HUB6              (1)                     /* Hub6 ISA card */
-#define UPIO_MEM               (2)                     /* 8b MMIO access */
-#define UPIO_MEM32             (3)                     /* 32b little endian */
-#define UPIO_MEM32BE           (4)                     /* 32b big endian */
-#define UPIO_AU                        (5)                     /* Au1x00 and RT288x type IO */
-#define UPIO_TSI               (6)                     /* Tsi108/109 type IO */
+#define UPIO_PORT              (SERIAL_IO_PORT)        /* 8b I/O port access */
+#define UPIO_HUB6              (SERIAL_IO_HUB6)        /* Hub6 ISA card */
+#define UPIO_MEM               (SERIAL_IO_MEM)         /* 8b MMIO access */
+#define UPIO_MEM32             (SERIAL_IO_MEM32)       /* 32b little endian */
+#define UPIO_AU                        (SERIAL_IO_AU)          /* Au1x00 and RT288x type IO */
+#define UPIO_TSI               (SERIAL_IO_TSI)         /* Tsi108/109 type IO */
+#define UPIO_MEM32BE           (SERIAL_IO_MEM32BE)     /* 32b big endian */
 
        unsigned int            read_status_mask;       /* driver specific */
        unsigned int            ignore_status_mask;     /* driver specific */
index 30007afe70b3541cdb4300919c2a5cfbbc0063f2..f54d6659713ae76e96391334dba700eac8be122f 100644 (file)
@@ -948,6 +948,13 @@ static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
        to->l4_hash = from->l4_hash;
 };
 
+static inline void skb_sender_cpu_clear(struct sk_buff *skb)
+{
+#ifdef CONFIG_XPS
+       skb->sender_cpu = 0;
+#endif
+}
+
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
 {
index ed9489d893a487f250868f8de603c84e707feaf8..856d34dde79bc9d81faae4171fb0c5492829c133 100644 (file)
@@ -649,7 +649,7 @@ struct spi_transfer {
  * sequence completes.  On some systems, many such sequences can execute as
  * as single programmed DMA transfer.  On all systems, these messages are
  * queued, and might complete after transactions to other devices.  Messages
- * sent to a given spi_device are alway executed in FIFO order.
+ * sent to a given spi_device are always executed in FIFO order.
  *
  * The code that submits an spi_message (and its spi_transfers)
  * to the lower layers is responsible for managing its memory.
index fc52e307efab8768effbb7880702986653e0a07c..5eac316490eab9ca0ad1a864be2b6fedb823f332 100644 (file)
@@ -314,6 +314,8 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
 }
 
 #endif
+
+#if IS_ENABLED(CONFIG_THERMAL)
 struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
                void *, struct thermal_zone_device_ops *,
                const struct thermal_zone_params *, int, int);
@@ -340,8 +342,58 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
                struct thermal_cooling_device *, int);
 void thermal_cdev_update(struct thermal_cooling_device *);
 void thermal_notify_framework(struct thermal_zone_device *, int);
-
-#ifdef CONFIG_NET
+#else
+static inline struct thermal_zone_device *thermal_zone_device_register(
+       const char *type, int trips, int mask, void *devdata,
+       struct thermal_zone_device_ops *ops,
+       const struct thermal_zone_params *tzp,
+       int passive_delay, int polling_delay)
+{ return ERR_PTR(-ENODEV); }
+static inline void thermal_zone_device_unregister(
+       struct thermal_zone_device *tz)
+{ }
+static inline int thermal_zone_bind_cooling_device(
+       struct thermal_zone_device *tz, int trip,
+       struct thermal_cooling_device *cdev,
+       unsigned long upper, unsigned long lower)
+{ return -ENODEV; }
+static inline int thermal_zone_unbind_cooling_device(
+       struct thermal_zone_device *tz, int trip,
+       struct thermal_cooling_device *cdev)
+{ return -ENODEV; }
+static inline void thermal_zone_device_update(struct thermal_zone_device *tz)
+{ }
+static inline struct thermal_cooling_device *
+thermal_cooling_device_register(char *type, void *devdata,
+       const struct thermal_cooling_device_ops *ops)
+{ return ERR_PTR(-ENODEV); }
+static inline struct thermal_cooling_device *
+thermal_of_cooling_device_register(struct device_node *np,
+       char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
+{ return ERR_PTR(-ENODEV); }
+static inline void thermal_cooling_device_unregister(
+       struct thermal_cooling_device *cdev)
+{ }
+static inline struct thermal_zone_device *thermal_zone_get_zone_by_name(
+               const char *name)
+{ return ERR_PTR(-ENODEV); }
+static inline int thermal_zone_get_temp(
+               struct thermal_zone_device *tz, unsigned long *temp)
+{ return -ENODEV; }
+static inline int get_tz_trend(struct thermal_zone_device *tz, int trip)
+{ return -ENODEV; }
+static inline struct thermal_instance *
+get_thermal_instance(struct thermal_zone_device *tz,
+       struct thermal_cooling_device *cdev, int trip)
+{ return ERR_PTR(-ENODEV); }
+static inline void thermal_cdev_update(struct thermal_cooling_device *cdev)
+{ }
+static inline void thermal_notify_framework(struct thermal_zone_device *tz,
+       int trip)
+{ }
+#endif /* CONFIG_THERMAL */
+
+#if defined(CONFIG_NET) && IS_ENABLED(CONFIG_THERMAL)
 extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
                                                enum events event);
 #else
index 07a022641996f0ccf74cd872ccd9e4bc8aa5f538..71880299ed487b68dc7b278248a4fb29ddb6b6ec 100644 (file)
@@ -98,6 +98,8 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
                        size_t maxsize, size_t *start);
 int iov_iter_npages(const struct iov_iter *i, int maxpages);
 
+const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags);
+
 static inline size_t iov_iter_count(struct iov_iter *i)
 {
        return i->count;
index 9bb547c7bce7c7ce0942fdb4e313188d4878b371..704a1ab8240ca124f29c5ce361c871090d28ea5b 100644 (file)
@@ -190,8 +190,7 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
  * @num_ports: the number of different ports this device will have.
  * @bulk_in_size: minimum number of bytes to allocate for bulk-in buffer
  *     (0 = end-point size)
- * @bulk_out_size: minimum number of bytes to allocate for bulk-out buffer
- *     (0 = end-point size)
+ * @bulk_out_size: bytes to allocate for bulk-out buffer (0 = end-point size)
  * @calc_num_ports: pointer to a function to determine how many ports this
  *     device has dynamically.  It will be called after the probe()
  *     callback is called, but before attach()
index 7d7acb35603d6d6e4bb8a468fcb635d666fea001..0ec598381f9766182db52f246afc2f0a5f28b36f 100644 (file)
@@ -17,6 +17,7 @@ struct vm_area_struct;                /* vma defining user mapping in mm_types.h */
 #define VM_VPAGES              0x00000010      /* buffer for pages was vmalloc'ed */
 #define VM_UNINITIALIZED       0x00000020      /* vm_struct is not fully initialized */
 #define VM_NO_GUARD            0x00000040      /* don't add guard page */
+#define VM_KASAN               0x00000080      /* has allocated kasan shadow memory */
 /* bits [20..32] reserved for arch specific ioremap internals */
 
 /*
index 74db135f99571e37f61e0aecc34d7b5ddba66756..f597846ff605cccaaf36d3cc4e6d603b630af156 100644 (file)
@@ -70,7 +70,8 @@ enum {
        /* data contains off-queue information when !WORK_STRUCT_PWQ */
        WORK_OFFQ_FLAG_BASE     = WORK_STRUCT_COLOR_SHIFT,
 
-       WORK_OFFQ_CANCELING     = (1 << WORK_OFFQ_FLAG_BASE),
+       __WORK_OFFQ_CANCELING   = WORK_OFFQ_FLAG_BASE,
+       WORK_OFFQ_CANCELING     = (1 << __WORK_OFFQ_CANCELING),
 
        /*
         * When a work item is off queue, its high bits point to the last
index 1c1ad46250d5c9e0abb0910f1b7debaa6aaa9608..fe328c52c46bd179b651d6bbb14e58a89f017557 100644 (file)
@@ -171,7 +171,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos);
  * @return    Checksum of buffer.
  */
 
-u16 cfpkt_iterate(struct cfpkt *pkt,
+int cfpkt_iterate(struct cfpkt *pkt,
                u16 (*iter_func)(u16 chks, void *buf, u16 len),
                u16 data);
 
index a8ae4e760778d8fe49ff21951bd1e088ac3aefca..0fb99a26e97372613da1851d9ee4d9bb432aba3f 100644 (file)
@@ -481,6 +481,7 @@ void dst_init(void);
 enum {
        XFRM_LOOKUP_ICMP = 1 << 0,
        XFRM_LOOKUP_QUEUE = 1 << 1,
+       XFRM_LOOKUP_KEEP_DST_REF = 1 << 2,
 };
 
 struct flowi;
index 534e1f2ac4fc36d5baeb7b3115dc95aaebd065d9..57639fca223a69823a48cecff03078387a917084 100644 (file)
@@ -79,6 +79,16 @@ void nf_log_packet(struct net *net,
                   const struct nf_loginfo *li,
                   const char *fmt, ...);
 
+__printf(8, 9)
+void nf_log_trace(struct net *net,
+                 u_int8_t pf,
+                 unsigned int hooknum,
+                 const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct nf_loginfo *li,
+                 const char *fmt, ...);
+
 struct nf_log_buf;
 
 struct nf_log_buf *nf_log_buf_open(void);
index 9eaaa788458607004cb5f160e77c38de02da17ec..decb9a095ae7c4df5ace79f366762138c223958c 100644 (file)
@@ -119,6 +119,22 @@ int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
                           const struct nft_data *data,
                           enum nft_data_types type);
 
+
+/**
+ *     struct nft_userdata - user defined data associated with an object
+ *
+ *     @len: length of the data
+ *     @data: content
+ *
+ *     The presence of user data is indicated in an object specific fashion,
+ *     so a length of zero can't occur and the value "len" indicates data
+ *     of length len + 1.
+ */
+struct nft_userdata {
+       u8                      len;
+       unsigned char           data[0];
+};
+
 /**
  *     struct nft_set_elem - generic representation of set elements
  *
@@ -380,7 +396,7 @@ static inline void *nft_expr_priv(const struct nft_expr *expr)
  *     @handle: rule handle
  *     @genmask: generation mask
  *     @dlen: length of expression data
- *     @ulen: length of user data (used for comments)
+ *     @udata: user data is appended to the rule
  *     @data: expression data
  */
 struct nft_rule {
@@ -388,7 +404,7 @@ struct nft_rule {
        u64                             handle:42,
                                        genmask:2,
                                        dlen:12,
-                                       ulen:8;
+                                       udata:1;
        unsigned char                   data[]
                __attribute__((aligned(__alignof__(struct nft_expr))));
 };
@@ -476,7 +492,7 @@ static inline struct nft_expr *nft_expr_last(const struct nft_rule *rule)
        return (struct nft_expr *)&rule->data[rule->dlen];
 }
 
-static inline void *nft_userdata(const struct nft_rule *rule)
+static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule)
 {
        return (void *)&rule->data[rule->dlen];
 }
index eabd3a038674dd00f69263b47828134dd3a24bf1..c73e7abbbaa50e917e65a1117e881bd78665b12a 100644 (file)
@@ -91,6 +91,7 @@ struct vxlanhdr {
 
 #define VXLAN_N_VID     (1u << 24)
 #define VXLAN_VID_MASK  (VXLAN_N_VID - 1)
+#define VXLAN_VNI_MASK  (VXLAN_VID_MASK << 8)
 #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
 
 struct vxlan_metadata {
index 0210797abf2e95e88f67dd480ae24597325842d3..dc10c52e0e9199e7e878a87a714569106a955df3 100644 (file)
@@ -92,7 +92,7 @@
 #define                AT91_DDRSDRC_UPD_MR     (3 << 20)        /* Update load mode register and extended mode register */
 
 #define AT91_DDRSDRC_MDR       0x20    /* Memory Device Register */
-#define                AT91_DDRSDRC_MD         (3 << 0)                /* Memory Device Type */
+#define                AT91_DDRSDRC_MD         (7 << 0)        /* Memory Device Type */
 #define                        AT91_DDRSDRC_MD_SDR             0
 #define                        AT91_DDRSDRC_MD_LOW_POWER_SDR   1
 #define                        AT91_DDRSDRC_MD_LOW_POWER_DDR   3
index db81c65b8f4857c011a025e5b54026bf7d683f7c..d61be7297b2c88c867acbacadcacfd65045e6c50 100644 (file)
@@ -111,6 +111,7 @@ void        array_free(void *array, int n);
 void   target_core_setup_sub_cits(struct se_subsystem_api *);
 
 /* attribute helpers from target_core_device.c for backend drivers */
+bool   se_dev_check_wce(struct se_device *);
 int    se_dev_set_max_unmap_lba_count(struct se_device *, u32);
 int    se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
 int    se_dev_set_unmap_granularity(struct se_device *, u32);
index 23d561512f64fe65a5165a23d4620f7d457504a4..22317d2b52abcbe194ef8e9964bf179ae7d32846 100644 (file)
@@ -7,27 +7,26 @@
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
 
-struct device;
-struct regmap;
+#include "../../../drivers/base/regmap/internal.h"
 
 /*
  * Log register events
  */
 DECLARE_EVENT_CLASS(regmap_reg,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val),
+       TP_ARGS(map, reg, val),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   reg             )
-               __field(        unsigned int,   val             )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   reg                     )
+               __field(        unsigned int,   val                     )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->reg = reg;
                __entry->val = val;
        ),
@@ -39,45 +38,45 @@ DECLARE_EVENT_CLASS(regmap_reg,
 
 DEFINE_EVENT(regmap_reg, regmap_reg_write,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DEFINE_EVENT(regmap_reg, regmap_reg_read,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DEFINE_EVENT(regmap_reg, regmap_reg_read_cache,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DECLARE_EVENT_CLASS(regmap_block,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count),
+       TP_ARGS(map, reg, count),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   reg             )
-               __field(        int,            count           )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   reg                     )
+               __field(        int,            count                   )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->reg = reg;
                __entry->count = count;
        ),
@@ -89,48 +88,48 @@ DECLARE_EVENT_CLASS(regmap_block,
 
 DEFINE_EVENT(regmap_block, regmap_hw_read_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_read_done,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_write_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_write_done,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 TRACE_EVENT(regcache_sync,
 
-       TP_PROTO(struct device *dev, const char *type,
+       TP_PROTO(struct regmap *map, const char *type,
                 const char *status),
 
-       TP_ARGS(dev, type, status),
+       TP_ARGS(map, type, status),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __string(       status,         status          )
-               __string(       type,           type            )
-               __field(        int,            type            )
+               __string(       name,           regmap_name(map)        )
+               __string(       status,         status                  )
+               __string(       type,           type                    )
+               __field(        int,            type                    )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __assign_str(status, status);
                __assign_str(type, type);
        ),
@@ -141,17 +140,17 @@ TRACE_EVENT(regcache_sync,
 
 DECLARE_EVENT_CLASS(regmap_bool,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag),
+       TP_ARGS(map, flag),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        int,            flag            )
+               __string(       name,           regmap_name(map)        )
+               __field(        int,            flag                    )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->flag = flag;
        ),
 
@@ -161,32 +160,32 @@ DECLARE_EVENT_CLASS(regmap_bool,
 
 DEFINE_EVENT(regmap_bool, regmap_cache_only,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag)
+       TP_ARGS(map, flag)
 
 );
 
 DEFINE_EVENT(regmap_bool, regmap_cache_bypass,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag)
+       TP_ARGS(map, flag)
 
 );
 
 DECLARE_EVENT_CLASS(regmap_async,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev),
+       TP_ARGS(map),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
+               __string(       name,           regmap_name(map)        )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
        ),
 
        TP_printk("%s", __get_str(name))
@@ -194,50 +193,50 @@ DECLARE_EVENT_CLASS(regmap_async,
 
 DEFINE_EVENT(regmap_block, regmap_async_write_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_io_complete,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_complete_start,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_complete_done,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 TRACE_EVENT(regcache_drop_region,
 
-       TP_PROTO(struct device *dev, unsigned int from,
+       TP_PROTO(struct regmap *map, unsigned int from,
                 unsigned int to),
 
-       TP_ARGS(dev, from, to),
+       TP_ARGS(map, from, to),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   from            )
-               __field(        unsigned int,   to              )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   from                    )
+               __field(        unsigned int,   to                      )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->from = from;
                __entry->to = to;
        ),
index 01b2d6d0e35529d534ca5d6bd8c3efcbcbd2d838..ff6ef62d084baea9c735768904ec688e96884700 100644 (file)
@@ -630,6 +630,7 @@ struct drm_gem_open {
  */
 #define DRM_CAP_CURSOR_WIDTH           0x8
 #define DRM_CAP_CURSOR_HEIGHT          0x9
+#define DRM_CAP_ADDFB2_MODIFIERS       0x10
 
 /** DRM_IOCTL_GET_CAP ioctl argument type */
 struct drm_get_cap {
index a284f11a8ef59432929007e93ec6d4953316c873..07735822a28fa792ecf0acdd07443d2dd3160670 100644 (file)
 #define DRM_FORMAT_YUV444      fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
 #define DRM_FORMAT_YVU444      fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */
 
+
+/*
+ * Format Modifiers:
+ *
+ * Format modifiers describe, typically, a re-ordering or modification
+ * of the data in a plane of an FB.  This can be used to express tiled/
+ * swizzled formats, or compression, or a combination of the two.
+ *
+ * The upper 8 bits of the format modifier are a vendor-id as assigned
+ * below.  The lower 56 bits are assigned as vendor sees fit.
+ */
+
+/* Vendor Ids: */
+#define DRM_FORMAT_MOD_NONE           0
+#define DRM_FORMAT_MOD_VENDOR_INTEL   0x01
+#define DRM_FORMAT_MOD_VENDOR_AMD     0x02
+#define DRM_FORMAT_MOD_VENDOR_NV      0x03
+#define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04
+#define DRM_FORMAT_MOD_VENDOR_QCOM    0x05
+/* add more to the end as needed */
+
+#define fourcc_mod_code(vendor, val) \
+       ((((u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffULL))
+
+/*
+ * Format Modifier tokens:
+ *
+ * When adding a new token please document the layout with a code comment,
+ * similar to the fourcc codes above. drm_fourcc.h is considered the
+ * authoritative source for all of these.
+ */
+
+/* Intel framebuffer modifiers */
+
+/*
+ * Intel X-tiling layout
+ *
+ * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb)
+ * in row-major layout. Within the tile bytes are laid out row-major, with
+ * a platform-dependent stride. On top of that the memory can apply
+ * platform-depending swizzling of some higher address bits into bit6.
+ *
+ * This format is highly platforms specific and not useful for cross-driver
+ * sharing. It exists since on a given platform it does uniquely identify the
+ * layout in a simple way for i915-specific userspace.
+ */
+#define I915_FORMAT_MOD_X_TILED        fourcc_mod_code(INTEL, 1)
+
+/*
+ * Intel Y-tiling layout
+ *
+ * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb)
+ * in row-major layout. Within the tile bytes are laid out in OWORD (16 bytes)
+ * chunks column-major, with a platform-dependent height. On top of that the
+ * memory can apply platform-depending swizzling of some higher address bits
+ * into bit6.
+ *
+ * This format is highly platforms specific and not useful for cross-driver
+ * sharing. It exists since on a given platform it does uniquely identify the
+ * layout in a simple way for i915-specific userspace.
+ */
+#define I915_FORMAT_MOD_Y_TILED        fourcc_mod_code(INTEL, 2)
+
+/*
+ * Intel Yf-tiling layout
+ *
+ * This is a tiled layout using 4Kb tiles in row-major layout.
+ * Within the tile pixels are laid out in 16 256 byte units / sub-tiles which
+ * are arranged in four groups (two wide, two high) with column-major layout.
+ * Each group therefore consits out of four 256 byte units, which are also laid
+ * out as 2x2 column-major.
+ * 256 byte units are made out of four 64 byte blocks of pixels, producing
+ * either a square block or a 2:1 unit.
+ * 64 byte blocks of pixels contain four pixel rows of 16 bytes, where the width
+ * in pixel depends on the pixel depth.
+ */
+#define I915_FORMAT_MOD_Yf_TILED fourcc_mod_code(INTEL, 3)
+
 #endif /* DRM_FOURCC_H */
index ca788e01dab20795ea848b0ab9c70ef3d9487743..dbeba949462a60613e3f75b49b74d13c73471134 100644 (file)
@@ -336,6 +336,7 @@ struct drm_mode_fb_cmd {
 };
 
 #define DRM_MODE_FB_INTERLACED (1<<0) /* for interlaced framebuffers */
+#define DRM_MODE_FB_MODIFIERS  (1<<1) /* enables ->modifer[] */
 
 struct drm_mode_fb_cmd2 {
        __u32 fb_id;
@@ -356,10 +357,18 @@ struct drm_mode_fb_cmd2 {
         * So it would consist of Y as offsets[0] and UV as
         * offsets[1].  Note that offsets[0] will generally
         * be 0 (but this is not required).
+        *
+        * To accommodate tiled, compressed, etc formats, a per-plane
+        * modifier can be specified.  The default value of zero
+        * indicates "native" format as specified by the fourcc.
+        * Vendor specific modifier token.  This allows, for example,
+        * different tiling/swizzling pattern on different planes.
+        * See discussion above of DRM_FORMAT_MOD_xxx.
         */
        __u32 handles[4];
        __u32 pitches[4]; /* pitch for each plane */
        __u32 offsets[4]; /* offset of each plane */
+       __u64 modifier[4]; /* ie, tiling, compressed (per plane) */
 };
 
 #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01
index 6eed16b92a24192a92c4fc920dbfafa0bca3872a..551b6737f5df6909bfa4e7632055c9762b159ed2 100644 (file)
@@ -270,7 +270,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE       DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image)
 #define DRM_IOCTL_I915_OVERLAY_ATTRS   DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
 #define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
-#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
+#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
 #define DRM_IOCTL_I915_GEM_WAIT                DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait)
 #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE      DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create)
 #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY     DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy)
@@ -347,6 +347,9 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_HAS_COHERENT_PHYS_GTT 29
 #define I915_PARAM_MMAP_VERSION          30
 #define I915_PARAM_HAS_BSD2             31
+#define I915_PARAM_REVISION              32
+#define I915_PARAM_SUBSLICE_TOTAL       33
+#define I915_PARAM_EU_TOTAL             34
 
 typedef struct drm_i915_getparam {
        int param;
index 50d0fb41a3bf32cb2a796f3738adb10d79e3fb6c..871e73f99a4d7aa13b4cd6f5bc8969421c2a9301 100644 (file)
@@ -1034,6 +1034,10 @@ struct drm_radeon_cs {
 #define RADEON_INFO_VRAM_USAGE         0x1e
 #define RADEON_INFO_GTT_USAGE          0x1f
 #define RADEON_INFO_ACTIVE_CU_COUNT    0x20
+#define RADEON_INFO_CURRENT_GPU_TEMP   0x21
+#define RADEON_INFO_CURRENT_GPU_SCLK   0x22
+#define RADEON_INFO_CURRENT_GPU_MCLK   0x23
+#define RADEON_INFO_READ_REG           0x24
 
 struct drm_radeon_info {
        uint32_t                request;
index c15d781ecc0f306ce5fd575192f547b8e756273f..5391780c2b054ba63ec6a2a24effe66bec248af0 100644 (file)
@@ -36,7 +36,8 @@ struct drm_tegra_gem_create {
 
 struct drm_tegra_gem_mmap {
        __u32 handle;
-       __u32 offset;
+       __u32 pad;
+       __u64 offset;
 };
 
 struct drm_tegra_syncpt_read {
index 5e0d0ed61cf3b76d2ee7cae605834d8139cf73ee..25331f9faa7682a88222d6db22a4213472219d06 100644 (file)
@@ -65,6 +65,10 @@ struct serial_struct {
 #define SERIAL_IO_PORT 0
 #define SERIAL_IO_HUB6 1
 #define SERIAL_IO_MEM  2
+#define SERIAL_IO_MEM32          3
+#define SERIAL_IO_AU     4
+#define SERIAL_IO_TSI    5
+#define SERIAL_IO_MEM32BE 6
 
 #define UART_CLEAR_FIFO                0x01
 #define UART_USE_FIFO          0x02
index 19d5219b0b991eda86a5bb8a0274d35a5a88ce17..242cf0c6e33d37f229a224839ca6f679bb142674 100644 (file)
@@ -9,3 +9,4 @@ header-y += tc_pedit.h
 header-y += tc_skbedit.h
 header-y += tc_vlan.h
 header-y += tc_bpf.h
+header-y += tc_connmark.h
index 3c53eec4ae22697ecb87522bf83de79f4e7e2b0e..19c66fcbab8afb1ee5239140fab657b4fe52ed67 100644 (file)
@@ -60,7 +60,7 @@ struct virtio_blk_config {
        __u32 size_max;
        /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
        __u32 seg_max;
-       /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */
+       /* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
        struct virtio_blk_geometry {
                __u16 cylinders;
                __u8 heads;
@@ -119,7 +119,11 @@ struct virtio_blk_config {
 #define VIRTIO_BLK_T_BARRIER   0x80000000
 #endif /* !VIRTIO_BLK_NO_LEGACY */
 
-/* This is the first element of the read scatter-gather list. */
+/*
+ * This comes first in the read scatter-gather list.
+ * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
+ * this is the first element of the read scatter-gather list.
+ */
 struct virtio_blk_outhdr {
        /* VIRTIO_BLK_T* */
        __virtio32 type;
index 42b9370771b014d4b959cd4c0c67a7bcc7eee41d..cc18ef8825c0eddb493a1d1b8bc618f5d3ce74e8 100644 (file)
 
 #include <linux/virtio_types.h>
 
-#define VIRTIO_SCSI_CDB_SIZE   32
-#define VIRTIO_SCSI_SENSE_SIZE 96
+/* Default values of the CDB and sense data size configuration fields */
+#define VIRTIO_SCSI_CDB_DEFAULT_SIZE   32
+#define VIRTIO_SCSI_SENSE_DEFAULT_SIZE 96
+
+#ifndef VIRTIO_SCSI_CDB_SIZE
+#define VIRTIO_SCSI_CDB_SIZE VIRTIO_SCSI_CDB_DEFAULT_SIZE
+#endif
+#ifndef VIRTIO_SCSI_SENSE_SIZE
+#define VIRTIO_SCSI_SENSE_SIZE VIRTIO_SCSI_SENSE_DEFAULT_SIZE
+#endif
 
 /* SCSI command request, followed by data-out */
 struct virtio_scsi_cmd_req {
index 60de61fea8e364069969faa9bc08a7f9e19c4433..c8ed15daad02d37c5a8eec0b3787dfabf8ad9d3f 100644 (file)
@@ -689,6 +689,7 @@ struct omapdss_dsi_ops {
 };
 
 struct omap_dss_device {
+       struct kobject kobj;
        struct device *dev;
 
        struct module *owner;
index 7491ee5d81647d704a7d34ce17e107c7c374b64d..83338210ee045277b785e2af35b11b30b24c1e74 100644 (file)
@@ -46,4 +46,30 @@ static inline efi_system_table_t __init *xen_efi_probe(void)
 }
 #endif
 
+#ifdef CONFIG_PREEMPT
+
+static inline void xen_preemptible_hcall_begin(void)
+{
+}
+
+static inline void xen_preemptible_hcall_end(void)
+{
+}
+
+#else
+
+DECLARE_PER_CPU(bool, xen_in_preemptible_hcall);
+
+static inline void xen_preemptible_hcall_begin(void)
+{
+       __this_cpu_write(xen_in_preemptible_hcall, true);
+}
+
+static inline void xen_preemptible_hcall_end(void)
+{
+       __this_cpu_write(xen_in_preemptible_hcall, false);
+}
+
+#endif /* CONFIG_PREEMPT */
+
 #endif /* INCLUDE_XEN_OPS_H */
index b78f21caf55aa074d3f883d0a0269f1c7d268339..b0f1c9e5d6878117c43a1b3e402e5f97ceb15657 100644 (file)
@@ -114,9 +114,9 @@ int __must_check __xenbus_register_backend(struct xenbus_driver *drv,
                                           const char *mod_name);
 
 #define xenbus_register_frontend(drv) \
-       __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME);
+       __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME)
 #define xenbus_register_backend(drv) \
-       __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME);
+       __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME)
 
 void xenbus_unregister_driver(struct xenbus_driver *drv);
 
index 1d1fe9361d29882369f76e426b56ddd002582d2c..fc7f4748d34a9fe017bd9a42353db7a4095240d2 100644 (file)
@@ -548,9 +548,6 @@ static void update_domain_attr_tree(struct sched_domain_attr *dattr,
 
        rcu_read_lock();
        cpuset_for_each_descendant_pre(cp, pos_css, root_cs) {
-               if (cp == root_cs)
-                       continue;
-
                /* skip the whole subtree if @cp doesn't have any CPU */
                if (cpumask_empty(cp->cpus_allowed)) {
                        pos_css = css_rightmost_descendant(pos_css);
@@ -873,7 +870,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct cpumask *new_cpus)
                 * If it becomes empty, inherit the effective mask of the
                 * parent, which is guaranteed to have some CPUs.
                 */
-               if (cpumask_empty(new_cpus))
+               if (cgroup_on_dfl(cp->css.cgroup) && cpumask_empty(new_cpus))
                        cpumask_copy(new_cpus, parent->effective_cpus);
 
                /* Skip the whole subtree if the cpumask remains the same. */
@@ -1129,7 +1126,7 @@ static void update_nodemasks_hier(struct cpuset *cs, nodemask_t *new_mems)
                 * If it becomes empty, inherit the effective mask of the
                 * parent, which is guaranteed to have some MEMs.
                 */
-               if (nodes_empty(*new_mems))
+               if (cgroup_on_dfl(cp->css.cgroup) && nodes_empty(*new_mems))
                        *new_mems = parent->effective_mems;
 
                /* Skip the whole subtree if the nodemask remains the same. */
@@ -1979,7 +1976,9 @@ static int cpuset_css_online(struct cgroup_subsys_state *css)
 
        spin_lock_irq(&callback_lock);
        cs->mems_allowed = parent->mems_allowed;
+       cs->effective_mems = parent->mems_allowed;
        cpumask_copy(cs->cpus_allowed, parent->cpus_allowed);
+       cpumask_copy(cs->effective_cpus, parent->cpus_allowed);
        spin_unlock_irq(&callback_lock);
 out_unlock:
        mutex_unlock(&cpuset_mutex);
index f04daabfd1cffb78856e03b634b9d7c914faf4d1..2fabc062716591e960dbab2c9cfc16a755895773 100644 (file)
@@ -3591,7 +3591,7 @@ static void put_event(struct perf_event *event)
        ctx = perf_event_ctx_lock_nested(event, SINGLE_DEPTH_NESTING);
        WARN_ON_ONCE(ctx->parent_ctx);
        perf_remove_from_context(event, true);
-       mutex_unlock(&ctx->mutex);
+       perf_event_ctx_unlock(event, ctx);
 
        _free_event(event);
 }
@@ -4574,6 +4574,13 @@ static void perf_pending_event(struct irq_work *entry)
 {
        struct perf_event *event = container_of(entry,
                        struct perf_event, pending);
+       int rctx;
+
+       rctx = perf_swevent_get_recursion_context();
+       /*
+        * If we 'fail' here, that's OK, it means recursion is already disabled
+        * and we won't recurse 'further'.
+        */
 
        if (event->pending_disable) {
                event->pending_disable = 0;
@@ -4584,6 +4591,9 @@ static void perf_pending_event(struct irq_work *entry)
                event->pending_wakeup = 0;
                perf_event_wakeup(event);
        }
+
+       if (rctx >= 0)
+               perf_swevent_put_recursion_context(rctx);
 }
 
 /*
index 196a06fbc122fed81333c3bfd7205cfcef9aa73f..886d09e691d5a8d180826f2d5581c6bfb252d63c 100644 (file)
@@ -1474,8 +1474,13 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
         * otherwise we'll have trouble later trying to figure out
         * which interrupt is which (messes up the interrupt freeing
         * logic etc).
+        *
+        * Also IRQF_COND_SUSPEND only makes sense for shared interrupts and
+        * it cannot be set along with IRQF_NO_SUSPEND.
         */
-       if ((irqflags & IRQF_SHARED) && !dev_id)
+       if (((irqflags & IRQF_SHARED) && !dev_id) ||
+           (!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) ||
+           ((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND)))
                return -EINVAL;
 
        desc = irq_to_desc(irq);
index 3ca5325927045572edfa7d3eebd79f01b2a4c29a..5204a6d1b9854feecfc2fff678e1d2b8eef33c42 100644 (file)
@@ -43,9 +43,12 @@ void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action)
 
        if (action->flags & IRQF_NO_SUSPEND)
                desc->no_suspend_depth++;
+       else if (action->flags & IRQF_COND_SUSPEND)
+               desc->cond_suspend_depth++;
 
        WARN_ON_ONCE(desc->no_suspend_depth &&
-                    desc->no_suspend_depth != desc->nr_actions);
+                    (desc->no_suspend_depth +
+                       desc->cond_suspend_depth) != desc->nr_actions);
 }
 
 /*
@@ -61,6 +64,8 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action)
 
        if (action->flags & IRQF_NO_SUSPEND)
                desc->no_suspend_depth--;
+       else if (action->flags & IRQF_COND_SUSPEND)
+               desc->cond_suspend_depth--;
 }
 
 static bool suspend_device_irq(struct irq_desc *desc, int irq)
index ff7f47d026ac48b21d6239f9db36ee8662585a45..3f9f1d6b4c2e5726217556a40454c46dbe368b89 100644 (file)
@@ -89,16 +89,28 @@ static bool klp_is_object_loaded(struct klp_object *obj)
 /* sets obj->mod if object is not vmlinux and module is found */
 static void klp_find_object_module(struct klp_object *obj)
 {
+       struct module *mod;
+
        if (!klp_is_module(obj))
                return;
 
        mutex_lock(&module_mutex);
        /*
-        * We don't need to take a reference on the module here because we have
-        * the klp_mutex, which is also taken by the module notifier.  This
-        * prevents any module from unloading until we release the klp_mutex.
+        * We do not want to block removal of patched modules and therefore
+        * we do not take a reference here. The patches are removed by
+        * a going module handler instead.
+        */
+       mod = find_module(obj->name);
+       /*
+        * Do not mess work of the module coming and going notifiers.
+        * Note that the patch might still be needed before the going handler
+        * is called. Module functions can be called even in the GOING state
+        * until mod->exit() finishes. This is especially important for
+        * patches that modify semantic of the functions.
         */
-       obj->mod = find_module(obj->name);
+       if (mod && mod->klp_alive)
+               obj->mod = mod;
+
        mutex_unlock(&module_mutex);
 }
 
@@ -248,11 +260,12 @@ static int klp_find_external_symbol(struct module *pmod, const char *name,
        /* first, check if it's an exported symbol */
        preempt_disable();
        sym = find_symbol(name, NULL, NULL, true, true);
-       preempt_enable();
        if (sym) {
                *addr = sym->value;
+               preempt_enable();
                return 0;
        }
+       preempt_enable();
 
        /* otherwise check if it's in another .o within the patch module */
        return klp_find_object_symbol(pmod->name, name, addr);
@@ -314,12 +327,12 @@ static void notrace klp_ftrace_handler(unsigned long ip,
        rcu_read_lock();
        func = list_first_or_null_rcu(&ops->func_stack, struct klp_func,
                                      stack_node);
-       rcu_read_unlock();
-
        if (WARN_ON_ONCE(!func))
-               return;
+               goto unlock;
 
        klp_arch_set_pc(regs, (unsigned long)func->new_func);
+unlock:
+       rcu_read_unlock();
 }
 
 static int klp_disable_func(struct klp_func *func)
@@ -731,7 +744,7 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)
        func->state = KLP_DISABLED;
 
        return kobject_init_and_add(&func->kobj, &klp_ktype_func,
-                                   obj->kobj, func->old_name);
+                                   obj->kobj, "%s", func->old_name);
 }
 
 /* parts of the initialization that is done only when the object is loaded */
@@ -766,6 +779,7 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj)
                return -EINVAL;
 
        obj->state = KLP_DISABLED;
+       obj->mod = NULL;
 
        klp_find_object_module(obj);
 
@@ -807,7 +821,7 @@ static int klp_init_patch(struct klp_patch *patch)
        patch->state = KLP_DISABLED;
 
        ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch,
-                                  klp_root_kobj, patch->mod->name);
+                                  klp_root_kobj, "%s", patch->mod->name);
        if (ret)
                goto unlock;
 
@@ -960,6 +974,15 @@ static int klp_module_notify(struct notifier_block *nb, unsigned long action,
 
        mutex_lock(&klp_mutex);
 
+       /*
+        * Each module has to know that the notifier has been called.
+        * We never know what module will get patched by a new patch.
+        */
+       if (action == MODULE_STATE_COMING)
+               mod->klp_alive = true;
+       else /* MODULE_STATE_GOING */
+               mod->klp_alive = false;
+
        list_for_each_entry(patch, &klp_patches, list) {
                for (obj = patch->objs; obj->funcs; obj++) {
                        if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
index 88d0d4420ad2e3e47e71129d361b153c96a49e18..ba77ab5f64dd9809f5e24f1b079ac5abbefeb495 100644 (file)
@@ -633,7 +633,7 @@ static int count_matching_names(struct lock_class *new_class)
        if (!new_class->name)
                return 0;
 
-       list_for_each_entry(class, &all_lock_classes, lock_entry) {
+       list_for_each_entry_rcu(class, &all_lock_classes, lock_entry) {
                if (new_class->key - new_class->subclass == class->key)
                        return class->name_version;
                if (class->name && !strcmp(class->name, new_class->name))
@@ -700,10 +700,12 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
        hash_head = classhashentry(key);
 
        /*
-        * We can walk the hash lockfree, because the hash only
-        * grows, and we are careful when adding entries to the end:
+        * We do an RCU walk of the hash, see lockdep_free_key_range().
         */
-       list_for_each_entry(class, hash_head, hash_entry) {
+       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+               return NULL;
+
+       list_for_each_entry_rcu(class, hash_head, hash_entry) {
                if (class->key == key) {
                        /*
                         * Huh! same key, different name? Did someone trample
@@ -728,7 +730,8 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
        struct lockdep_subclass_key *key;
        struct list_head *hash_head;
        struct lock_class *class;
-       unsigned long flags;
+
+       DEBUG_LOCKS_WARN_ON(!irqs_disabled());
 
        class = look_up_lock_class(lock, subclass);
        if (likely(class))
@@ -750,28 +753,26 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
        key = lock->key->subkeys + subclass;
        hash_head = classhashentry(key);
 
-       raw_local_irq_save(flags);
        if (!graph_lock()) {
-               raw_local_irq_restore(flags);
                return NULL;
        }
        /*
         * We have to do the hash-walk again, to avoid races
         * with another CPU:
         */
-       list_for_each_entry(class, hash_head, hash_entry)
+       list_for_each_entry_rcu(class, hash_head, hash_entry) {
                if (class->key == key)
                        goto out_unlock_set;
+       }
+
        /*
         * Allocate a new key from the static array, and add it to
         * the hash:
         */
        if (nr_lock_classes >= MAX_LOCKDEP_KEYS) {
                if (!debug_locks_off_graph_unlock()) {
-                       raw_local_irq_restore(flags);
                        return NULL;
                }
-               raw_local_irq_restore(flags);
 
                print_lockdep_off("BUG: MAX_LOCKDEP_KEYS too low!");
                dump_stack();
@@ -798,7 +799,6 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
 
        if (verbose(class)) {
                graph_unlock();
-               raw_local_irq_restore(flags);
 
                printk("\nnew class %p: %s", class->key, class->name);
                if (class->name_version > 1)
@@ -806,15 +806,12 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
                printk("\n");
                dump_stack();
 
-               raw_local_irq_save(flags);
                if (!graph_lock()) {
-                       raw_local_irq_restore(flags);
                        return NULL;
                }
        }
 out_unlock_set:
        graph_unlock();
-       raw_local_irq_restore(flags);
 
 out_set_class_cache:
        if (!subclass || force)
@@ -870,11 +867,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
        entry->distance = distance;
        entry->trace = *trace;
        /*
-        * Since we never remove from the dependency list, the list can
-        * be walked lockless by other CPUs, it's only allocation
-        * that must be protected by the spinlock. But this also means
-        * we must make new entries visible only once writes to the
-        * entry become visible - hence the RCU op:
+        * Both allocation and removal are done under the graph lock; but
+        * iteration is under RCU-sched; see look_up_lock_class() and
+        * lockdep_free_key_range().
         */
        list_add_tail_rcu(&entry->entry, head);
 
@@ -1025,7 +1020,9 @@ static int __bfs(struct lock_list *source_entry,
                else
                        head = &lock->class->locks_before;
 
-               list_for_each_entry(entry, head, entry) {
+               DEBUG_LOCKS_WARN_ON(!irqs_disabled());
+
+               list_for_each_entry_rcu(entry, head, entry) {
                        if (!lock_accessed(entry)) {
                                unsigned int cq_depth;
                                mark_lock_accessed(entry, lock);
@@ -2022,7 +2019,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
         * We can walk it lock-free, because entries only get added
         * to the hash:
         */
-       list_for_each_entry(chain, hash_head, entry) {
+       list_for_each_entry_rcu(chain, hash_head, entry) {
                if (chain->chain_key == chain_key) {
 cache_hit:
                        debug_atomic_inc(chain_lookup_hits);
@@ -2996,8 +2993,18 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
        if (unlikely(!debug_locks))
                return;
 
-       if (subclass)
+       if (subclass) {
+               unsigned long flags;
+
+               if (DEBUG_LOCKS_WARN_ON(current->lockdep_recursion))
+                       return;
+
+               raw_local_irq_save(flags);
+               current->lockdep_recursion = 1;
                register_lock_class(lock, subclass, 1);
+               current->lockdep_recursion = 0;
+               raw_local_irq_restore(flags);
+       }
 }
 EXPORT_SYMBOL_GPL(lockdep_init_map);
 
@@ -3887,9 +3894,17 @@ static inline int within(const void *addr, void *start, unsigned long size)
        return addr >= start && addr < start + size;
 }
 
+/*
+ * Used in module.c to remove lock classes from memory that is going to be
+ * freed; and possibly re-used by other modules.
+ *
+ * We will have had one sync_sched() before getting here, so we're guaranteed
+ * nobody will look up these exact classes -- they're properly dead but still
+ * allocated.
+ */
 void lockdep_free_key_range(void *start, unsigned long size)
 {
-       struct lock_class *class, *next;
+       struct lock_class *class;
        struct list_head *head;
        unsigned long flags;
        int i;
@@ -3905,7 +3920,7 @@ void lockdep_free_key_range(void *start, unsigned long size)
                head = classhash_table + i;
                if (list_empty(head))
                        continue;
-               list_for_each_entry_safe(class, next, head, hash_entry) {
+               list_for_each_entry_rcu(class, head, hash_entry) {
                        if (within(class->key, start, size))
                                zap_class(class);
                        else if (within(class->name, start, size))
@@ -3916,11 +3931,25 @@ void lockdep_free_key_range(void *start, unsigned long size)
        if (locked)
                graph_unlock();
        raw_local_irq_restore(flags);
+
+       /*
+        * Wait for any possible iterators from look_up_lock_class() to pass
+        * before continuing to free the memory they refer to.
+        *
+        * sync_sched() is sufficient because the read-side is IRQ disable.
+        */
+       synchronize_sched();
+
+       /*
+        * XXX at this point we could return the resources to the pool;
+        * instead we leak them. We would need to change to bitmap allocators
+        * instead of the linear allocators we have now.
+        */
 }
 
 void lockdep_reset_lock(struct lockdep_map *lock)
 {
-       struct lock_class *class, *next;
+       struct lock_class *class;
        struct list_head *head;
        unsigned long flags;
        int i, j;
@@ -3948,7 +3977,7 @@ void lockdep_reset_lock(struct lockdep_map *lock)
                head = classhash_table + i;
                if (list_empty(head))
                        continue;
-               list_for_each_entry_safe(class, next, head, hash_entry) {
+               list_for_each_entry_rcu(class, head, hash_entry) {
                        int match = 0;
 
                        for (j = 0; j < NR_LOCKDEP_CACHING_CLASSES; j++)
index e16e5542bf13f381a36c304b7e6b1ff9b66aaea0..6357265a31ad1a34b881aba31abe27ab6d3921ec 100644 (file)
@@ -1193,6 +1193,7 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
                ret = __rt_mutex_slowlock(lock, state, timeout, &waiter);
 
        if (unlikely(ret)) {
+               __set_current_state(TASK_RUNNING);
                if (rt_mutex_has_waiters(lock))
                        remove_waiter(lock, &waiter);
                rt_mutex_handle_deadlock(ret, chwalk, &waiter);
index b34813f725e970fa79b97e625fab6c568543aaf8..99fdf94efce80f432fc4ab203aeb2a918ad5c564 100644 (file)
@@ -56,7 +56,6 @@
 #include <linux/async.h>
 #include <linux/percpu.h>
 #include <linux/kmemleak.h>
-#include <linux/kasan.h>
 #include <linux/jump_label.h>
 #include <linux/pfn.h>
 #include <linux/bsearch.h>
@@ -1814,7 +1813,6 @@ static void unset_module_init_ro_nx(struct module *mod) { }
 void __weak module_memfree(void *module_region)
 {
        vfree(module_region);
-       kasan_module_free(module_region);
 }
 
 void __weak module_arch_cleanup(struct module *mod)
@@ -1867,7 +1865,7 @@ static void free_module(struct module *mod)
        kfree(mod->args);
        percpu_modfree(mod);
 
-       /* Free lock-classes: */
+       /* Free lock-classes; relies on the preceding sync_rcu(). */
        lockdep_free_key_range(mod->module_core, mod->core_size);
 
        /* Finally, free the core (containing the module structure) */
@@ -2313,11 +2311,13 @@ static void layout_symtab(struct module *mod, struct load_info *info)
        info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
        info->stroffs = mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);
        mod->core_size += strtab_size;
+       mod->core_size = debug_align(mod->core_size);
 
        /* Put string table section at end of init part of module. */
        strsect->sh_flags |= SHF_ALLOC;
        strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
                                         info->index.str) | INIT_OFFSET_MASK;
+       mod->init_size = debug_align(mod->init_size);
        pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
 }
 
@@ -3349,9 +3349,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
        module_bug_cleanup(mod);
        mutex_unlock(&module_mutex);
 
-       /* Free lock-classes: */
-       lockdep_free_key_range(mod->module_core, mod->core_size);
-
        /* we can't deallocate the module until we clear memory protection */
        unset_module_init_ro_nx(mod);
        unset_module_core_ro_nx(mod);
@@ -3375,6 +3372,9 @@ static int load_module(struct load_info *info, const char __user *uargs,
        synchronize_rcu();
        mutex_unlock(&module_mutex);
  free_module:
+       /* Free lock-classes; relies on the preceding sync_rcu() */
+       lockdep_free_key_range(mod->module_core, mod->core_size);
+
        module_deallocate(mod, info);
  free_copy:
        free_copy(info);
index cbd69d842341175e4c6db7c68a4b6e3689f5c928..2ca4a8b5fe57960c584d74e7dabf76b22bc71613 100644 (file)
@@ -3,7 +3,7 @@
 
 struct console_cmdline
 {
-       char    name[8];                        /* Name of the driver       */
+       char    name[16];                       /* Name of the driver       */
        int     index;                          /* Minor dev. to use        */
        char    *options;                       /* Options for the driver   */
 #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
index 01cfd69c54c6772ad49a1d81120258f765f435a1..bb0635bd74f26a2ecb9f651de9e0c4113e4f2476 100644 (file)
@@ -2464,6 +2464,7 @@ void register_console(struct console *newcon)
        for (i = 0, c = console_cmdline;
             i < MAX_CMDLINECONSOLES && c->name[0];
             i++, c++) {
+               BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
                if (strcmp(c->name, newcon->name) != 0)
                        continue;
                if (newcon->index >= 0 &&
index f0f831e8a345d835f4cb21bf899c50ab67042b43..62671f53202ac7d4de8037dce950c934c7a4ddbc 100644 (file)
@@ -3034,6 +3034,8 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
        } else {
                if (dl_prio(oldprio))
                        p->dl.dl_boosted = 0;
+               if (rt_prio(oldprio))
+                       p->rt.timeout = 0;
                p->sched_class = &fair_sched_class;
        }
 
index 7ce18f3c097ac4779eb4cf6ed0ad14ac1beb3eb5..bcfe32088b3768363c2f37502a953b61a361f7ff 100644 (file)
@@ -1609,9 +1609,11 @@ static void update_task_scan_period(struct task_struct *p,
        /*
         * If there were no record hinting faults then either the task is
         * completely idle or all activity is areas that are not of interest
-        * to automatic numa balancing. Scan slower
+        * to automatic numa balancing. Related to that, if there were failed
+        * migration then it implies we are migrating too quickly or the local
+        * node is overloaded. In either case, scan slower
         */
-       if (local + shared == 0) {
+       if (local + shared == 0 || p->numa_faults_locality[2]) {
                p->numa_scan_period = min(p->numa_scan_period_max,
                        p->numa_scan_period << 1);
 
@@ -2080,6 +2082,8 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
 
        if (migrated)
                p->numa_pages_migrated += pages;
+       if (flags & TNF_MIGRATE_FAIL)
+               p->numa_faults_locality[2] += pages;
 
        p->numa_faults[task_faults_idx(NUMA_MEMBUF, mem_node, priv)] += pages;
        p->numa_faults[task_faults_idx(NUMA_CPUBUF, cpu_node, priv)] += pages;
index 94b2d7b88a272856bf0f49ac0f0bdce430a5255d..80014a17834214fcad51add08b2b171463e84128 100644 (file)
@@ -82,6 +82,7 @@ static void cpuidle_idle_call(void)
        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
        int next_state, entered_state;
        unsigned int broadcast;
+       bool reflect;
 
        /*
         * Check if the idle task must be rescheduled. If it is the
@@ -105,6 +106,9 @@ static void cpuidle_idle_call(void)
         */
        rcu_idle_enter();
 
+       if (cpuidle_not_available(drv, dev))
+               goto use_default;
+
        /*
         * Suspend-to-idle ("freeze") is a system state in which all user space
         * has been frozen, all I/O devices have been suspended and the only
@@ -115,30 +119,24 @@ static void cpuidle_idle_call(void)
         * until a proper wakeup interrupt happens.
         */
        if (idle_should_freeze()) {
-               cpuidle_enter_freeze();
-               local_irq_enable();
-               goto exit_idle;
-       }
+               entered_state = cpuidle_enter_freeze(drv, dev);
+               if (entered_state >= 0) {
+                       local_irq_enable();
+                       goto exit_idle;
+               }
 
-       /*
-        * Ask the cpuidle framework to choose a convenient idle state.
-        * Fall back to the default arch idle method on errors.
-        */
-       next_state = cpuidle_select(drv, dev);
-       if (next_state < 0) {
-use_default:
+               reflect = false;
+               next_state = cpuidle_find_deepest_state(drv, dev);
+       } else {
+               reflect = true;
                /*
-                * We can't use the cpuidle framework, let's use the default
-                * idle routine.
+                * Ask the cpuidle framework to choose a convenient idle state.
                 */
-               if (current_clr_polling_and_test())
-                       local_irq_enable();
-               else
-                       arch_cpu_idle();
-
-               goto exit_idle;
+               next_state = cpuidle_select(drv, dev);
        }
-
+       /* Fall back to the default arch idle method on errors. */
+       if (next_state < 0)
+               goto use_default;
 
        /*
         * The idle task must be scheduled, it is pointless to
@@ -183,7 +181,8 @@ use_default:
        /*
         * Give the governor an opportunity to reflect on the outcome
         */
-       cpuidle_reflect(dev, entered_state);
+       if (reflect)
+               cpuidle_reflect(dev, entered_state);
 
 exit_idle:
        __current_set_polling();
@@ -196,6 +195,19 @@ exit_idle:
 
        rcu_idle_exit();
        start_critical_timings();
+       return;
+
+use_default:
+       /*
+        * We can't use the cpuidle framework, let's use the default
+        * idle routine.
+        */
+       if (current_clr_polling_and_test())
+               local_irq_enable();
+       else
+               arch_cpu_idle();
+
+       goto exit_idle;
 }
 
 /*
index 667b2e62fad25bffd03109b4468fd3cbd4af00bf..a03d9cd23ed779b2a38d8bf564bac6860d934f2f 100644 (file)
@@ -1108,6 +1108,7 @@ DECLARE_RWSEM(uts_sem);
 /*
  * Work around broken programs that cannot handle "Linux 3.0".
  * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
+ * And we map 4.x to 2.6.60+x, so 4.0 would be 2.6.60.
  */
 static int override_release(char __user *release, size_t len)
 {
@@ -1127,7 +1128,7 @@ static int override_release(char __user *release, size_t len)
                                break;
                        rest++;
                }
-               v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
+               v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 60;
                copy = clamp_t(size_t, len, 1, sizeof(buf));
                copy = scnprintf(buf, copy, "2.6.%u%s", v, rest);
                ret = copy_to_user(release, buf, copy + 1);
index eb682d5c697cd5b67c988654915d1f5333fbe342..6aac4beedbbe235951c0671336e52b2459a047fb 100644 (file)
@@ -49,6 +49,7 @@ static void bc_set_mode(enum clock_event_mode mode,
  */
 static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
 {
+       int bc_moved;
        /*
         * We try to cancel the timer first. If the callback is on
         * flight on some other cpu then we let it handle it. If we
@@ -60,9 +61,15 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
         * restart the timer because we are in the callback, but we
         * can set the expiry time and let the callback return
         * HRTIMER_RESTART.
+        *
+        * Since we are in the idle loop at this point and because
+        * hrtimer_{start/cancel} functions call into tracing,
+        * calls to these functions must be bound within RCU_NONIDLE.
         */
-       if (hrtimer_try_to_cancel(&bctimer) >= 0) {
-               hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED);
+       RCU_NONIDLE(bc_moved = (hrtimer_try_to_cancel(&bctimer) >= 0) ?
+               !hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED) :
+                       0);
+       if (bc_moved) {
                /* Bind the "device" to the cpu */
                bc->bound_on = smp_processor_id();
        } else if (bc->bound_on == smp_processor_id()) {
index 45e5cb143d173d979576689dbc8e7a66703eee06..4f228024055b119d93279705ec4c42d7475c72f7 100644 (file)
@@ -1059,6 +1059,12 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
 
 static struct pid * const ftrace_swapper_pid = &init_struct_pid;
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+static int ftrace_graph_active;
+#else
+# define ftrace_graph_active 0
+#endif
+
 #ifdef CONFIG_DYNAMIC_FTRACE
 
 static struct ftrace_ops *removed_ops;
@@ -2041,8 +2047,12 @@ static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
                if (!ftrace_rec_count(rec))
                        rec->flags = 0;
                else
-                       /* Just disable the record (keep REGS state) */
-                       rec->flags &= ~FTRACE_FL_ENABLED;
+                       /*
+                        * Just disable the record, but keep the ops TRAMP
+                        * and REGS states. The _EN flags must be disabled though.
+                        */
+                       rec->flags &= ~(FTRACE_FL_ENABLED | FTRACE_FL_TRAMP_EN |
+                                       FTRACE_FL_REGS_EN);
        }
 
        return FTRACE_UPDATE_MAKE_NOP;
@@ -2688,24 +2698,36 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
 
 static void ftrace_startup_sysctl(void)
 {
+       int command;
+
        if (unlikely(ftrace_disabled))
                return;
 
        /* Force update next time */
        saved_ftrace_func = NULL;
        /* ftrace_start_up is true if we want ftrace running */
-       if (ftrace_start_up)
-               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+       if (ftrace_start_up) {
+               command = FTRACE_UPDATE_CALLS;
+               if (ftrace_graph_active)
+                       command |= FTRACE_START_FUNC_RET;
+               ftrace_startup_enable(command);
+       }
 }
 
 static void ftrace_shutdown_sysctl(void)
 {
+       int command;
+
        if (unlikely(ftrace_disabled))
                return;
 
        /* ftrace_start_up is true if ftrace is running */
-       if (ftrace_start_up)
-               ftrace_run_update_code(FTRACE_DISABLE_CALLS);
+       if (ftrace_start_up) {
+               command = FTRACE_DISABLE_CALLS;
+               if (ftrace_graph_active)
+                       command |= FTRACE_STOP_FUNC_RET;
+               ftrace_run_update_code(command);
+       }
 }
 
 static cycle_t         ftrace_update_time;
@@ -5558,12 +5580,12 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
 
        if (ftrace_enabled) {
 
-               ftrace_startup_sysctl();
-
                /* we are starting ftrace again */
                if (ftrace_ops_list != &ftrace_list_end)
                        update_ftrace_function();
 
+               ftrace_startup_sysctl();
+
        } else {
                /* stopping ftrace calls (just send to ftrace_stub) */
                ftrace_trace_function = ftrace_stub;
@@ -5590,8 +5612,6 @@ static struct ftrace_ops graph_ops = {
        ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash)
 };
 
-static int ftrace_graph_active;
-
 int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
 {
        return 0;
index f2884939479109f349b6291a82ee4cc990aa1c32..41ff75b478c60b443cd80626351b1e3f3030f94b 100644 (file)
@@ -2728,19 +2728,57 @@ bool flush_work(struct work_struct *work)
 }
 EXPORT_SYMBOL_GPL(flush_work);
 
+struct cwt_wait {
+       wait_queue_t            wait;
+       struct work_struct      *work;
+};
+
+static int cwt_wakefn(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+       struct cwt_wait *cwait = container_of(wait, struct cwt_wait, wait);
+
+       if (cwait->work != key)
+               return 0;
+       return autoremove_wake_function(wait, mode, sync, key);
+}
+
 static bool __cancel_work_timer(struct work_struct *work, bool is_dwork)
 {
+       static DECLARE_WAIT_QUEUE_HEAD(cancel_waitq);
        unsigned long flags;
        int ret;
 
        do {
                ret = try_to_grab_pending(work, is_dwork, &flags);
                /*
-                * If someone else is canceling, wait for the same event it
-                * would be waiting for before retrying.
+                * If someone else is already canceling, wait for it to
+                * finish.  flush_work() doesn't work for PREEMPT_NONE
+                * because we may get scheduled between @work's completion
+                * and the other canceling task resuming and clearing
+                * CANCELING - flush_work() will return false immediately
+                * as @work is no longer busy, try_to_grab_pending() will
+                * return -ENOENT as @work is still being canceled and the
+                * other canceling task won't be able to clear CANCELING as
+                * we're hogging the CPU.
+                *
+                * Let's wait for completion using a waitqueue.  As this
+                * may lead to the thundering herd problem, use a custom
+                * wake function which matches @work along with exclusive
+                * wait and wakeup.
                 */
-               if (unlikely(ret == -ENOENT))
-                       flush_work(work);
+               if (unlikely(ret == -ENOENT)) {
+                       struct cwt_wait cwait;
+
+                       init_wait(&cwait.wait);
+                       cwait.wait.func = cwt_wakefn;
+                       cwait.work = work;
+
+                       prepare_to_wait_exclusive(&cancel_waitq, &cwait.wait,
+                                                 TASK_UNINTERRUPTIBLE);
+                       if (work_is_canceling(work))
+                               schedule();
+                       finish_wait(&cancel_waitq, &cwait.wait);
+               }
        } while (unlikely(ret < 0));
 
        /* tell other tasks trying to grab @work to back off */
@@ -2749,6 +2787,16 @@ static bool __cancel_work_timer(struct work_struct *work, bool is_dwork)
 
        flush_work(work);
        clear_work_data(work);
+
+       /*
+        * Paired with prepare_to_wait() above so that either
+        * waitqueue_active() is visible here or !work_is_canceling() is
+        * visible there.
+        */
+       smp_mb();
+       if (waitqueue_active(&cancel_waitq))
+               __wake_up(&cancel_waitq, TASK_NORMAL, 1, work);
+
        return ret;
 }
 
index 87eb3bffc283aa8c0e65c5678729dbad484bd5bf..58f74d2dd3967a3bf0a6d9f5dc9996bfeb9bc842 100644 (file)
@@ -24,7 +24,7 @@ obj-y += lockref.o
 
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \
-        gcd.o lcm.o list_sort.o uuid.o flex_array.o clz_ctz.o \
+        gcd.o lcm.o list_sort.o uuid.o flex_array.o iov_iter.o clz_ctz.o \
         bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \
         percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o
 obj-y += string_helpers.o
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
new file mode 100644 (file)
index 0000000..9d96e28
--- /dev/null
@@ -0,0 +1,768 @@
+#include <linux/export.h>
+#include <linux/uio.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <net/checksum.h>
+
+#define iterate_iovec(i, n, __v, __p, skip, STEP) {    \
+       size_t left;                                    \
+       size_t wanted = n;                              \
+       __p = i->iov;                                   \
+       __v.iov_len = min(n, __p->iov_len - skip);      \
+       if (likely(__v.iov_len)) {                      \
+               __v.iov_base = __p->iov_base + skip;    \
+               left = (STEP);                          \
+               __v.iov_len -= left;                    \
+               skip += __v.iov_len;                    \
+               n -= __v.iov_len;                       \
+       } else {                                        \
+               left = 0;                               \
+       }                                               \
+       while (unlikely(!left && n)) {                  \
+               __p++;                                  \
+               __v.iov_len = min(n, __p->iov_len);     \
+               if (unlikely(!__v.iov_len))             \
+                       continue;                       \
+               __v.iov_base = __p->iov_base;           \
+               left = (STEP);                          \
+               __v.iov_len -= left;                    \
+               skip = __v.iov_len;                     \
+               n -= __v.iov_len;                       \
+       }                                               \
+       n = wanted - n;                                 \
+}
+
+#define iterate_kvec(i, n, __v, __p, skip, STEP) {     \
+       size_t wanted = n;                              \
+       __p = i->kvec;                                  \
+       __v.iov_len = min(n, __p->iov_len - skip);      \
+       if (likely(__v.iov_len)) {                      \
+               __v.iov_base = __p->iov_base + skip;    \
+               (void)(STEP);                           \
+               skip += __v.iov_len;                    \
+               n -= __v.iov_len;                       \
+       }                                               \
+       while (unlikely(n)) {                           \
+               __p++;                                  \
+               __v.iov_len = min(n, __p->iov_len);     \
+               if (unlikely(!__v.iov_len))             \
+                       continue;                       \
+               __v.iov_base = __p->iov_base;           \
+               (void)(STEP);                           \
+               skip = __v.iov_len;                     \
+               n -= __v.iov_len;                       \
+       }                                               \
+       n = wanted;                                     \
+}
+
+#define iterate_bvec(i, n, __v, __p, skip, STEP) {     \
+       size_t wanted = n;                              \
+       __p = i->bvec;                                  \
+       __v.bv_len = min_t(size_t, n, __p->bv_len - skip);      \
+       if (likely(__v.bv_len)) {                       \
+               __v.bv_page = __p->bv_page;             \
+               __v.bv_offset = __p->bv_offset + skip;  \
+               (void)(STEP);                           \
+               skip += __v.bv_len;                     \
+               n -= __v.bv_len;                        \
+       }                                               \
+       while (unlikely(n)) {                           \
+               __p++;                                  \
+               __v.bv_len = min_t(size_t, n, __p->bv_len);     \
+               if (unlikely(!__v.bv_len))              \
+                       continue;                       \
+               __v.bv_page = __p->bv_page;             \
+               __v.bv_offset = __p->bv_offset;         \
+               (void)(STEP);                           \
+               skip = __v.bv_len;                      \
+               n -= __v.bv_len;                        \
+       }                                               \
+       n = wanted;                                     \
+}
+
+#define iterate_all_kinds(i, n, v, I, B, K) {                  \
+       size_t skip = i->iov_offset;                            \
+       if (unlikely(i->type & ITER_BVEC)) {                    \
+               const struct bio_vec *bvec;                     \
+               struct bio_vec v;                               \
+               iterate_bvec(i, n, v, bvec, skip, (B))          \
+       } else if (unlikely(i->type & ITER_KVEC)) {             \
+               const struct kvec *kvec;                        \
+               struct kvec v;                                  \
+               iterate_kvec(i, n, v, kvec, skip, (K))          \
+       } else {                                                \
+               const struct iovec *iov;                        \
+               struct iovec v;                                 \
+               iterate_iovec(i, n, v, iov, skip, (I))          \
+       }                                                       \
+}
+
+#define iterate_and_advance(i, n, v, I, B, K) {                        \
+       size_t skip = i->iov_offset;                            \
+       if (unlikely(i->type & ITER_BVEC)) {                    \
+               const struct bio_vec *bvec;                     \
+               struct bio_vec v;                               \
+               iterate_bvec(i, n, v, bvec, skip, (B))          \
+               if (skip == bvec->bv_len) {                     \
+                       bvec++;                                 \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= bvec - i->bvec;                   \
+               i->bvec = bvec;                                 \
+       } else if (unlikely(i->type & ITER_KVEC)) {             \
+               const struct kvec *kvec;                        \
+               struct kvec v;                                  \
+               iterate_kvec(i, n, v, kvec, skip, (K))          \
+               if (skip == kvec->iov_len) {                    \
+                       kvec++;                                 \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= kvec - i->kvec;                   \
+               i->kvec = kvec;                                 \
+       } else {                                                \
+               const struct iovec *iov;                        \
+               struct iovec v;                                 \
+               iterate_iovec(i, n, v, iov, skip, (I))          \
+               if (skip == iov->iov_len) {                     \
+                       iov++;                                  \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= iov - i->iov;                     \
+               i->iov = iov;                                   \
+       }                                                       \
+       i->count -= n;                                          \
+       i->iov_offset = skip;                                   \
+}
+
+static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       size_t skip, copy, left, wanted;
+       const struct iovec *iov;
+       char __user *buf;
+       void *kaddr, *from;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       iov = i->iov;
+       skip = i->iov_offset;
+       buf = iov->iov_base + skip;
+       copy = min(bytes, iov->iov_len - skip);
+
+       if (!fault_in_pages_writeable(buf, copy)) {
+               kaddr = kmap_atomic(page);
+               from = kaddr + offset;
+
+               /* first chunk, usually the only one */
+               left = __copy_to_user_inatomic(buf, from, copy);
+               copy -= left;
+               skip += copy;
+               from += copy;
+               bytes -= copy;
+
+               while (unlikely(!left && bytes)) {
+                       iov++;
+                       buf = iov->iov_base;
+                       copy = min(bytes, iov->iov_len);
+                       left = __copy_to_user_inatomic(buf, from, copy);
+                       copy -= left;
+                       skip = copy;
+                       from += copy;
+                       bytes -= copy;
+               }
+               if (likely(!bytes)) {
+                       kunmap_atomic(kaddr);
+                       goto done;
+               }
+               offset = from - kaddr;
+               buf += copy;
+               kunmap_atomic(kaddr);
+               copy = min(bytes, iov->iov_len - skip);
+       }
+       /* Too bad - revert to non-atomic kmap */
+       kaddr = kmap(page);
+       from = kaddr + offset;
+       left = __copy_to_user(buf, from, copy);
+       copy -= left;
+       skip += copy;
+       from += copy;
+       bytes -= copy;
+       while (unlikely(!left && bytes)) {
+               iov++;
+               buf = iov->iov_base;
+               copy = min(bytes, iov->iov_len);
+               left = __copy_to_user(buf, from, copy);
+               copy -= left;
+               skip = copy;
+               from += copy;
+               bytes -= copy;
+       }
+       kunmap(page);
+done:
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= iov - i->iov;
+       i->iov = iov;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
+static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       size_t skip, copy, left, wanted;
+       const struct iovec *iov;
+       char __user *buf;
+       void *kaddr, *to;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       iov = i->iov;
+       skip = i->iov_offset;
+       buf = iov->iov_base + skip;
+       copy = min(bytes, iov->iov_len - skip);
+
+       if (!fault_in_pages_readable(buf, copy)) {
+               kaddr = kmap_atomic(page);
+               to = kaddr + offset;
+
+               /* first chunk, usually the only one */
+               left = __copy_from_user_inatomic(to, buf, copy);
+               copy -= left;
+               skip += copy;
+               to += copy;
+               bytes -= copy;
+
+               while (unlikely(!left && bytes)) {
+                       iov++;
+                       buf = iov->iov_base;
+                       copy = min(bytes, iov->iov_len);
+                       left = __copy_from_user_inatomic(to, buf, copy);
+                       copy -= left;
+                       skip = copy;
+                       to += copy;
+                       bytes -= copy;
+               }
+               if (likely(!bytes)) {
+                       kunmap_atomic(kaddr);
+                       goto done;
+               }
+               offset = to - kaddr;
+               buf += copy;
+               kunmap_atomic(kaddr);
+               copy = min(bytes, iov->iov_len - skip);
+       }
+       /* Too bad - revert to non-atomic kmap */
+       kaddr = kmap(page);
+       to = kaddr + offset;
+       left = __copy_from_user(to, buf, copy);
+       copy -= left;
+       skip += copy;
+       to += copy;
+       bytes -= copy;
+       while (unlikely(!left && bytes)) {
+               iov++;
+               buf = iov->iov_base;
+               copy = min(bytes, iov->iov_len);
+               left = __copy_from_user(to, buf, copy);
+               copy -= left;
+               skip = copy;
+               to += copy;
+               bytes -= copy;
+       }
+       kunmap(page);
+done:
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= iov - i->iov;
+       i->iov = iov;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
+/*
+ * Fault in the first iovec of the given iov_iter, to a maximum length
+ * of bytes. Returns 0 on success, or non-zero if the memory could not be
+ * accessed (ie. because it is an invalid address).
+ *
+ * writev-intensive code may want this to prefault several iovecs -- that
+ * would be possible (callers must not rely on the fact that _only_ the
+ * first iovec will be faulted with the current implementation).
+ */
+int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
+{
+       if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
+               char __user *buf = i->iov->iov_base + i->iov_offset;
+               bytes = min(bytes, i->iov->iov_len - i->iov_offset);
+               return fault_in_pages_readable(buf, bytes);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(iov_iter_fault_in_readable);
+
+void iov_iter_init(struct iov_iter *i, int direction,
+                       const struct iovec *iov, unsigned long nr_segs,
+                       size_t count)
+{
+       /* It will get better.  Eventually... */
+       if (segment_eq(get_fs(), KERNEL_DS)) {
+               direction |= ITER_KVEC;
+               i->type = direction;
+               i->kvec = (struct kvec *)iov;
+       } else {
+               i->type = direction;
+               i->iov = iov;
+       }
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_init);
+
+static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len)
+{
+       char *from = kmap_atomic(page);
+       memcpy(to, from + offset, len);
+       kunmap_atomic(from);
+}
+
+static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t len)
+{
+       char *to = kmap_atomic(page);
+       memcpy(to + offset, from, len);
+       kunmap_atomic(to);
+}
+
+static void memzero_page(struct page *page, size_t offset, size_t len)
+{
+       char *addr = kmap_atomic(page);
+       memset(addr + offset, 0, len);
+       kunmap_atomic(addr);
+}
+
+size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *from = addr;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __copy_to_user(v.iov_base, (from += v.iov_len) - v.iov_len,
+                              v.iov_len),
+               memcpy_to_page(v.bv_page, v.bv_offset,
+                              (from += v.bv_len) - v.bv_len, v.bv_len),
+               memcpy(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(copy_to_iter);
+
+size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *to = addr;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __copy_from_user((to += v.iov_len) - v.iov_len, v.iov_base,
+                                v.iov_len),
+               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(copy_from_iter);
+
+size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *to = addr;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __copy_from_user_nocache((to += v.iov_len) - v.iov_len,
+                                        v.iov_base, v.iov_len),
+               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(copy_from_iter_nocache);
+
+size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       if (i->type & (ITER_BVEC|ITER_KVEC)) {
+               void *kaddr = kmap_atomic(page);
+               size_t wanted = copy_to_iter(kaddr + offset, bytes, i);
+               kunmap_atomic(kaddr);
+               return wanted;
+       } else
+               return copy_page_to_iter_iovec(page, offset, bytes, i);
+}
+EXPORT_SYMBOL(copy_page_to_iter);
+
+size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       if (i->type & (ITER_BVEC|ITER_KVEC)) {
+               void *kaddr = kmap_atomic(page);
+               size_t wanted = copy_from_iter(kaddr + offset, bytes, i);
+               kunmap_atomic(kaddr);
+               return wanted;
+       } else
+               return copy_page_from_iter_iovec(page, offset, bytes, i);
+}
+EXPORT_SYMBOL(copy_page_from_iter);
+
+size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
+{
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __clear_user(v.iov_base, v.iov_len),
+               memzero_page(v.bv_page, v.bv_offset, v.bv_len),
+               memset(v.iov_base, 0, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(iov_iter_zero);
+
+size_t iov_iter_copy_from_user_atomic(struct page *page,
+               struct iov_iter *i, unsigned long offset, size_t bytes)
+{
+       char *kaddr = kmap_atomic(page), *p = kaddr + offset;
+       iterate_all_kinds(i, bytes, v,
+               __copy_from_user_inatomic((p += v.iov_len) - v.iov_len,
+                                         v.iov_base, v.iov_len),
+               memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
+       kunmap_atomic(kaddr);
+       return bytes;
+}
+EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
+
+void iov_iter_advance(struct iov_iter *i, size_t size)
+{
+       iterate_and_advance(i, size, v, 0, 0, 0)
+}
+EXPORT_SYMBOL(iov_iter_advance);
+
+/*
+ * Return the count of just the current iov_iter segment.
+ */
+size_t iov_iter_single_seg_count(const struct iov_iter *i)
+{
+       if (i->nr_segs == 1)
+               return i->count;
+       else if (i->type & ITER_BVEC)
+               return min(i->count, i->bvec->bv_len - i->iov_offset);
+       else
+               return min(i->count, i->iov->iov_len - i->iov_offset);
+}
+EXPORT_SYMBOL(iov_iter_single_seg_count);
+
+void iov_iter_kvec(struct iov_iter *i, int direction,
+                       const struct kvec *kvec, unsigned long nr_segs,
+                       size_t count)
+{
+       BUG_ON(!(direction & ITER_KVEC));
+       i->type = direction;
+       i->kvec = kvec;
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_kvec);
+
+void iov_iter_bvec(struct iov_iter *i, int direction,
+                       const struct bio_vec *bvec, unsigned long nr_segs,
+                       size_t count)
+{
+       BUG_ON(!(direction & ITER_BVEC));
+       i->type = direction;
+       i->bvec = bvec;
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_bvec);
+
+unsigned long iov_iter_alignment(const struct iov_iter *i)
+{
+       unsigned long res = 0;
+       size_t size = i->count;
+
+       if (!size)
+               return 0;
+
+       iterate_all_kinds(i, size, v,
+               (res |= (unsigned long)v.iov_base | v.iov_len, 0),
+               res |= v.bv_offset | v.bv_len,
+               res |= (unsigned long)v.iov_base | v.iov_len
+       )
+       return res;
+}
+EXPORT_SYMBOL(iov_iter_alignment);
+
+ssize_t iov_iter_get_pages(struct iov_iter *i,
+                  struct page **pages, size_t maxsize, unsigned maxpages,
+                  size_t *start)
+{
+       if (maxsize > i->count)
+               maxsize = i->count;
+
+       if (!maxsize)
+               return 0;
+
+       iterate_all_kinds(i, maxsize, v, ({
+               unsigned long addr = (unsigned long)v.iov_base;
+               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
+               int n;
+               int res;
+
+               if (len > maxpages * PAGE_SIZE)
+                       len = maxpages * PAGE_SIZE;
+               addr &= ~(PAGE_SIZE - 1);
+               n = DIV_ROUND_UP(len, PAGE_SIZE);
+               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages);
+               if (unlikely(res < 0))
+                       return res;
+               return (res == n ? len : res * PAGE_SIZE) - *start;
+       0;}),({
+               /* can't be more than PAGE_SIZE */
+               *start = v.bv_offset;
+               get_page(*pages = v.bv_page);
+               return v.bv_len;
+       }),({
+               return -EFAULT;
+       })
+       )
+       return 0;
+}
+EXPORT_SYMBOL(iov_iter_get_pages);
+
+static struct page **get_pages_array(size_t n)
+{
+       struct page **p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
+       if (!p)
+               p = vmalloc(n * sizeof(struct page *));
+       return p;
+}
+
+ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
+                  struct page ***pages, size_t maxsize,
+                  size_t *start)
+{
+       struct page **p;
+
+       if (maxsize > i->count)
+               maxsize = i->count;
+
+       if (!maxsize)
+               return 0;
+
+       iterate_all_kinds(i, maxsize, v, ({
+               unsigned long addr = (unsigned long)v.iov_base;
+               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
+               int n;
+               int res;
+
+               addr &= ~(PAGE_SIZE - 1);
+               n = DIV_ROUND_UP(len, PAGE_SIZE);
+               p = get_pages_array(n);
+               if (!p)
+                       return -ENOMEM;
+               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
+               if (unlikely(res < 0)) {
+                       kvfree(p);
+                       return res;
+               }
+               *pages = p;
+               return (res == n ? len : res * PAGE_SIZE) - *start;
+       0;}),({
+               /* can't be more than PAGE_SIZE */
+               *start = v.bv_offset;
+               *pages = p = get_pages_array(1);
+               if (!p)
+                       return -ENOMEM;
+               get_page(*p = v.bv_page);
+               return v.bv_len;
+       }),({
+               return -EFAULT;
+       })
+       )
+       return 0;
+}
+EXPORT_SYMBOL(iov_iter_get_pages_alloc);
+
+size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
+                              struct iov_iter *i)
+{
+       char *to = addr;
+       __wsum sum, next;
+       size_t off = 0;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       sum = *csum;
+       iterate_and_advance(i, bytes, v, ({
+               int err = 0;
+               next = csum_and_copy_from_user(v.iov_base, 
+                                              (to += v.iov_len) - v.iov_len,
+                                              v.iov_len, 0, &err);
+               if (!err) {
+                       sum = csum_block_add(sum, next, off);
+                       off += v.iov_len;
+               }
+               err ? v.iov_len : 0;
+       }), ({
+               char *p = kmap_atomic(v.bv_page);
+               next = csum_partial_copy_nocheck(p + v.bv_offset,
+                                                (to += v.bv_len) - v.bv_len,
+                                                v.bv_len, 0);
+               kunmap_atomic(p);
+               sum = csum_block_add(sum, next, off);
+               off += v.bv_len;
+       }),({
+               next = csum_partial_copy_nocheck(v.iov_base,
+                                                (to += v.iov_len) - v.iov_len,
+                                                v.iov_len, 0);
+               sum = csum_block_add(sum, next, off);
+               off += v.iov_len;
+       })
+       )
+       *csum = sum;
+       return bytes;
+}
+EXPORT_SYMBOL(csum_and_copy_from_iter);
+
+size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum,
+                            struct iov_iter *i)
+{
+       char *from = addr;
+       __wsum sum, next;
+       size_t off = 0;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       sum = *csum;
+       iterate_and_advance(i, bytes, v, ({
+               int err = 0;
+               next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
+                                            v.iov_base, 
+                                            v.iov_len, 0, &err);
+               if (!err) {
+                       sum = csum_block_add(sum, next, off);
+                       off += v.iov_len;
+               }
+               err ? v.iov_len : 0;
+       }), ({
+               char *p = kmap_atomic(v.bv_page);
+               next = csum_partial_copy_nocheck((from += v.bv_len) - v.bv_len,
+                                                p + v.bv_offset,
+                                                v.bv_len, 0);
+               kunmap_atomic(p);
+               sum = csum_block_add(sum, next, off);
+               off += v.bv_len;
+       }),({
+               next = csum_partial_copy_nocheck((from += v.iov_len) - v.iov_len,
+                                                v.iov_base,
+                                                v.iov_len, 0);
+               sum = csum_block_add(sum, next, off);
+               off += v.iov_len;
+       })
+       )
+       *csum = sum;
+       return bytes;
+}
+EXPORT_SYMBOL(csum_and_copy_to_iter);
+
+int iov_iter_npages(const struct iov_iter *i, int maxpages)
+{
+       size_t size = i->count;
+       int npages = 0;
+
+       if (!size)
+               return 0;
+
+       iterate_all_kinds(i, size, v, ({
+               unsigned long p = (unsigned long)v.iov_base;
+               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
+                       - p / PAGE_SIZE;
+               if (npages >= maxpages)
+                       return maxpages;
+       0;}),({
+               npages++;
+               if (npages >= maxpages)
+                       return maxpages;
+       }),({
+               unsigned long p = (unsigned long)v.iov_base;
+               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
+                       - p / PAGE_SIZE;
+               if (npages >= maxpages)
+                       return maxpages;
+       })
+       )
+       return npages;
+}
+EXPORT_SYMBOL(iov_iter_npages);
+
+const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
+{
+       *new = *old;
+       if (new->type & ITER_BVEC)
+               return new->bvec = kmemdup(new->bvec,
+                                   new->nr_segs * sizeof(struct bio_vec),
+                                   flags);
+       else
+               /* iovec and kvec have identical layout */
+               return new->iov = kmemdup(new->iov,
+                                  new->nr_segs * sizeof(struct iovec),
+                                  flags);
+}
+EXPORT_SYMBOL(dup_iter);
index 7a85967060a518a43c5da9125a03d701ab892304..f0f5c5c3de12e1a23b5aeebc7ec05da6e78d3c14 100644 (file)
@@ -139,6 +139,9 @@ static int lz4_uncompress(const char *source, char *dest, int osize)
                        /* Error: request to write beyond destination buffer */
                        if (cpy > oend)
                                goto _output_error;
+                       if ((ref + COPYLENGTH) > oend ||
+                                       (op + COPYLENGTH) > oend)
+                               goto _output_error;
                        LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
                        while (op < cpy)
                                *op++ = *ref++;
index 9cc4c4a90d00686228bebdfe55b212c34e98206f..b5344ef4c6846c4f9256c1d0d418f774284c8fcc 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/log2.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
@@ -217,15 +218,15 @@ static void bucket_table_free(const struct bucket_table *tbl)
 static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
                                               size_t nbuckets)
 {
-       struct bucket_table *tbl;
+       struct bucket_table *tbl = NULL;
        size_t size;
        int i;
 
        size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]);
-       tbl = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+       if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
+               tbl = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
        if (tbl == NULL)
                tbl = vzalloc(size);
-
        if (tbl == NULL)
                return NULL;
 
@@ -247,26 +248,24 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
  * @ht:                hash table
  * @new_size:  new table size
  */
-bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size)
+static bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size)
 {
        /* Expand table when exceeding 75% load */
        return atomic_read(&ht->nelems) > (new_size / 4 * 3) &&
-              (ht->p.max_shift && atomic_read(&ht->shift) < ht->p.max_shift);
+              (!ht->p.max_shift || atomic_read(&ht->shift) < ht->p.max_shift);
 }
-EXPORT_SYMBOL_GPL(rht_grow_above_75);
 
 /**
  * rht_shrink_below_30 - returns true if nelems < 0.3 * table-size
  * @ht:                hash table
  * @new_size:  new table size
  */
-bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size)
+static bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size)
 {
        /* Shrink table beneath 30% load */
        return atomic_read(&ht->nelems) < (new_size * 3 / 10) &&
               (atomic_read(&ht->shift) > ht->p.min_shift);
 }
-EXPORT_SYMBOL_GPL(rht_shrink_below_30);
 
 static void lock_buckets(struct bucket_table *new_tbl,
                         struct bucket_table *old_tbl, unsigned int hash)
@@ -414,6 +413,7 @@ int rhashtable_expand(struct rhashtable *ht)
                        }
                }
                unlock_buckets(new_tbl, old_tbl, new_hash);
+               cond_resched();
        }
 
        /* Unzip interleaved hash chains */
@@ -437,6 +437,7 @@ int rhashtable_expand(struct rhashtable *ht)
                                complete = false;
 
                        unlock_buckets(new_tbl, old_tbl, old_hash);
+                       cond_resched();
                }
        }
 
@@ -495,6 +496,7 @@ int rhashtable_shrink(struct rhashtable *ht)
                                   tbl->buckets[new_hash + new_tbl->size]);
 
                unlock_buckets(new_tbl, tbl, new_hash);
+               cond_resched();
        }
 
        /* Publish the new, valid hash table */
@@ -528,31 +530,19 @@ static void rht_deferred_worker(struct work_struct *work)
        list_for_each_entry(walker, &ht->walkers, list)
                walker->resize = true;
 
-       if (ht->p.grow_decision && ht->p.grow_decision(ht, tbl->size))
+       if (rht_grow_above_75(ht, tbl->size))
                rhashtable_expand(ht);
-       else if (ht->p.shrink_decision && ht->p.shrink_decision(ht, tbl->size))
+       else if (rht_shrink_below_30(ht, tbl->size))
                rhashtable_shrink(ht);
-
 unlock:
        mutex_unlock(&ht->mutex);
 }
 
-static void rhashtable_wakeup_worker(struct rhashtable *ht)
-{
-       struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht);
-       struct bucket_table *new_tbl = rht_dereference_rcu(ht->future_tbl, ht);
-       size_t size = tbl->size;
-
-       /* Only adjust the table if no resizing is currently in progress. */
-       if (tbl == new_tbl &&
-           ((ht->p.grow_decision && ht->p.grow_decision(ht, size)) ||
-            (ht->p.shrink_decision && ht->p.shrink_decision(ht, size))))
-               schedule_work(&ht->run_work);
-}
-
 static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj,
-                               struct bucket_table *tbl, u32 hash)
+                               struct bucket_table *tbl,
+                               const struct bucket_table *old_tbl, u32 hash)
 {
+       bool no_resize_running = tbl == old_tbl;
        struct rhash_head *head;
 
        hash = rht_bucket_index(tbl, hash);
@@ -568,8 +558,8 @@ static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj,
        rcu_assign_pointer(tbl->buckets[hash], obj);
 
        atomic_inc(&ht->nelems);
-
-       rhashtable_wakeup_worker(ht);
+       if (no_resize_running && rht_grow_above_75(ht, tbl->size))
+               schedule_work(&ht->run_work);
 }
 
 /**
@@ -599,7 +589,7 @@ void rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj)
        hash = obj_raw_hashfn(ht, rht_obj(ht, obj));
 
        lock_buckets(tbl, old_tbl, hash);
-       __rhashtable_insert(ht, obj, tbl, hash);
+       __rhashtable_insert(ht, obj, tbl, old_tbl, hash);
        unlock_buckets(tbl, old_tbl, hash);
 
        rcu_read_unlock();
@@ -681,8 +671,11 @@ found:
        unlock_buckets(new_tbl, old_tbl, new_hash);
 
        if (ret) {
+               bool no_resize_running = new_tbl == old_tbl;
+
                atomic_dec(&ht->nelems);
-               rhashtable_wakeup_worker(ht);
+               if (no_resize_running && rht_shrink_below_30(ht, new_tbl->size))
+                       schedule_work(&ht->run_work);
        }
 
        rcu_read_unlock();
@@ -852,7 +845,7 @@ bool rhashtable_lookup_compare_insert(struct rhashtable *ht,
                goto exit;
        }
 
-       __rhashtable_insert(ht, obj, new_tbl, new_hash);
+       __rhashtable_insert(ht, obj, new_tbl, old_tbl, new_hash);
 
 exit:
        unlock_buckets(new_tbl, old_tbl, new_hash);
@@ -894,6 +887,9 @@ int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter)
        if (!iter->walker)
                return -ENOMEM;
 
+       INIT_LIST_HEAD(&iter->walker->list);
+       iter->walker->resize = false;
+
        mutex_lock(&ht->mutex);
        list_add(&iter->walker->list, &ht->walkers);
        mutex_unlock(&ht->mutex);
@@ -1111,8 +1107,7 @@ int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params)
        if (!ht->p.hash_rnd)
                get_random_bytes(&ht->p.hash_rnd, sizeof(ht->p.hash_rnd));
 
-       if (ht->p.grow_decision || ht->p.shrink_decision)
-               INIT_WORK(&ht->run_work, rht_deferred_worker);
+       INIT_WORK(&ht->run_work, rht_deferred_worker);
 
        return 0;
 }
@@ -1130,8 +1125,7 @@ void rhashtable_destroy(struct rhashtable *ht)
 {
        ht->being_destroyed = true;
 
-       if (ht->p.grow_decision || ht->p.shrink_decision)
-               cancel_work_sync(&ht->run_work);
+       cancel_work_sync(&ht->run_work);
 
        mutex_lock(&ht->mutex);
        bucket_table_free(rht_dereference(ht->tbl, ht));
index 88c0854bd7527aca54ca5ec3f533efe896c5477a..5c94e1012a91f9ea65b20ca130f3f4aa4fb337f5 100644 (file)
@@ -61,7 +61,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
 
        if (s->len < s->size) {
                len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
-               if (seq_buf_can_fit(s, len)) {
+               if (s->len + len < s->size) {
                        s->len += len;
                        return 0;
                }
@@ -118,7 +118,7 @@ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
 
        if (s->len < s->size) {
                ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
-               if (seq_buf_can_fit(s, ret)) {
+               if (s->len + ret < s->size) {
                        s->len += ret;
                        return 0;
                }
index 1dfeba73fc743718d94551e9356ec8c6580a1fac..67c7593d1dd69c91f646e21e47b589c40c808837 100644 (file)
@@ -191,18 +191,18 @@ error:
        return err;
 }
 
+static struct rhashtable ht;
+
 static int __init test_rht_init(void)
 {
-       struct rhashtable ht;
        struct rhashtable_params params = {
                .nelem_hint = TEST_HT_SIZE,
                .head_offset = offsetof(struct test_obj, node),
                .key_offset = offsetof(struct test_obj, value),
                .key_len = sizeof(int),
                .hashfn = jhash,
+               .max_shift = 1, /* we expand/shrink manually here */
                .nulls_base = (3U << RHT_BASE_SHIFT),
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
        int err;
 
@@ -222,6 +222,11 @@ static int __init test_rht_init(void)
        return err;
 }
 
+static void __exit test_rht_exit(void)
+{
+}
+
 module_init(test_rht_init);
+module_exit(test_rht_exit);
 
 MODULE_LICENSE("GPL v2");
index 3c1caa2693bd22bad68864896c5e02737aac31c5..15dbe9903c273f87c3e7c6a09e3c4a659647bd48 100644 (file)
@@ -21,7 +21,7 @@ obj-y                 := filemap.o mempool.o oom_kill.o \
                           mm_init.o mmu_context.o percpu.o slab_common.o \
                           compaction.o vmacache.o \
                           interval_tree.o list_lru.o workingset.o \
-                          iov_iter.o debug.o $(mmu-y)
+                          debug.o $(mmu-y)
 
 obj-y += init-mm.o
 
index 75016fd1de906280490352006ffc6845c90ddc46..68ecb7a42983a589fe4c057f109e327b352c8a0b 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -64,15 +64,17 @@ static unsigned long cma_bitmap_aligned_mask(struct cma *cma, int align_order)
        return (1UL << (align_order - cma->order_per_bit)) - 1;
 }
 
+/*
+ * Find a PFN aligned to the specified order and return an offset represented in
+ * order_per_bits.
+ */
 static unsigned long cma_bitmap_aligned_offset(struct cma *cma, int align_order)
 {
-       unsigned int alignment;
-
        if (align_order <= cma->order_per_bit)
                return 0;
-       alignment = 1UL << (align_order - cma->order_per_bit);
-       return ALIGN(cma->base_pfn, alignment) -
-               (cma->base_pfn >> cma->order_per_bit);
+
+       return (ALIGN(cma->base_pfn, (1UL << align_order))
+               - cma->base_pfn) >> cma->order_per_bit;
 }
 
 static unsigned long cma_bitmap_maxno(struct cma *cma)
index fc00c8cb5a82ee89addf4d2ee8983894bf6aa5d1..6817b0350c71c43b0f89a4972ce19c51a2408a2b 100644 (file)
@@ -1260,6 +1260,7 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        int target_nid, last_cpupid = -1;
        bool page_locked;
        bool migrated = false;
+       bool was_writable;
        int flags = 0;
 
        /* A PROT_NONE fault should not end up here */
@@ -1291,12 +1292,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                flags |= TNF_FAULT_LOCAL;
        }
 
-       /*
-        * Avoid grouping on DSO/COW pages in specific and RO pages
-        * in general, RO pages shouldn't hurt as much anyway since
-        * they can be in shared cache state.
-        */
-       if (!pmd_write(pmd))
+       /* See similar comment in do_numa_page for explanation */
+       if (!(vma->vm_flags & VM_WRITE))
                flags |= TNF_NO_GROUP;
 
        /*
@@ -1353,12 +1350,17 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (migrated) {
                flags |= TNF_MIGRATED;
                page_nid = target_nid;
-       }
+       } else
+               flags |= TNF_MIGRATE_FAIL;
 
        goto out;
 clear_pmdnuma:
        BUG_ON(!PageLocked(page));
+       was_writable = pmd_write(pmd);
        pmd = pmd_modify(pmd, vma->vm_page_prot);
+       pmd = pmd_mkyoung(pmd);
+       if (was_writable)
+               pmd = pmd_mkwrite(pmd);
        set_pmd_at(mm, haddr, pmdp, pmd);
        update_mmu_cache_pmd(vma, addr, pmdp);
        unlock_page(page);
@@ -1482,6 +1484,8 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
 
        if (__pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
                pmd_t entry;
+               bool preserve_write = prot_numa && pmd_write(*pmd);
+               ret = 1;
 
                /*
                 * Avoid trapping faults against the zero page. The read-only
@@ -1490,16 +1494,17 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                 */
                if (prot_numa && is_huge_zero_pmd(*pmd)) {
                        spin_unlock(ptl);
-                       return 0;
+                       return ret;
                }
 
                if (!prot_numa || !pmd_protnone(*pmd)) {
-                       ret = 1;
                        entry = pmdp_get_and_clear_notify(mm, addr, pmd);
                        entry = pmd_modify(entry, newprot);
+                       if (preserve_write)
+                               entry = pmd_mkwrite(entry);
                        ret = HPAGE_PMD_NR;
                        set_pmd_at(mm, addr, pmd, entry);
-                       BUG_ON(pmd_write(entry));
+                       BUG_ON(!preserve_write && pmd_write(entry));
                }
                spin_unlock(ptl);
        }
index 0a9ac6c268325a6ca9096bfc784cfbf68ac6a65e..c41b2a0ee2736e4f7df74c440ceb90bd5fcceecb 100644 (file)
@@ -917,7 +917,6 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order)
        __SetPageHead(page);
        __ClearPageReserved(page);
        for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) {
-               __SetPageTail(p);
                /*
                 * For gigantic hugepages allocated through bootmem at
                 * boot, it's safer to be consistent with the not-gigantic
@@ -933,6 +932,9 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order)
                __ClearPageReserved(p);
                set_page_count(p, 0);
                p->first_page = page;
+               /* Make sure p->first_page is always valid for PageTail() */
+               smp_wmb();
+               __SetPageTail(p);
        }
 }
 
diff --git a/mm/iov_iter.c b/mm/iov_iter.c
deleted file mode 100644 (file)
index 8277320..0000000
+++ /dev/null
@@ -1,753 +0,0 @@
-#include <linux/export.h>
-#include <linux/uio.h>
-#include <linux/pagemap.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <net/checksum.h>
-
-#define iterate_iovec(i, n, __v, __p, skip, STEP) {    \
-       size_t left;                                    \
-       size_t wanted = n;                              \
-       __p = i->iov;                                   \
-       __v.iov_len = min(n, __p->iov_len - skip);      \
-       if (likely(__v.iov_len)) {                      \
-               __v.iov_base = __p->iov_base + skip;    \
-               left = (STEP);                          \
-               __v.iov_len -= left;                    \
-               skip += __v.iov_len;                    \
-               n -= __v.iov_len;                       \
-       } else {                                        \
-               left = 0;                               \
-       }                                               \
-       while (unlikely(!left && n)) {                  \
-               __p++;                                  \
-               __v.iov_len = min(n, __p->iov_len);     \
-               if (unlikely(!__v.iov_len))             \
-                       continue;                       \
-               __v.iov_base = __p->iov_base;           \
-               left = (STEP);                          \
-               __v.iov_len -= left;                    \
-               skip = __v.iov_len;                     \
-               n -= __v.iov_len;                       \
-       }                                               \
-       n = wanted - n;                                 \
-}
-
-#define iterate_kvec(i, n, __v, __p, skip, STEP) {     \
-       size_t wanted = n;                              \
-       __p = i->kvec;                                  \
-       __v.iov_len = min(n, __p->iov_len - skip);      \
-       if (likely(__v.iov_len)) {                      \
-               __v.iov_base = __p->iov_base + skip;    \
-               (void)(STEP);                           \
-               skip += __v.iov_len;                    \
-               n -= __v.iov_len;                       \
-       }                                               \
-       while (unlikely(n)) {                           \
-               __p++;                                  \
-               __v.iov_len = min(n, __p->iov_len);     \
-               if (unlikely(!__v.iov_len))             \
-                       continue;                       \
-               __v.iov_base = __p->iov_base;           \
-               (void)(STEP);                           \
-               skip = __v.iov_len;                     \
-               n -= __v.iov_len;                       \
-       }                                               \
-       n = wanted;                                     \
-}
-
-#define iterate_bvec(i, n, __v, __p, skip, STEP) {     \
-       size_t wanted = n;                              \
-       __p = i->bvec;                                  \
-       __v.bv_len = min_t(size_t, n, __p->bv_len - skip);      \
-       if (likely(__v.bv_len)) {                       \
-               __v.bv_page = __p->bv_page;             \
-               __v.bv_offset = __p->bv_offset + skip;  \
-               (void)(STEP);                           \
-               skip += __v.bv_len;                     \
-               n -= __v.bv_len;                        \
-       }                                               \
-       while (unlikely(n)) {                           \
-               __p++;                                  \
-               __v.bv_len = min_t(size_t, n, __p->bv_len);     \
-               if (unlikely(!__v.bv_len))              \
-                       continue;                       \
-               __v.bv_page = __p->bv_page;             \
-               __v.bv_offset = __p->bv_offset;         \
-               (void)(STEP);                           \
-               skip = __v.bv_len;                      \
-               n -= __v.bv_len;                        \
-       }                                               \
-       n = wanted;                                     \
-}
-
-#define iterate_all_kinds(i, n, v, I, B, K) {                  \
-       size_t skip = i->iov_offset;                            \
-       if (unlikely(i->type & ITER_BVEC)) {                    \
-               const struct bio_vec *bvec;                     \
-               struct bio_vec v;                               \
-               iterate_bvec(i, n, v, bvec, skip, (B))          \
-       } else if (unlikely(i->type & ITER_KVEC)) {             \
-               const struct kvec *kvec;                        \
-               struct kvec v;                                  \
-               iterate_kvec(i, n, v, kvec, skip, (K))          \
-       } else {                                                \
-               const struct iovec *iov;                        \
-               struct iovec v;                                 \
-               iterate_iovec(i, n, v, iov, skip, (I))          \
-       }                                                       \
-}
-
-#define iterate_and_advance(i, n, v, I, B, K) {                        \
-       size_t skip = i->iov_offset;                            \
-       if (unlikely(i->type & ITER_BVEC)) {                    \
-               const struct bio_vec *bvec;                     \
-               struct bio_vec v;                               \
-               iterate_bvec(i, n, v, bvec, skip, (B))          \
-               if (skip == bvec->bv_len) {                     \
-                       bvec++;                                 \
-                       skip = 0;                               \
-               }                                               \
-               i->nr_segs -= bvec - i->bvec;                   \
-               i->bvec = bvec;                                 \
-       } else if (unlikely(i->type & ITER_KVEC)) {             \
-               const struct kvec *kvec;                        \
-               struct kvec v;                                  \
-               iterate_kvec(i, n, v, kvec, skip, (K))          \
-               if (skip == kvec->iov_len) {                    \
-                       kvec++;                                 \
-                       skip = 0;                               \
-               }                                               \
-               i->nr_segs -= kvec - i->kvec;                   \
-               i->kvec = kvec;                                 \
-       } else {                                                \
-               const struct iovec *iov;                        \
-               struct iovec v;                                 \
-               iterate_iovec(i, n, v, iov, skip, (I))          \
-               if (skip == iov->iov_len) {                     \
-                       iov++;                                  \
-                       skip = 0;                               \
-               }                                               \
-               i->nr_segs -= iov - i->iov;                     \
-               i->iov = iov;                                   \
-       }                                                       \
-       i->count -= n;                                          \
-       i->iov_offset = skip;                                   \
-}
-
-static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       size_t skip, copy, left, wanted;
-       const struct iovec *iov;
-       char __user *buf;
-       void *kaddr, *from;
-
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       wanted = bytes;
-       iov = i->iov;
-       skip = i->iov_offset;
-       buf = iov->iov_base + skip;
-       copy = min(bytes, iov->iov_len - skip);
-
-       if (!fault_in_pages_writeable(buf, copy)) {
-               kaddr = kmap_atomic(page);
-               from = kaddr + offset;
-
-               /* first chunk, usually the only one */
-               left = __copy_to_user_inatomic(buf, from, copy);
-               copy -= left;
-               skip += copy;
-               from += copy;
-               bytes -= copy;
-
-               while (unlikely(!left && bytes)) {
-                       iov++;
-                       buf = iov->iov_base;
-                       copy = min(bytes, iov->iov_len);
-                       left = __copy_to_user_inatomic(buf, from, copy);
-                       copy -= left;
-                       skip = copy;
-                       from += copy;
-                       bytes -= copy;
-               }
-               if (likely(!bytes)) {
-                       kunmap_atomic(kaddr);
-                       goto done;
-               }
-               offset = from - kaddr;
-               buf += copy;
-               kunmap_atomic(kaddr);
-               copy = min(bytes, iov->iov_len - skip);
-       }
-       /* Too bad - revert to non-atomic kmap */
-       kaddr = kmap(page);
-       from = kaddr + offset;
-       left = __copy_to_user(buf, from, copy);
-       copy -= left;
-       skip += copy;
-       from += copy;
-       bytes -= copy;
-       while (unlikely(!left && bytes)) {
-               iov++;
-               buf = iov->iov_base;
-               copy = min(bytes, iov->iov_len);
-               left = __copy_to_user(buf, from, copy);
-               copy -= left;
-               skip = copy;
-               from += copy;
-               bytes -= copy;
-       }
-       kunmap(page);
-done:
-       if (skip == iov->iov_len) {
-               iov++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= iov - i->iov;
-       i->iov = iov;
-       i->iov_offset = skip;
-       return wanted - bytes;
-}
-
-static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       size_t skip, copy, left, wanted;
-       const struct iovec *iov;
-       char __user *buf;
-       void *kaddr, *to;
-
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       wanted = bytes;
-       iov = i->iov;
-       skip = i->iov_offset;
-       buf = iov->iov_base + skip;
-       copy = min(bytes, iov->iov_len - skip);
-
-       if (!fault_in_pages_readable(buf, copy)) {
-               kaddr = kmap_atomic(page);
-               to = kaddr + offset;
-
-               /* first chunk, usually the only one */
-               left = __copy_from_user_inatomic(to, buf, copy);
-               copy -= left;
-               skip += copy;
-               to += copy;
-               bytes -= copy;
-
-               while (unlikely(!left && bytes)) {
-                       iov++;
-                       buf = iov->iov_base;
-                       copy = min(bytes, iov->iov_len);
-                       left = __copy_from_user_inatomic(to, buf, copy);
-                       copy -= left;
-                       skip = copy;
-                       to += copy;
-                       bytes -= copy;
-               }
-               if (likely(!bytes)) {
-                       kunmap_atomic(kaddr);
-                       goto done;
-               }
-               offset = to - kaddr;
-               buf += copy;
-               kunmap_atomic(kaddr);
-               copy = min(bytes, iov->iov_len - skip);
-       }
-       /* Too bad - revert to non-atomic kmap */
-       kaddr = kmap(page);
-       to = kaddr + offset;
-       left = __copy_from_user(to, buf, copy);
-       copy -= left;
-       skip += copy;
-       to += copy;
-       bytes -= copy;
-       while (unlikely(!left && bytes)) {
-               iov++;
-               buf = iov->iov_base;
-               copy = min(bytes, iov->iov_len);
-               left = __copy_from_user(to, buf, copy);
-               copy -= left;
-               skip = copy;
-               to += copy;
-               bytes -= copy;
-       }
-       kunmap(page);
-done:
-       if (skip == iov->iov_len) {
-               iov++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= iov - i->iov;
-       i->iov = iov;
-       i->iov_offset = skip;
-       return wanted - bytes;
-}
-
-/*
- * Fault in the first iovec of the given iov_iter, to a maximum length
- * of bytes. Returns 0 on success, or non-zero if the memory could not be
- * accessed (ie. because it is an invalid address).
- *
- * writev-intensive code may want this to prefault several iovecs -- that
- * would be possible (callers must not rely on the fact that _only_ the
- * first iovec will be faulted with the current implementation).
- */
-int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
-{
-       if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
-               char __user *buf = i->iov->iov_base + i->iov_offset;
-               bytes = min(bytes, i->iov->iov_len - i->iov_offset);
-               return fault_in_pages_readable(buf, bytes);
-       }
-       return 0;
-}
-EXPORT_SYMBOL(iov_iter_fault_in_readable);
-
-void iov_iter_init(struct iov_iter *i, int direction,
-                       const struct iovec *iov, unsigned long nr_segs,
-                       size_t count)
-{
-       /* It will get better.  Eventually... */
-       if (segment_eq(get_fs(), KERNEL_DS)) {
-               direction |= ITER_KVEC;
-               i->type = direction;
-               i->kvec = (struct kvec *)iov;
-       } else {
-               i->type = direction;
-               i->iov = iov;
-       }
-       i->nr_segs = nr_segs;
-       i->iov_offset = 0;
-       i->count = count;
-}
-EXPORT_SYMBOL(iov_iter_init);
-
-static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len)
-{
-       char *from = kmap_atomic(page);
-       memcpy(to, from + offset, len);
-       kunmap_atomic(from);
-}
-
-static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t len)
-{
-       char *to = kmap_atomic(page);
-       memcpy(to + offset, from, len);
-       kunmap_atomic(to);
-}
-
-static void memzero_page(struct page *page, size_t offset, size_t len)
-{
-       char *addr = kmap_atomic(page);
-       memset(addr + offset, 0, len);
-       kunmap_atomic(addr);
-}
-
-size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i)
-{
-       char *from = addr;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __copy_to_user(v.iov_base, (from += v.iov_len) - v.iov_len,
-                              v.iov_len),
-               memcpy_to_page(v.bv_page, v.bv_offset,
-                              (from += v.bv_len) - v.bv_len, v.bv_len),
-               memcpy(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(copy_to_iter);
-
-size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
-{
-       char *to = addr;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __copy_from_user((to += v.iov_len) - v.iov_len, v.iov_base,
-                                v.iov_len),
-               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
-                                v.bv_offset, v.bv_len),
-               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(copy_from_iter);
-
-size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
-{
-       char *to = addr;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __copy_from_user_nocache((to += v.iov_len) - v.iov_len,
-                                        v.iov_base, v.iov_len),
-               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
-                                v.bv_offset, v.bv_len),
-               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(copy_from_iter_nocache);
-
-size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       if (i->type & (ITER_BVEC|ITER_KVEC)) {
-               void *kaddr = kmap_atomic(page);
-               size_t wanted = copy_to_iter(kaddr + offset, bytes, i);
-               kunmap_atomic(kaddr);
-               return wanted;
-       } else
-               return copy_page_to_iter_iovec(page, offset, bytes, i);
-}
-EXPORT_SYMBOL(copy_page_to_iter);
-
-size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       if (i->type & (ITER_BVEC|ITER_KVEC)) {
-               void *kaddr = kmap_atomic(page);
-               size_t wanted = copy_from_iter(kaddr + offset, bytes, i);
-               kunmap_atomic(kaddr);
-               return wanted;
-       } else
-               return copy_page_from_iter_iovec(page, offset, bytes, i);
-}
-EXPORT_SYMBOL(copy_page_from_iter);
-
-size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
-{
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __clear_user(v.iov_base, v.iov_len),
-               memzero_page(v.bv_page, v.bv_offset, v.bv_len),
-               memset(v.iov_base, 0, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(iov_iter_zero);
-
-size_t iov_iter_copy_from_user_atomic(struct page *page,
-               struct iov_iter *i, unsigned long offset, size_t bytes)
-{
-       char *kaddr = kmap_atomic(page), *p = kaddr + offset;
-       iterate_all_kinds(i, bytes, v,
-               __copy_from_user_inatomic((p += v.iov_len) - v.iov_len,
-                                         v.iov_base, v.iov_len),
-               memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page,
-                                v.bv_offset, v.bv_len),
-               memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
-       )
-       kunmap_atomic(kaddr);
-       return bytes;
-}
-EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
-
-void iov_iter_advance(struct iov_iter *i, size_t size)
-{
-       iterate_and_advance(i, size, v, 0, 0, 0)
-}
-EXPORT_SYMBOL(iov_iter_advance);
-
-/*
- * Return the count of just the current iov_iter segment.
- */
-size_t iov_iter_single_seg_count(const struct iov_iter *i)
-{
-       if (i->nr_segs == 1)
-               return i->count;
-       else if (i->type & ITER_BVEC)
-               return min(i->count, i->bvec->bv_len - i->iov_offset);
-       else
-               return min(i->count, i->iov->iov_len - i->iov_offset);
-}
-EXPORT_SYMBOL(iov_iter_single_seg_count);
-
-void iov_iter_kvec(struct iov_iter *i, int direction,
-                       const struct kvec *kvec, unsigned long nr_segs,
-                       size_t count)
-{
-       BUG_ON(!(direction & ITER_KVEC));
-       i->type = direction;
-       i->kvec = kvec;
-       i->nr_segs = nr_segs;
-       i->iov_offset = 0;
-       i->count = count;
-}
-EXPORT_SYMBOL(iov_iter_kvec);
-
-void iov_iter_bvec(struct iov_iter *i, int direction,
-                       const struct bio_vec *bvec, unsigned long nr_segs,
-                       size_t count)
-{
-       BUG_ON(!(direction & ITER_BVEC));
-       i->type = direction;
-       i->bvec = bvec;
-       i->nr_segs = nr_segs;
-       i->iov_offset = 0;
-       i->count = count;
-}
-EXPORT_SYMBOL(iov_iter_bvec);
-
-unsigned long iov_iter_alignment(const struct iov_iter *i)
-{
-       unsigned long res = 0;
-       size_t size = i->count;
-
-       if (!size)
-               return 0;
-
-       iterate_all_kinds(i, size, v,
-               (res |= (unsigned long)v.iov_base | v.iov_len, 0),
-               res |= v.bv_offset | v.bv_len,
-               res |= (unsigned long)v.iov_base | v.iov_len
-       )
-       return res;
-}
-EXPORT_SYMBOL(iov_iter_alignment);
-
-ssize_t iov_iter_get_pages(struct iov_iter *i,
-                  struct page **pages, size_t maxsize, unsigned maxpages,
-                  size_t *start)
-{
-       if (maxsize > i->count)
-               maxsize = i->count;
-
-       if (!maxsize)
-               return 0;
-
-       iterate_all_kinds(i, maxsize, v, ({
-               unsigned long addr = (unsigned long)v.iov_base;
-               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
-               int n;
-               int res;
-
-               if (len > maxpages * PAGE_SIZE)
-                       len = maxpages * PAGE_SIZE;
-               addr &= ~(PAGE_SIZE - 1);
-               n = DIV_ROUND_UP(len, PAGE_SIZE);
-               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages);
-               if (unlikely(res < 0))
-                       return res;
-               return (res == n ? len : res * PAGE_SIZE) - *start;
-       0;}),({
-               /* can't be more than PAGE_SIZE */
-               *start = v.bv_offset;
-               get_page(*pages = v.bv_page);
-               return v.bv_len;
-       }),({
-               return -EFAULT;
-       })
-       )
-       return 0;
-}
-EXPORT_SYMBOL(iov_iter_get_pages);
-
-static struct page **get_pages_array(size_t n)
-{
-       struct page **p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
-       if (!p)
-               p = vmalloc(n * sizeof(struct page *));
-       return p;
-}
-
-ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
-                  struct page ***pages, size_t maxsize,
-                  size_t *start)
-{
-       struct page **p;
-
-       if (maxsize > i->count)
-               maxsize = i->count;
-
-       if (!maxsize)
-               return 0;
-
-       iterate_all_kinds(i, maxsize, v, ({
-               unsigned long addr = (unsigned long)v.iov_base;
-               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
-               int n;
-               int res;
-
-               addr &= ~(PAGE_SIZE - 1);
-               n = DIV_ROUND_UP(len, PAGE_SIZE);
-               p = get_pages_array(n);
-               if (!p)
-                       return -ENOMEM;
-               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
-               if (unlikely(res < 0)) {
-                       kvfree(p);
-                       return res;
-               }
-               *pages = p;
-               return (res == n ? len : res * PAGE_SIZE) - *start;
-       0;}),({
-               /* can't be more than PAGE_SIZE */
-               *start = v.bv_offset;
-               *pages = p = get_pages_array(1);
-               if (!p)
-                       return -ENOMEM;
-               get_page(*p = v.bv_page);
-               return v.bv_len;
-       }),({
-               return -EFAULT;
-       })
-       )
-       return 0;
-}
-EXPORT_SYMBOL(iov_iter_get_pages_alloc);
-
-size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
-                              struct iov_iter *i)
-{
-       char *to = addr;
-       __wsum sum, next;
-       size_t off = 0;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       sum = *csum;
-       iterate_and_advance(i, bytes, v, ({
-               int err = 0;
-               next = csum_and_copy_from_user(v.iov_base, 
-                                              (to += v.iov_len) - v.iov_len,
-                                              v.iov_len, 0, &err);
-               if (!err) {
-                       sum = csum_block_add(sum, next, off);
-                       off += v.iov_len;
-               }
-               err ? v.iov_len : 0;
-       }), ({
-               char *p = kmap_atomic(v.bv_page);
-               next = csum_partial_copy_nocheck(p + v.bv_offset,
-                                                (to += v.bv_len) - v.bv_len,
-                                                v.bv_len, 0);
-               kunmap_atomic(p);
-               sum = csum_block_add(sum, next, off);
-               off += v.bv_len;
-       }),({
-               next = csum_partial_copy_nocheck(v.iov_base,
-                                                (to += v.iov_len) - v.iov_len,
-                                                v.iov_len, 0);
-               sum = csum_block_add(sum, next, off);
-               off += v.iov_len;
-       })
-       )
-       *csum = sum;
-       return bytes;
-}
-EXPORT_SYMBOL(csum_and_copy_from_iter);
-
-size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum,
-                            struct iov_iter *i)
-{
-       char *from = addr;
-       __wsum sum, next;
-       size_t off = 0;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       sum = *csum;
-       iterate_and_advance(i, bytes, v, ({
-               int err = 0;
-               next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
-                                            v.iov_base, 
-                                            v.iov_len, 0, &err);
-               if (!err) {
-                       sum = csum_block_add(sum, next, off);
-                       off += v.iov_len;
-               }
-               err ? v.iov_len : 0;
-       }), ({
-               char *p = kmap_atomic(v.bv_page);
-               next = csum_partial_copy_nocheck((from += v.bv_len) - v.bv_len,
-                                                p + v.bv_offset,
-                                                v.bv_len, 0);
-               kunmap_atomic(p);
-               sum = csum_block_add(sum, next, off);
-               off += v.bv_len;
-       }),({
-               next = csum_partial_copy_nocheck((from += v.iov_len) - v.iov_len,
-                                                v.iov_base,
-                                                v.iov_len, 0);
-               sum = csum_block_add(sum, next, off);
-               off += v.iov_len;
-       })
-       )
-       *csum = sum;
-       return bytes;
-}
-EXPORT_SYMBOL(csum_and_copy_to_iter);
-
-int iov_iter_npages(const struct iov_iter *i, int maxpages)
-{
-       size_t size = i->count;
-       int npages = 0;
-
-       if (!size)
-               return 0;
-
-       iterate_all_kinds(i, size, v, ({
-               unsigned long p = (unsigned long)v.iov_base;
-               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
-                       - p / PAGE_SIZE;
-               if (npages >= maxpages)
-                       return maxpages;
-       0;}),({
-               npages++;
-               if (npages >= maxpages)
-                       return maxpages;
-       }),({
-               unsigned long p = (unsigned long)v.iov_base;
-               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
-                       - p / PAGE_SIZE;
-               if (npages >= maxpages)
-                       return maxpages;
-       })
-       )
-       return npages;
-}
-EXPORT_SYMBOL(iov_iter_npages);
index 78fee632a7ee9b73d9d0d5498d76aeb58460e711..936d81661c478a89fd797e8b311b4c52291f2414 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/stacktrace.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/vmalloc.h>
 #include <linux/kasan.h>
 
 #include "kasan.h"
@@ -414,12 +415,19 @@ int kasan_module_alloc(void *addr, size_t size)
                        GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
                        PAGE_KERNEL, VM_NO_GUARD, NUMA_NO_NODE,
                        __builtin_return_address(0));
-       return ret ? 0 : -ENOMEM;
+
+       if (ret) {
+               find_vm_area(addr)->flags |= VM_KASAN;
+               return 0;
+       }
+
+       return -ENOMEM;
 }
 
-void kasan_module_free(void *addr)
+void kasan_free_shadow(const struct vm_struct *vm)
 {
-       vfree(kasan_mem_to_shadow(addr));
+       if (vm->flags & VM_KASAN)
+               vfree(kasan_mem_to_shadow(vm->addr));
 }
 
 static void register_global(struct kasan_global *global)
index d18d3a6e7337d944a36e1375b1f50fdce483961f..b34ef4a32a3b266768248743849e241183e112ed 100644 (file)
@@ -5232,7 +5232,9 @@ static void mem_cgroup_bind(struct cgroup_subsys_state *root_css)
         * on for the root memcg is enough.
         */
        if (cgroup_on_dfl(root_css->cgroup))
-               mem_cgroup_from_css(root_css)->use_hierarchy = true;
+               root_mem_cgroup->use_hierarchy = true;
+       else
+               root_mem_cgroup->use_hierarchy = false;
 }
 
 static u64 memory_current_read(struct cgroup_subsys_state *css,
@@ -5247,7 +5249,7 @@ static int memory_low_show(struct seq_file *m, void *v)
        unsigned long low = ACCESS_ONCE(memcg->low);
 
        if (low == PAGE_COUNTER_MAX)
-               seq_puts(m, "infinity\n");
+               seq_puts(m, "max\n");
        else
                seq_printf(m, "%llu\n", (u64)low * PAGE_SIZE);
 
@@ -5262,7 +5264,7 @@ static ssize_t memory_low_write(struct kernfs_open_file *of,
        int err;
 
        buf = strstrip(buf);
-       err = page_counter_memparse(buf, "infinity", &low);
+       err = page_counter_memparse(buf, "max", &low);
        if (err)
                return err;
 
@@ -5277,7 +5279,7 @@ static int memory_high_show(struct seq_file *m, void *v)
        unsigned long high = ACCESS_ONCE(memcg->high);
 
        if (high == PAGE_COUNTER_MAX)
-               seq_puts(m, "infinity\n");
+               seq_puts(m, "max\n");
        else
                seq_printf(m, "%llu\n", (u64)high * PAGE_SIZE);
 
@@ -5292,7 +5294,7 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
        int err;
 
        buf = strstrip(buf);
-       err = page_counter_memparse(buf, "infinity", &high);
+       err = page_counter_memparse(buf, "max", &high);
        if (err)
                return err;
 
@@ -5307,7 +5309,7 @@ static int memory_max_show(struct seq_file *m, void *v)
        unsigned long max = ACCESS_ONCE(memcg->memory.limit);
 
        if (max == PAGE_COUNTER_MAX)
-               seq_puts(m, "infinity\n");
+               seq_puts(m, "max\n");
        else
                seq_printf(m, "%llu\n", (u64)max * PAGE_SIZE);
 
@@ -5322,7 +5324,7 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
        int err;
 
        buf = strstrip(buf);
-       err = page_counter_memparse(buf, "infinity", &max);
+       err = page_counter_memparse(buf, "max", &max);
        if (err)
                return err;
 
@@ -5426,7 +5428,7 @@ bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg)
        if (memcg == root_mem_cgroup)
                return false;
 
-       if (page_counter_read(&memcg->memory) > memcg->low)
+       if (page_counter_read(&memcg->memory) >= memcg->low)
                return false;
 
        while (memcg != root) {
@@ -5435,7 +5437,7 @@ bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg)
                if (memcg == root_mem_cgroup)
                        break;
 
-               if (page_counter_read(&memcg->memory) > memcg->low)
+               if (page_counter_read(&memcg->memory) >= memcg->low)
                        return false;
        }
        return true;
index 8068893697bbdbb5d64f9d43508658d601a6932e..97839f5c8c303df324a1cec1dfacadb1b0bfa04c 100644 (file)
@@ -3035,6 +3035,7 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        int last_cpupid;
        int target_nid;
        bool migrated = false;
+       bool was_writable = pte_write(pte);
        int flags = 0;
 
        /* A PROT_NONE fault should not end up here */
@@ -3059,6 +3060,8 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        /* Make it present again */
        pte = pte_modify(pte, vma->vm_page_prot);
        pte = pte_mkyoung(pte);
+       if (was_writable)
+               pte = pte_mkwrite(pte);
        set_pte_at(mm, addr, ptep, pte);
        update_mmu_cache(vma, addr, ptep);
 
@@ -3069,11 +3072,14 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        }
 
        /*
-        * Avoid grouping on DSO/COW pages in specific and RO pages
-        * in general, RO pages shouldn't hurt as much anyway since
-        * they can be in shared cache state.
+        * Avoid grouping on RO pages in general. RO pages shouldn't hurt as
+        * much anyway since they can be in shared cache state. This misses
+        * the case where a mapping is writable but the process never writes
+        * to it but pte_write gets cleared during protection updates and
+        * pte_dirty has unpredictable behaviour between PTE scan updates,
+        * background writeback, dirty balancing and application behaviour.
         */
-       if (!pte_write(pte))
+       if (!(vma->vm_flags & VM_WRITE))
                flags |= TNF_NO_GROUP;
 
        /*
@@ -3097,7 +3103,8 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (migrated) {
                page_nid = target_nid;
                flags |= TNF_MIGRATED;
-       }
+       } else
+               flags |= TNF_MIGRATE_FAIL;
 
 out:
        if (page_nid != -1)
index 9fab10795beabd723c29722a442ace37c349c66b..65842d688b7c9bb5dbfd2440fc07339fa94650f4 100644 (file)
@@ -1092,6 +1092,10 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
                        return NULL;
 
                arch_refresh_nodedata(nid, pgdat);
+       } else {
+               /* Reset the nr_zones and classzone_idx to 0 before reuse */
+               pgdat->nr_zones = 0;
+               pgdat->classzone_idx = 0;
        }
 
        /* we can use NODE_DATA(nid) from here */
@@ -1977,15 +1981,6 @@ void try_offline_node(int nid)
                if (is_vmalloc_addr(zone->wait_table))
                        vfree(zone->wait_table);
        }
-
-       /*
-        * Since there is no way to guarentee the address of pgdat/zone is not
-        * on stack of any kernel threads or used by other kernel objects
-        * without reference counting or other symchronizing method, do not
-        * reset node_data and free pgdat here. Just reset it to 0 and reuse
-        * the memory when the node is online again.
-        */
-       memset(pgdat, 0, sizeof(*pgdat));
 }
 EXPORT_SYMBOL(try_offline_node);
 
index 73cf0987088c36647fbb805278978bb656ff1fda..8a54cd214925872a66d4d1cc36b69ec6c6047324 100644 (file)
 
 int can_do_mlock(void)
 {
-       if (capable(CAP_IPC_LOCK))
-               return 1;
        if (rlimit(RLIMIT_MEMLOCK) != 0)
                return 1;
+       if (capable(CAP_IPC_LOCK))
+               return 1;
        return 0;
 }
 EXPORT_SYMBOL(can_do_mlock);
index da9990acc08b2d8014e342771a52650b47ee05fc..9ec50a368634a8d9a0824504d479b03798bdc402 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -774,10 +774,8 @@ again:                     remove_next = 1 + (end > next->vm_end);
 
                        importer->anon_vma = exporter->anon_vma;
                        error = anon_vma_clone(importer, exporter);
-                       if (error) {
-                               importer->anon_vma = NULL;
+                       if (error)
                                return error;
-                       }
                }
        }
 
index 44727811bf4cf62e3579261ee9699a37fab78b3d..88584838e7046bec724d68c0cafcd94eec65a040 100644 (file)
@@ -75,6 +75,7 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                oldpte = *pte;
                if (pte_present(oldpte)) {
                        pte_t ptent;
+                       bool preserve_write = prot_numa && pte_write(oldpte);
 
                        /*
                         * Avoid trapping faults against the zero or KSM
@@ -94,6 +95,8 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 
                        ptent = ptep_modify_prot_start(mm, addr, pte);
                        ptent = pte_modify(ptent, newprot);
+                       if (preserve_write)
+                               ptent = pte_mkwrite(ptent);
 
                        /* Avoid taking write faults for known dirty pages */
                        if (dirty_accountable && pte_dirty(ptent) &&
index 7296360fc057e5bbf67b9904501fdbe98a97b1b2..3fba2dc97c44bece0d6fb5754afdafb1dba6353e 100644 (file)
@@ -62,6 +62,7 @@ void *high_memory;
 EXPORT_SYMBOL(high_memory);
 struct page *mem_map;
 unsigned long max_mapnr;
+EXPORT_SYMBOL(max_mapnr);
 unsigned long highest_memmap_pfn;
 struct percpu_counter vm_committed_as;
 int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */
@@ -1213,11 +1214,9 @@ static int do_mmap_private(struct vm_area_struct *vma,
        if (sysctl_nr_trim_pages && total - point >= sysctl_nr_trim_pages) {
                total = point;
                kdebug("try to alloc exact %lu pages", total);
-               base = alloc_pages_exact(len, GFP_KERNEL);
-       } else {
-               base = (void *)__get_free_pages(GFP_KERNEL, order);
        }
 
+       base = alloc_pages_exact(total << PAGE_SHIFT, GFP_KERNEL);
        if (!base)
                goto enomem;
 
index 45e187b2d97183a90df9a5ee8558404f9f1bd826..644bcb665773f6e53f50fe6599429595b506f0c5 100644 (file)
@@ -857,8 +857,11 @@ static void bdi_update_write_bandwidth(struct backing_dev_info *bdi,
         *                   bw * elapsed + write_bandwidth * (period - elapsed)
         * write_bandwidth = ---------------------------------------------------
         *                                          period
+        *
+        * @written may have decreased due to account_page_redirty().
+        * Avoid underflowing @bw calculation.
         */
-       bw = written - bdi->written_stamp;
+       bw = written - min(written, bdi->written_stamp);
        bw *= HZ;
        if (unlikely(elapsed > period)) {
                do_div(bw, elapsed);
@@ -922,7 +925,7 @@ static void global_update_bandwidth(unsigned long thresh,
                                    unsigned long now)
 {
        static DEFINE_SPINLOCK(dirty_lock);
-       static unsigned long update_time;
+       static unsigned long update_time = INITIAL_JIFFIES;
 
        /*
         * check locklessly first to optimize away locking for the most time
index a47f0b229a1aca202b15195c88ab93d52e65064f..40e29429e7b0995bd5799bd6263b18d6ce8261cb 100644 (file)
@@ -2353,8 +2353,15 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
                if (ac->high_zoneidx < ZONE_NORMAL)
                        goto out;
                /* The OOM killer does not compensate for light reclaim */
-               if (!(gfp_mask & __GFP_FS))
+               if (!(gfp_mask & __GFP_FS)) {
+                       /*
+                        * XXX: Page reclaim didn't yield anything,
+                        * and the OOM killer can't be invoked, but
+                        * keep looping as per should_alloc_retry().
+                        */
+                       *did_some_progress = 1;
                        goto out;
+               }
                /*
                 * GFP_THISNODE contains __GFP_NORETRY and we never hit this.
                 * Sanity check for bare calls of __GFP_THISNODE, not real OOM.
@@ -2366,7 +2373,8 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
                        goto out;
        }
        /* Exhausted what can be done so it's blamo time */
-       if (out_of_memory(ac->zonelist, gfp_mask, order, ac->nodemask, false))
+       if (out_of_memory(ac->zonelist, gfp_mask, order, ac->nodemask, false)
+                       || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL))
                *did_some_progress = 1;
 out:
        oom_zonelist_unlock(ac->zonelist, gfp_mask);
index 72f5ac381ab3253b6016583e0618be6f3e91367c..755a42c76eb4747623da51acdeb780b322b5ac06 100644 (file)
@@ -103,6 +103,7 @@ void unset_migratetype_isolate(struct page *page, unsigned migratetype)
 
                        if (!is_migrate_isolate_page(buddy)) {
                                __isolate_free_page(page, order);
+                               kernel_map_pages(page, (1 << order), 1);
                                set_page_refcounted(page);
                                isolated_page = page;
                        }
index 75c1f2878519171139ae2d0b6f1e24809067ab4a..29f2f8b853ae51be4f9e35fbc1495ad69297ff82 100644 (file)
@@ -265,8 +265,15 @@ int walk_page_range(unsigned long start, unsigned long end,
                        vma = vma->vm_next;
 
                        err = walk_page_test(start, next, walk);
-                       if (err > 0)
+                       if (err > 0) {
+                               /*
+                                * positive return values are purely for
+                                * controlling the pagewalk, so should never
+                                * be passed to the callers.
+                                */
+                               err = 0;
                                continue;
+                       }
                        if (err < 0)
                                break;
                }
index 5e3e09081164b83814683513c174445e67669a4b..c161a14b6a8fb127150678f18582ad6f0a29f55d 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -287,6 +287,13 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
        return 0;
 
  enomem_failure:
+       /*
+        * dst->anon_vma is dropped here otherwise its degree can be incorrectly
+        * decremented in unlink_anon_vmas().
+        * We can safely do this because callers of anon_vma_clone() don't care
+        * about dst->anon_vma if anon_vma_clone() failed.
+        */
+       dst->anon_vma = NULL;
        unlink_anon_vmas(dst);
        return -ENOMEM;
 }
index 2f17cb5f00a43f87b7868a2a2192dd911f4501bd..cf2d0ca010bc52efd5ea86c7f6ba760a5c3ef286 100644 (file)
@@ -1455,6 +1455,9 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
 
 bool shmem_mapping(struct address_space *mapping)
 {
+       if (!mapping->host)
+               return false;
+
        return mapping->host->i_sb->s_op == &shmem_ops;
 }
 
index 6832c4eab104d15ff3d3bd907c92591540facf01..82c473780c9188ecf7bfc393703f47793a2fbfe9 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2449,7 +2449,8 @@ redo:
        do {
                tid = this_cpu_read(s->cpu_slab->tid);
                c = raw_cpu_ptr(s->cpu_slab);
-       } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid));
+       } while (IS_ENABLED(CONFIG_PREEMPT) &&
+                unlikely(tid != READ_ONCE(c->tid)));
 
        /*
         * Irqless object alloc/free algorithm used here depends on sequence
@@ -2718,7 +2719,8 @@ redo:
        do {
                tid = this_cpu_read(s->cpu_slab->tid);
                c = raw_cpu_ptr(s->cpu_slab);
-       } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid));
+       } while (IS_ENABLED(CONFIG_PREEMPT) &&
+                unlikely(tid != READ_ONCE(c->tid)));
 
        /* Same with comment on barrier() in slab_alloc_node() */
        barrier();
index 35b25e1340ca49cf0a95bbc80c69490ec68b5554..49abccf29a29f65c4748a6decec00c27fec23c6d 100644 (file)
@@ -1418,6 +1418,7 @@ struct vm_struct *remove_vm_area(const void *addr)
                spin_unlock(&vmap_area_lock);
 
                vmap_debug_free_range(va->va_start, va->va_end);
+               kasan_free_shadow(vm);
                free_unmap_vmap_area(va);
                vm->size -= PAGE_SIZE;
 
index d8e376a5f0f13d9eed735f62b81367b7bc685ebe..36a1a739ad68ff57eace5ba4bc4166faf12c485b 100644 (file)
@@ -658,14 +658,30 @@ p9_virtio_create(struct p9_client *client, const char *devname, char *args)
 static void p9_virtio_remove(struct virtio_device *vdev)
 {
        struct virtio_chan *chan = vdev->priv;
-
-       if (chan->inuse)
-               p9_virtio_close(chan->client);
-       vdev->config->del_vqs(vdev);
+       unsigned long warning_time;
 
        mutex_lock(&virtio_9p_lock);
+
+       /* Remove self from list so we don't get new users. */
        list_del(&chan->chan_list);
+       warning_time = jiffies;
+
+       /* Wait for existing users to close. */
+       while (chan->inuse) {
+               mutex_unlock(&virtio_9p_lock);
+               msleep(250);
+               if (time_after(jiffies, warning_time + 10 * HZ)) {
+                       dev_emerg(&vdev->dev,
+                                 "p9_virtio_remove: waiting for device in use.\n");
+                       warning_time = jiffies;
+               }
+               mutex_lock(&virtio_9p_lock);
+       }
+
        mutex_unlock(&virtio_9p_lock);
+
+       vdev->config->del_vqs(vdev);
+
        sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
        kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
        kfree(chan->tag);
index fb57ab6b24f9ef8feea780179ad2e8284a9e532f..02c24cf63c344a3b15bcf87369da7f847150fab3 100644 (file)
@@ -190,6 +190,8 @@ static int __init br_init(void)
 {
        int err;
 
+       BUILD_BUG_ON(sizeof(struct br_input_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb));
+
        err = stp_proto_register(&br_stp_proto);
        if (err < 0) {
                pr_err("bridge: can't register sap for STP\n");
index b087d278c6793f48f413082ff60fd8abbea49ff3..1849d96b3c91d82e20f85ca2579546857343d0f2 100644 (file)
@@ -563,6 +563,8 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
         */
        del_nbp(p);
 
+       dev_set_mtu(br->dev, br_min_mtu(br));
+
        spin_lock_bh(&br->lock);
        changed_addr = br_stp_recalculate_bridge_id(br);
        spin_unlock_bh(&br->lock);
index 769b185fefbd5f6bb6d4e68c1bcb0caeafa23d25..a6e2da0bc7184501ed5eb2bcef0e5169be2cf276 100644 (file)
@@ -281,7 +281,7 @@ static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
        int copylen;
 
        ret = -EOPNOTSUPP;
-       if (m->msg_flags&MSG_OOB)
+       if (flags & MSG_OOB)
                goto read_error;
 
        skb = skb_recv_datagram(sk, flags, 0 , &ret);
index 8bc7caa28e64ddc32d30f0054ac9dee708ba8f3f..434ba8557826ddf160fafd08a04949d546201692 100644 (file)
@@ -84,7 +84,7 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
        u16 tmp;
        u16 len;
        u16 hdrchks;
-       u16 pktchks;
+       int pktchks;
        struct cffrml *this;
        this = container_obj(layr);
 
index 1be0b521ac490143e60e3b2d5b02d7fd68c24087..f6c3b2137eeaacdc5cf38d1eac03e018d8f2d37b 100644 (file)
@@ -255,9 +255,9 @@ inline u16 cfpkt_getlen(struct cfpkt *pkt)
        return skb->len;
 }
 
-inline u16 cfpkt_iterate(struct cfpkt *pkt,
-                        u16 (*iter_func)(u16, void *, u16),
-                        u16 data)
+int cfpkt_iterate(struct cfpkt *pkt,
+                 u16 (*iter_func)(u16, void *, u16),
+                 u16 data)
 {
        /*
         * Don't care about the performance hit of linearizing,
index 66e08040ced7557ba19e7535815804bbcffca12a..32d710eaf1fc991b2ef4638fe8ccc95b84352ace 100644 (file)
@@ -259,6 +259,9 @@ int can_send(struct sk_buff *skb, int loop)
                goto inval_skb;
        }
 
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       skb_reset_mac_header(skb);
        skb_reset_network_header(skb);
        skb_reset_transport_header(skb);
 
index 3236b4167a32109b91b1eb28ae8bdf522c8db3f5..f7bd286a82807148bed32622e5de2f975450c877 100644 (file)
@@ -49,6 +49,13 @@ ssize_t get_compat_msghdr(struct msghdr *kmsg,
            __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
            __get_user(kmsg->msg_flags, &umsg->msg_flags))
                return -EFAULT;
+
+       if (!uaddr)
+               kmsg->msg_namelen = 0;
+
+       if (kmsg->msg_namelen < 0)
+               return -EINVAL;
+
        if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
        kmsg->msg_control = compat_ptr(tmp3);
@@ -711,24 +718,18 @@ static unsigned char nas[21] = {
 
 COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
 {
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
        return __sys_sendmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 }
 
 COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
                       unsigned int, vlen, unsigned int, flags)
 {
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
        return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                              flags | MSG_CMSG_COMPAT);
 }
 
 COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
 {
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
        return __sys_recvmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 }
 
@@ -751,9 +752,6 @@ COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
        int datagrams;
        struct timespec ktspec;
 
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
-
        if (timeout == NULL)
                return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                                      flags | MSG_CMSG_COMPAT, NULL);
index 8f9710c62e20d58bcdcec3d184ca6344fbe5a57c..962ee9d719641291853715f366717bf1626e115c 100644 (file)
@@ -946,7 +946,7 @@ bool dev_valid_name(const char *name)
                return false;
 
        while (*name) {
-               if (*name == '/' || isspace(*name))
+               if (*name == '/' || *name == ':' || isspace(*name))
                        return false;
                name++;
        }
index 91f74f3eb20475439214d9692f9b17c8124a9c3a..aa378ecef1860d0c1e255c001aef9528b8198d6f 100644 (file)
@@ -98,6 +98,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
        [NETIF_F_RXALL_BIT] =            "rx-all",
        [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
        [NETIF_F_BUSY_POLL_BIT] =        "busy-poll",
+       [NETIF_F_HW_SWITCH_OFFLOAD_BIT] = "hw-switch-offload",
 };
 
 static const char
index 0c08062d1796337f25b9dbc2cbce68d5e3194037..1e2f46a69d50196f71f1fb7ae97e7732c2a8a059 100644 (file)
@@ -32,6 +32,9 @@ gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size)
        return 0;
 
 nla_put_failure:
+       kfree(d->xstats);
+       d->xstats = NULL;
+       d->xstats_len = 0;
        spin_unlock_bh(d->lock);
        return -1;
 }
@@ -305,7 +308,9 @@ int
 gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
 {
        if (d->compat_xstats) {
-               d->xstats = st;
+               d->xstats = kmemdup(st, len, GFP_ATOMIC);
+               if (!d->xstats)
+                       goto err_out;
                d->xstats_len = len;
        }
 
@@ -313,6 +318,11 @@ gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
                return gnet_stats_copy(d, TCA_STATS_APP, st, len);
 
        return 0;
+
+err_out:
+       d->xstats_len = 0;
+       spin_unlock_bh(d->lock);
+       return -1;
 }
 EXPORT_SYMBOL(gnet_stats_copy_app);
 
@@ -345,6 +355,9 @@ gnet_stats_finish_copy(struct gnet_dump *d)
                        return -1;
        }
 
+       kfree(d->xstats);
+       d->xstats = NULL;
+       d->xstats_len = 0;
        spin_unlock_bh(d->lock);
        return 0;
 }
index b4899f5b7388e8f0c825a433a1f633d6b087a0f9..508155b283ddcc73a967a2bc8068e67cb8cada7d 100644 (file)
@@ -1134,6 +1134,9 @@ static ssize_t pktgen_if_write(struct file *file,
                        return len;
 
                i += len;
+               if ((value > 1) &&
+                   (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
+                       return -ENOTSUPP;
                pkt_dev->burst = value < 1 ? 1 : value;
                sprintf(pg_result, "OK: burst=%d", pkt_dev->burst);
                return count;
index ab293a3066b34bc4f6af71701f0c12b9ab6e5a34..ee0608bb3bc087212d12bac729677bf454053560 100644 (file)
@@ -1300,7 +1300,6 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        s_h = cb->args[0];
        s_idx = cb->args[1];
 
-       rcu_read_lock();
        cb->seq = net->dev_base_seq;
 
        /* A hack to preserve kernel<->userspace interface.
@@ -1322,7 +1321,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
                idx = 0;
                head = &net->dev_index_head[h];
-               hlist_for_each_entry_rcu(dev, head, index_hlist) {
+               hlist_for_each_entry(dev, head, index_hlist) {
                        if (idx < s_idx)
                                goto cont;
                        err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
@@ -1344,7 +1343,6 @@ cont:
                }
        }
 out:
-       rcu_read_unlock();
        cb->args[1] = idx;
        cb->args[0] = h;
 
@@ -2012,8 +2010,8 @@ replay:
        }
 
        if (1) {
-               struct nlattr *attr[ops ? ops->maxtype + 1 : 0];
-               struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 0];
+               struct nlattr *attr[ops ? ops->maxtype + 1 : 1];
+               struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 1];
                struct nlattr **data = NULL;
                struct nlattr **slave_data = NULL;
                struct net *dest_net, *link_net = NULL;
@@ -2122,6 +2120,10 @@ replay:
                if (IS_ERR(dest_net))
                        return PTR_ERR(dest_net);
 
+               err = -EPERM;
+               if (!netlink_ns_capable(skb, dest_net->user_ns, CAP_NET_ADMIN))
+                       goto out;
+
                if (tb[IFLA_LINK_NETNSID]) {
                        int id = nla_get_s32(tb[IFLA_LINK_NETNSID]);
 
@@ -2130,6 +2132,9 @@ replay:
                                err =  -EINVAL;
                                goto out;
                        }
+                       err = -EPERM;
+                       if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN))
+                               goto out;
                }
 
                dev = rtnl_create_link(link_net ? : dest_net, ifname,
@@ -2161,28 +2166,28 @@ replay:
                        }
                }
                err = rtnl_configure_link(dev, ifm);
-               if (err < 0) {
-                       if (ops->newlink) {
-                               LIST_HEAD(list_kill);
-
-                               ops->dellink(dev, &list_kill);
-                               unregister_netdevice_many(&list_kill);
-                       } else {
-                               unregister_netdevice(dev);
-                       }
-                       goto out;
-               }
-
+               if (err < 0)
+                       goto out_unregister;
                if (link_net) {
                        err = dev_change_net_namespace(dev, dest_net, ifname);
                        if (err < 0)
-                               unregister_netdevice(dev);
+                               goto out_unregister;
                }
 out:
                if (link_net)
                        put_net(link_net);
                put_net(dest_net);
                return err;
+out_unregister:
+               if (ops->newlink) {
+                       LIST_HEAD(list_kill);
+
+                       ops->dellink(dev, &list_kill);
+                       unregister_netdevice_many(&list_kill);
+               } else {
+                       unregister_netdevice(dev);
+               }
+               goto out;
        }
 }
 
index 88c613eab142962dc44f2075378fce0b94349e8e..8e4ac97c84775f15c786020ff87a2ef22a8dbac8 100644 (file)
@@ -3621,13 +3621,14 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
 {
        struct sk_buff_head *q = &sk->sk_error_queue;
        struct sk_buff *skb, *skb_next;
+       unsigned long flags;
        int err = 0;
 
-       spin_lock_bh(&q->lock);
+       spin_lock_irqsave(&q->lock, flags);
        skb = __skb_dequeue(q);
        if (skb && (skb_next = skb_peek(q)))
                err = SKB_EXT_ERR(skb_next)->ee.ee_errno;
-       spin_unlock_bh(&q->lock);
+       spin_unlock_irqrestore(&q->lock, flags);
 
        sk->sk_err = err;
        if (err)
@@ -3732,9 +3733,13 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb,
                     struct sock *sk, int tstype)
 {
        struct sk_buff *skb;
-       bool tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
+       bool tsonly;
+
+       if (!sk)
+               return;
 
-       if (!sk || !skb_may_tx_timestamp(sk, tsonly))
+       tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
+       if (!skb_may_tx_timestamp(sk, tsonly))
                return;
 
        if (tsonly)
@@ -4172,7 +4177,7 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
        skb->ignore_df = 0;
        skb_dst_drop(skb);
        skb->mark = 0;
-       skb->sender_cpu = 0;
+       skb_sender_cpu_clear(skb);
        skb_init_secmark(skb);
        secpath_reset(skb);
        nf_reset(skb);
index 93c8b20c91e496648f7f2e5c769c062ca2dd679d..78e89eb7eb705624d3ff63324f5002ae10b51145 100644 (file)
@@ -1655,6 +1655,10 @@ void sock_rfree(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_rfree);
 
+/*
+ * Buffer destructor for skbs that are not used directly in read or write
+ * path, e.g. for error handler skbs. Automatically called from kfree_skb.
+ */
 void sock_efree(struct sk_buff *skb)
 {
        sock_put(skb->sk);
index 433424804284cad8921a2efb6427a615b740ecc5..8ce351ffceb122568ae05587a0b1dc3544d476d7 100644 (file)
@@ -25,6 +25,8 @@
 static int zero = 0;
 static int one = 1;
 static int ushort_max = USHRT_MAX;
+static int min_sndbuf = SOCK_MIN_SNDBUF;
+static int min_rcvbuf = SOCK_MIN_RCVBUF;
 
 static int net_msg_warn;       /* Unused, but still a sysctl */
 
@@ -237,7 +239,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_sndbuf,
        },
        {
                .procname       = "rmem_max",
@@ -245,7 +247,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_rcvbuf,
        },
        {
                .procname       = "wmem_default",
@@ -253,7 +255,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_sndbuf,
        },
        {
                .procname       = "rmem_default",
@@ -261,7 +263,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_rcvbuf,
        },
        {
                .procname       = "dev_weight",
index 1d7c1256e8458d35e4a9f9daa392aba37672e1bf..3b81092771f8b7beb74349a84819046f7c080df1 100644 (file)
@@ -1062,7 +1062,7 @@ source_ok:
        if (decnet_debug_level & 16)
                printk(KERN_DEBUG
                       "dn_route_output_slow: initial checks complete."
-                      " dst=%o4x src=%04x oif=%d try_hard=%d\n",
+                      " dst=%04x src=%04x oif=%d try_hard=%d\n",
                       le16_to_cpu(fld.daddr), le16_to_cpu(fld.saddr),
                       fld.flowidn_oif, try_hard);
 
index a138d75751df2fb46219168c01fd1bf5cce24d43..44d27469ae55982d1895021b79ba76a85c1324a8 100644 (file)
@@ -359,8 +359,11 @@ static void hsr_dev_destroy(struct net_device *hsr_dev)
        struct hsr_port *port;
 
        hsr = netdev_priv(hsr_dev);
+
+       rtnl_lock();
        hsr_for_each_port(hsr, port)
                hsr_del_port(port);
+       rtnl_unlock();
 
        del_timer_sync(&hsr->prune_timer);
        del_timer_sync(&hsr->announce_timer);
index 779d28b65417a6e62b687d8f5ea36d6be285f417..cd37d0011b424824fd113ffd4da59f36c116996a 100644 (file)
@@ -36,6 +36,10 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
                        return NOTIFY_DONE;     /* Not an HSR device */
                hsr = netdev_priv(dev);
                port = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
+               if (port == NULL) {
+                       /* Resend of notification concerning removed device? */
+                       return NOTIFY_DONE;
+               }
        } else {
                hsr = port->hsr;
        }
index a348dcbcd683e6858248bf17ee73e7e24d08b4ea..7d37366cc695554ae243f940869b46d26f598b65 100644 (file)
@@ -181,8 +181,10 @@ void hsr_del_port(struct hsr_port *port)
        list_del_rcu(&port->port_list);
 
        if (port != master) {
-               netdev_update_features(master->dev);
-               dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
+               if (master != NULL) {
+                       netdev_update_features(master->dev);
+                       dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
+               }
                netdev_rx_handler_unregister(port->dev);
                dev_set_promiscuity(port->dev, -1);
        }
@@ -192,5 +194,7 @@ void hsr_del_port(struct hsr_port *port)
         */
 
        synchronize_rcu();
-       dev_put(port->dev);
+
+       if (port != master)
+               dev_put(port->dev);
 }
index 14d02ea905b6bea37240f88054f0cd42db73c4c2..3e44b9b0b78ece392a1f1b0763b5445cadfb2557 100644 (file)
@@ -268,6 +268,7 @@ static int inet_csk_wait_for_connect(struct sock *sk, long timeo)
                release_sock(sk);
                if (reqsk_queue_empty(&icsk->icsk_accept_queue))
                        timeo = schedule_timeout(timeo);
+               sched_annotate_sleep();
                lock_sock(sk);
                err = 0;
                if (!reqsk_queue_empty(&icsk->icsk_accept_queue))
index 81751f12645f6224a7f076dea1da2fc0d638819a..592aff37366bb932c0aeb2bad944b5470374ec21 100644 (file)
@@ -71,6 +71,20 @@ static inline void inet_diag_unlock_handler(
        mutex_unlock(&inet_diag_table_mutex);
 }
 
+static size_t inet_sk_attr_size(void)
+{
+       return    nla_total_size(sizeof(struct tcp_info))
+               + nla_total_size(1) /* INET_DIAG_SHUTDOWN */
+               + nla_total_size(1) /* INET_DIAG_TOS */
+               + nla_total_size(1) /* INET_DIAG_TCLASS */
+               + nla_total_size(sizeof(struct inet_diag_meminfo))
+               + nla_total_size(sizeof(struct inet_diag_msg))
+               + nla_total_size(SK_MEMINFO_VARS * sizeof(u32))
+               + nla_total_size(TCP_CA_NAME_MAX)
+               + nla_total_size(sizeof(struct tcpvegas_info))
+               + 64;
+}
+
 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
                              struct sk_buff *skb, struct inet_diag_req_v2 *req,
                              struct user_namespace *user_ns,                   
@@ -326,9 +340,7 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s
        if (err)
                goto out;
 
-       rep = nlmsg_new(sizeof(struct inet_diag_msg) +
-                       sizeof(struct inet_diag_meminfo) +
-                       sizeof(struct tcp_info) + 64, GFP_KERNEL);
+       rep = nlmsg_new(inet_sk_attr_size(), GFP_KERNEL);
        if (!rep) {
                err = -ENOMEM;
                goto out;
index 787b3c294ce672244ce08c5426c03bbd1f71c0f3..d9bc28ac5d1b97340e79aae1eefcbac3f463251a 100644 (file)
@@ -67,6 +67,7 @@ static int ip_forward_finish(struct sk_buff *skb)
        if (unlikely(opt->optlen))
                ip_forward_options(skb);
 
+       skb_sender_cpu_clear(skb);
        return dst_output(skb);
 }
 
index e5b6d0ddcb5808f662ca0b1fd5863d63e6b54b83..145a50c4d56630a5fc97283d85c3fa29e10ab476 100644 (file)
@@ -659,27 +659,30 @@ EXPORT_SYMBOL(ip_defrag);
 struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user)
 {
        struct iphdr iph;
+       int netoff;
        u32 len;
 
        if (skb->protocol != htons(ETH_P_IP))
                return skb;
 
-       if (!skb_copy_bits(skb, 0, &iph, sizeof(iph)))
+       netoff = skb_network_offset(skb);
+
+       if (skb_copy_bits(skb, netoff, &iph, sizeof(iph)) < 0)
                return skb;
 
        if (iph.ihl < 5 || iph.version != 4)
                return skb;
 
        len = ntohs(iph.tot_len);
-       if (skb->len < len || len < (iph.ihl * 4))
+       if (skb->len < netoff + len || len < (iph.ihl * 4))
                return skb;
 
        if (ip_is_fragment(&iph)) {
                skb = skb_share_check(skb, GFP_ATOMIC);
                if (skb) {
-                       if (!pskb_may_pull(skb, iph.ihl*4))
+                       if (!pskb_may_pull(skb, netoff + iph.ihl * 4))
                                return skb;
-                       if (pskb_trim_rcsum(skb, len))
+                       if (pskb_trim_rcsum(skb, netoff + len))
                                return skb;
                        memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
                        if (ip_defrag(skb, user))
index d68199d9b2b01faf7a5272862b7cd8658f08c8ae..a7aea2048a0d7a624ceb79923d25e9750ec6fa9a 100644 (file)
@@ -888,7 +888,8 @@ static int __ip_append_data(struct sock *sk,
        cork->length += length;
        if (((length > mtu) || (skb && skb_is_gso(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
-           (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len) {
+           (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
+           (sk->sk_type == SOCK_DGRAM)) {
                err = ip_ufo_append_data(sk, queue, getfrag, from, length,
                                         hh_len, fragheaderlen, transhdrlen,
                                         maxfraglen, flags);
index 31d8c71986b40e28e5c84f5e62d474a639d3bf91..5cd99271d3a6a07c17a915fddde7a5a0c8a86618 100644 (file)
@@ -432,17 +432,32 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf
                kfree_skb(skb);
 }
 
-static bool ipv4_pktinfo_prepare_errqueue(const struct sock *sk,
-                                         const struct sk_buff *skb,
-                                         int ee_origin)
+/* IPv4 supports cmsg on all imcp errors and some timestamps
+ *
+ * Timestamp code paths do not initialize the fields expected by cmsg:
+ * the PKTINFO fields in skb->cb[]. Fill those in here.
+ */
+static bool ipv4_datagram_support_cmsg(const struct sock *sk,
+                                      struct sk_buff *skb,
+                                      int ee_origin)
 {
-       struct in_pktinfo *info = PKTINFO_SKB_CB(skb);
+       struct in_pktinfo *info;
+
+       if (ee_origin == SO_EE_ORIGIN_ICMP)
+               return true;
 
-       if ((ee_origin != SO_EE_ORIGIN_TIMESTAMPING) ||
-           (!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) ||
+       if (ee_origin == SO_EE_ORIGIN_LOCAL)
+               return false;
+
+       /* Support IP_PKTINFO on tstamp packets if requested, to correlate
+        * timestamp with egress dev. Not possible for packets without dev
+        * or without payload (SOF_TIMESTAMPING_OPT_TSONLY).
+        */
+       if ((!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) ||
            (!skb->dev))
                return false;
 
+       info = PKTINFO_SKB_CB(skb);
        info->ipi_spec_dst.s_addr = ip_hdr(skb)->saddr;
        info->ipi_ifindex = skb->dev->ifindex;
        return true;
@@ -483,7 +498,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 
        serr = SKB_EXT_ERR(skb);
 
-       if (sin && skb->len) {
+       if (sin && serr->port) {
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
                                                   serr->addr_offset);
@@ -496,9 +511,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        sin = &errhdr.offender;
        memset(sin, 0, sizeof(*sin));
 
-       if (skb->len &&
-           (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
-            ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin))) {
+       if (ipv4_datagram_support_cmsg(sk, skb, serr->ee.ee_origin)) {
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
                if (inet_sk(sk)->cmsg_flags)
index 99e810f84671bbdb80e33c6915cc7be49ba0f1bb..cf5e82f39d3b87d7f8163320bffbc26af38d6f98 100644 (file)
@@ -272,9 +272,9 @@ static void trace_packet(const struct sk_buff *skb,
                    &chainname, &comment, &rulenum) != 0)
                        break;
 
-       nf_log_packet(net, AF_INET, hook, skb, in, out, &trace_loginfo,
-                     "TRACE: %s:%s:%s:%u ",
-                     tablename, chainname, comment, rulenum);
+       nf_log_trace(net, AF_INET, hook, skb, in, out, &trace_loginfo,
+                    "TRACE: %s:%s:%s:%u ",
+                    tablename, chainname, comment, rulenum);
 }
 #endif
 
index e9f66e1cda507cf2d5cb532958d23a89beeccaba..208d5439e59b2e8c3ccb2da46c292ad4f75b3784 100644 (file)
@@ -259,6 +259,9 @@ int ping_init_sock(struct sock *sk)
        kgid_t low, high;
        int ret = 0;
 
+       if (sk->sk_family == AF_INET6)
+               sk->sk_ipv6only = 1;
+
        inet_get_ping_group_range_net(net, &low, &high);
        if (gid_lte(low, group) && gid_lte(group, high))
                return 0;
@@ -305,6 +308,11 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
                if (addr_len < sizeof(*addr))
                        return -EINVAL;
 
+               if (addr->sin_family != AF_INET &&
+                   !(addr->sin_family == AF_UNSPEC &&
+                     addr->sin_addr.s_addr == htonl(INADDR_ANY)))
+                       return -EAFNOSUPPORT;
+
                pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)\n",
                         sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port));
 
@@ -330,7 +338,7 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
                        return -EINVAL;
 
                if (addr->sin6_family != AF_INET6)
-                       return -EINVAL;
+                       return -EAFNOSUPPORT;
 
                pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n",
                         sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port));
@@ -716,7 +724,7 @@ static int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
                if (msg->msg_namelen < sizeof(*usin))
                        return -EINVAL;
                if (usin->sin_family != AF_INET)
-                       return -EINVAL;
+                       return -EAFNOSUPPORT;
                daddr = usin->sin_addr.s_addr;
                /* no remote port */
        } else {
index 9d72a0fcd9284425e088cef6e1b8c14e95950ca4..995a2259bcfc80894caec08fe2e7ccd62311e227 100644 (file)
@@ -835,17 +835,13 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
                                       int large_allowed)
 {
        struct tcp_sock *tp = tcp_sk(sk);
-       u32 new_size_goal, size_goal, hlen;
+       u32 new_size_goal, size_goal;
 
        if (!large_allowed || !sk_can_gso(sk))
                return mss_now;
 
-       /* Maybe we should/could use sk->sk_prot->max_header here ? */
-       hlen = inet_csk(sk)->icsk_af_ops->net_header_len +
-              inet_csk(sk)->icsk_ext_hdr_len +
-              tp->tcp_header_len;
-
-       new_size_goal = sk->sk_gso_max_size - 1 - hlen;
+       /* Note : tcp_tso_autosize() will eventually split this later */
+       new_size_goal = sk->sk_gso_max_size - 1 - MAX_TCP_HEADER;
        new_size_goal = tcp_bound_to_half_wnd(tp, new_size_goal);
 
        /* We try hard to avoid divides here */
index d694088214cd87fa50e413730402499610c546e6..62856e185a935e44deb26de59ff94c8bf7500579 100644 (file)
@@ -378,6 +378,12 @@ EXPORT_SYMBOL_GPL(tcp_slow_start);
  */
 void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked)
 {
+       /* If credits accumulated at a higher w, apply them gently now. */
+       if (tp->snd_cwnd_cnt >= w) {
+               tp->snd_cwnd_cnt = 0;
+               tp->snd_cwnd++;
+       }
+
        tp->snd_cwnd_cnt += acked;
        if (tp->snd_cwnd_cnt >= w) {
                u32 delta = tp->snd_cwnd_cnt / w;
index 4b276d1ed9807057986bd3b050e2e901bf1afec0..06d3d665a9fd1bfda5688907a284de83697273f6 100644 (file)
@@ -306,8 +306,10 @@ tcp_friendliness:
                }
        }
 
-       if (ca->cnt == 0)                       /* cannot be zero */
-               ca->cnt = 1;
+       /* The maximum rate of cwnd increase CUBIC allows is 1 packet per
+        * 2 packets ACKed, meaning cwnd grows at 1.5x per RTT.
+        */
+       ca->cnt = max(ca->cnt, 2U);
 }
 
 static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
index 8fdd27b173061def484663beeace691a8bfa2365..fb4cf8b8e121acd4bffcf2fdfbd7e03c76bad7cc 100644 (file)
@@ -4770,7 +4770,7 @@ static bool tcp_should_expand_sndbuf(const struct sock *sk)
                return false;
 
        /* If we filled the congestion window, do not expand.  */
-       if (tp->packets_out >= tp->snd_cwnd)
+       if (tcp_packets_in_flight(tp) >= tp->snd_cwnd)
                return false;
 
        return true;
index a2a796c5536b032264e2a71f596f673e8307f25c..1db253e36045ac038d7449a06d312275535a8014 100644 (file)
@@ -2773,15 +2773,11 @@ void tcp_send_fin(struct sock *sk)
        } else {
                /* Socket is locked, keep trying until memory is available. */
                for (;;) {
-                       skb = alloc_skb_fclone(MAX_TCP_HEADER,
-                                              sk->sk_allocation);
+                       skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation);
                        if (skb)
                                break;
                        yield();
                }
-
-               /* Reserve space for headers and prepare control bits. */
-               skb_reserve(skb, MAX_TCP_HEADER);
                /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
                tcp_init_nondata_skb(skb, tp->write_seq,
                                     TCPHDR_ACK | TCPHDR_FIN);
index d5f6bd9a210ab93ed27177ecffc9499259dbe999..dab73813cb9208dafaae1277e281c2255601a771 100644 (file)
@@ -63,6 +63,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
                return err;
 
        IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
+       skb->protocol = htons(ETH_P_IP);
 
        return x->outer_mode->output2(x, skb);
 }
@@ -71,7 +72,6 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
 int xfrm4_output_finish(struct sk_buff *skb)
 {
        memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-       skb->protocol = htons(ETH_P_IP);
 
 #ifdef CONFIG_NETFILTER
        IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
index 98e4a63d72bb435e1ac1ae7cf2767072eed6db92..b6030025f41197efbcdfd1d8c013e469413550b5 100644 (file)
@@ -4903,6 +4903,21 @@ int addrconf_sysctl_forward(struct ctl_table *ctl, int write,
        return ret;
 }
 
+static
+int addrconf_sysctl_mtu(struct ctl_table *ctl, int write,
+                       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct inet6_dev *idev = ctl->extra1;
+       int min_mtu = IPV6_MIN_MTU;
+       struct ctl_table lctl;
+
+       lctl = *ctl;
+       lctl.extra1 = &min_mtu;
+       lctl.extra2 = idev ? &idev->dev->mtu : NULL;
+
+       return proc_dointvec_minmax(&lctl, write, buffer, lenp, ppos);
+}
+
 static void dev_disable_change(struct inet6_dev *idev)
 {
        struct netdev_notifier_info info;
@@ -5054,7 +5069,7 @@ static struct addrconf_sysctl_table
                        .data           = &ipv6_devconf.mtu6,
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .proc_handler   = addrconf_sysctl_mtu,
                },
                {
                        .procname       = "accept_ra",
index c215be70cac08af78953ea860c5d67cf9d3fa642..ace8daca5c8361ad37073a4eeb0f8d55c622d807 100644 (file)
@@ -325,14 +325,34 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)
        kfree_skb(skb);
 }
 
-static void ip6_datagram_prepare_pktinfo_errqueue(struct sk_buff *skb)
+/* IPv6 supports cmsg on all origins aside from SO_EE_ORIGIN_LOCAL.
+ *
+ * At one point, excluding local errors was a quick test to identify icmp/icmp6
+ * errors. This is no longer true, but the test remained, so the v6 stack,
+ * unlike v4, also honors cmsg requests on all wifi and timestamp errors.
+ *
+ * Timestamp code paths do not initialize the fields expected by cmsg:
+ * the PKTINFO fields in skb->cb[]. Fill those in here.
+ */
+static bool ip6_datagram_support_cmsg(struct sk_buff *skb,
+                                     struct sock_exterr_skb *serr)
 {
-       int ifindex = skb->dev ? skb->dev->ifindex : -1;
+       if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
+           serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6)
+               return true;
+
+       if (serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL)
+               return false;
+
+       if (!skb->dev)
+               return false;
 
        if (skb->protocol == htons(ETH_P_IPV6))
-               IP6CB(skb)->iif = ifindex;
+               IP6CB(skb)->iif = skb->dev->ifindex;
        else
-               PKTINFO_SKB_CB(skb)->ipi_ifindex = ifindex;
+               PKTINFO_SKB_CB(skb)->ipi_ifindex = skb->dev->ifindex;
+
+       return true;
 }
 
 /*
@@ -369,7 +389,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 
        serr = SKB_EXT_ERR(skb);
 
-       if (sin && skb->len) {
+       if (sin && serr->port) {
                const unsigned char *nh = skb_network_header(skb);
                sin->sin6_family = AF_INET6;
                sin->sin6_flowinfo = 0;
@@ -394,14 +414,11 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
        sin = &errhdr.offender;
        memset(sin, 0, sizeof(*sin));
-       if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL && skb->len) {
+
+       if (ip6_datagram_support_cmsg(skb, serr)) {
                sin->sin6_family = AF_INET6;
-               if (np->rxopt.all) {
-                       if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP &&
-                           serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6)
-                               ip6_datagram_prepare_pktinfo_errqueue(skb);
+               if (np->rxopt.all)
                        ip6_datagram_recv_common_ctl(sk, msg, skb);
-               }
                if (skb->protocol == htons(ETH_P_IPV6)) {
                        sin->sin6_addr = ipv6_hdr(skb)->saddr;
                        if (np->rxopt.all)
index b4d5e1d97c1b2576fc02a15b7a05a773197bb8e0..27ca79682efbf681a0ab6073f50f8fa73214028e 100644 (file)
@@ -104,6 +104,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
                                goto again;
                        flp6->saddr = saddr;
                }
+               err = rt->dst.error;
                goto out;
        }
 again:
index 7deebf102cbafc276f45e4eaffdd8efdb658d842..7e80b61b51ff474db6c188218b70f12709209256 100644 (file)
@@ -318,6 +318,7 @@ static int ip6_forward_proxy_check(struct sk_buff *skb)
 
 static inline int ip6_forward_finish(struct sk_buff *skb)
 {
+       skb_sender_cpu_clear(skb);
        return dst_output(skb);
 }
 
@@ -1298,7 +1299,8 @@ emsgsize:
        if (((length > mtu) ||
             (skb && skb_is_gso(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
-           (rt->dst.dev->features & NETIF_F_UFO)) {
+           (rt->dst.dev->features & NETIF_F_UFO) &&
+           (sk->sk_type == SOCK_DGRAM)) {
                err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
                                          hh_len, fragheaderlen,
                                          transhdrlen, mtu, flags, rt);
index 266a264ec21273147b32d75ac7bde55afdd1b4cf..ddd94eca19b3986e4fc0b1ff684eee401032815e 100644 (file)
@@ -314,7 +314,7 @@ out:
  *   Create tunnel matching given parameters.
  *
  * Return:
- *   created tunnel or NULL
+ *   created tunnel or error pointer
  **/
 
 static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
@@ -322,7 +322,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
        struct net_device *dev;
        struct ip6_tnl *t;
        char name[IFNAMSIZ];
-       int err;
+       int err = -ENOMEM;
 
        if (p->name[0])
                strlcpy(name, p->name, IFNAMSIZ);
@@ -348,7 +348,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
 failed_free:
        ip6_dev_free(dev);
 failed:
-       return NULL;
+       return ERR_PTR(err);
 }
 
 /**
@@ -362,7 +362,7 @@ failed:
  *   tunnel device is created and registered for use.
  *
  * Return:
- *   matching tunnel or NULL
+ *   matching tunnel or error pointer
  **/
 
 static struct ip6_tnl *ip6_tnl_locate(struct net *net,
@@ -380,13 +380,13 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net,
                if (ipv6_addr_equal(local, &t->parms.laddr) &&
                    ipv6_addr_equal(remote, &t->parms.raddr)) {
                        if (create)
-                               return NULL;
+                               return ERR_PTR(-EEXIST);
 
                        return t;
                }
        }
        if (!create)
-               return NULL;
+               return ERR_PTR(-ENODEV);
        return ip6_tnl_create(net, p);
 }
 
@@ -1420,7 +1420,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        }
                        ip6_tnl_parm_from_user(&p1, &p);
                        t = ip6_tnl_locate(net, &p1, 0);
-                       if (t == NULL)
+                       if (IS_ERR(t))
                                t = netdev_priv(dev);
                } else {
                        memset(&p, 0, sizeof(p));
@@ -1445,7 +1445,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                ip6_tnl_parm_from_user(&p1, &p);
                t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
                if (cmd == SIOCCHGTUNNEL) {
-                       if (t != NULL) {
+                       if (!IS_ERR(t)) {
                                if (t->dev != dev) {
                                        err = -EEXIST;
                                        break;
@@ -1457,14 +1457,15 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        else
                                err = ip6_tnl_update(t, &p1);
                }
-               if (t) {
+               if (!IS_ERR(t)) {
                        err = 0;
                        ip6_tnl_parm_to_user(&p, &t->parms);
                        if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
                                err = -EFAULT;
 
-               } else
-                       err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+               } else {
+                       err = PTR_ERR(t);
+               }
                break;
        case SIOCDELTUNNEL:
                err = -EPERM;
@@ -1478,7 +1479,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        err = -ENOENT;
                        ip6_tnl_parm_from_user(&p1, &p);
                        t = ip6_tnl_locate(net, &p1, 0);
-                       if (t == NULL)
+                       if (IS_ERR(t))
                                break;
                        err = -EPERM;
                        if (t->dev == ip6n->fb_tnl_dev)
@@ -1672,12 +1673,13 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
                           struct nlattr *tb[], struct nlattr *data[])
 {
        struct net *net = dev_net(dev);
-       struct ip6_tnl *nt;
+       struct ip6_tnl *nt, *t;
 
        nt = netdev_priv(dev);
        ip6_tnl_netlink_parms(data, &nt->parms);
 
-       if (ip6_tnl_locate(net, &nt->parms, 0))
+       t = ip6_tnl_locate(net, &nt->parms, 0);
+       if (!IS_ERR(t))
                return -EEXIST;
 
        return ip6_tnl_create2(dev);
@@ -1697,8 +1699,7 @@ static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
        ip6_tnl_netlink_parms(data, &p);
 
        t = ip6_tnl_locate(net, &p, 0);
-
-       if (t) {
+       if (!IS_ERR(t)) {
                if (t->dev != dev)
                        return -EEXIST;
        } else
index e080fbbbc0e5ce8d4d71014eed149e6b34250b62..bb00c6f2a8855fb72dcc6a1bc5b496e8216d683f 100644 (file)
@@ -298,9 +298,9 @@ static void trace_packet(const struct sk_buff *skb,
                    &chainname, &comment, &rulenum) != 0)
                        break;
 
-       nf_log_packet(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
-                     "TRACE: %s:%s:%s:%u ",
-                     tablename, chainname, comment, rulenum);
+       nf_log_trace(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
+                    "TRACE: %s:%s:%s:%u ",
+                    tablename, chainname, comment, rulenum);
 }
 #endif
 
index bd46f736f61d74bcb75a4dabef264154f55a9fb0..a2dfff6ff227e09607d1d267265e7635d64a2030 100644 (file)
@@ -102,9 +102,10 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        if (msg->msg_name) {
                DECLARE_SOCKADDR(struct sockaddr_in6 *, u, msg->msg_name);
-               if (msg->msg_namelen < sizeof(struct sockaddr_in6) ||
-                   u->sin6_family != AF_INET6) {
+               if (msg->msg_namelen < sizeof(*u))
                        return -EINVAL;
+               if (u->sin6_family != AF_INET6) {
+                       return -EAFNOSUPPORT;
                }
                if (sk->sk_bound_dev_if &&
                    sk->sk_bound_dev_if != u->sin6_scope_id) {
index ab889bb16b3cb077d26ddd2837b8b2eaaf1de666..be2c0ba82c8525ca466468ae45b05df5b35f85b6 100644 (file)
@@ -112,11 +112,9 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
                fptr->nexthdr = nexthdr;
                fptr->reserved = 0;
-               if (skb_shinfo(skb)->ip6_frag_id)
-                       fptr->identification = skb_shinfo(skb)->ip6_frag_id;
-               else
-                       ipv6_select_ident(fptr,
-                                         (struct rt6_info *)skb_dst(skb));
+               if (!skb_shinfo(skb)->ip6_frag_id)
+                       ipv6_proxy_select_ident(skb);
+               fptr->identification = skb_shinfo(skb)->ip6_frag_id;
 
                /* Fragment the skb. ipv6 header and the remaining fields of the
                 * fragment header are updated in ipv6_gso_segment()
index ca3f29b98ae5d76b7e69c38f617362a90fd9fd04..010f8bd2d577f9767d7d44182b246e62f4a118f6 100644 (file)
@@ -114,6 +114,7 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
                return err;
 
        skb->ignore_df = 1;
+       skb->protocol = htons(ETH_P_IPV6);
 
        return x->outer_mode->output2(x, skb);
 }
@@ -122,7 +123,6 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
 int xfrm6_output_finish(struct sk_buff *skb)
 {
        memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
-       skb->protocol = htons(ETH_P_IPV6);
 
 #ifdef CONFIG_NETFILTER
        IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
index 48bf5a06847bd59db7834758b22aa9208d727940..8d2d01b4800a197eaaa64fb184f56c58920ad462 100644 (file)
@@ -200,6 +200,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
 
 #if IS_ENABLED(CONFIG_IPV6_MIP6)
                case IPPROTO_MH:
+                       offset += ipv6_optlen(exthdr);
                        if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
                                struct ip6_mh *mh;
 
index 40695b9751c10b41e7fd310fa5d15bcef4629549..683346d2d633b4b2ac839e975e2c21d687242075 100644 (file)
@@ -798,7 +798,9 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
        orig_jiffies = jiffies;
 
        /* Set poll time to 200 ms */
-       poll_time = IRDA_MIN(timeout, msecs_to_jiffies(200));
+       poll_time = msecs_to_jiffies(200);
+       if (timeout)
+               poll_time = min_t(unsigned long, timeout, poll_time);
 
        spin_lock_irqsave(&self->spinlock, flags);
        while (self->tx_skb && self->tx_skb->len) {
@@ -811,7 +813,7 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
                        break;
        }
        spin_unlock_irqrestore(&self->spinlock, flags);
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
 }
 
 /*
index 3c83a1e5ab0394f0eaa04b4ba5a813d118c17434..1215693fdd22897b5217b878763d56d087a25372 100644 (file)
@@ -305,7 +305,7 @@ irnet_ctrl_read(irnet_socket *      ap,
 
   /* Put ourselves on the wait queue to be woken up */
   add_wait_queue(&irnet_events.rwait, &wait);
-  current->state = TASK_INTERRUPTIBLE;
+  set_current_state(TASK_INTERRUPTIBLE);
   for(;;)
     {
       /* If there is unread events */
@@ -321,7 +321,7 @@ irnet_ctrl_read(irnet_socket *      ap,
       /* Yield and wait to be woken up */
       schedule();
     }
-  current->state = TASK_RUNNING;
+  __set_current_state(TASK_RUNNING);
   remove_wait_queue(&irnet_events.rwait, &wait);
 
   /* Did we got it ? */
index ff0d2db09df9db467a5831606971e02f2fe6d410..5bcd4e5589d3294602c4abdeff778497afbc8de1 100644 (file)
@@ -1508,6 +1508,8 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
        if (ieee80211_chanctx_refcount(local, ctx) == 0)
                ieee80211_free_chanctx(local, ctx);
 
+       sdata->radar_required = false;
+
        /* Unreserving may ready an in-place reservation. */
        if (use_reserved_switch)
                ieee80211_vif_use_reserved_switch(local);
@@ -1566,6 +1568,9 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
        ieee80211_recalc_smps_chanctx(local, ctx);
        ieee80211_recalc_radar_chanctx(local, ctx);
  out:
+       if (ret)
+               sdata->radar_required = false;
+
        mutex_unlock(&local->chanctx_mtx);
        return ret;
 }
index 3afe36824703f49dcfe374e103b6372a9851b8aa..8d53d65bd2abc2d993ae5dbc7df37b707fd9ec13 100644 (file)
@@ -58,13 +58,24 @@ struct ieee80211_local;
 #define IEEE80211_UNSET_POWER_LEVEL    INT_MIN
 
 /*
- * Some APs experience problems when working with U-APSD. Decrease the
- * probability of that happening by using legacy mode for all ACs but VO.
- * The AP that caused us trouble was a Cisco 4410N. It ignores our
- * setting, and always treats non-VO ACs as legacy.
+ * Some APs experience problems when working with U-APSD. Decreasing the
+ * probability of that happening by using legacy mode for all ACs but VO isn't
+ * enough.
+ *
+ * Cisco 4410N originally forced us to enable VO by default only because it
+ * treated non-VO ACs as legacy.
+ *
+ * However some APs (notably Netgear R7000) silently reclassify packets to
+ * different ACs. Since u-APSD ACs require trigger frames for frame retrieval
+ * clients would never see some frames (e.g. ARP responses) or would fetch them
+ * accidentally after a long time.
+ *
+ * It makes little sense to enable u-APSD queues by default because it needs
+ * userspace applications to be aware of it to actually take advantage of the
+ * possible additional powersavings. Implicitly depending on driver autotrigger
+ * frame support doesn't make much sense.
  */
-#define IEEE80211_DEFAULT_UAPSD_QUEUES \
-       IEEE80211_WMM_IE_STA_QOSINFO_AC_VO
+#define IEEE80211_DEFAULT_UAPSD_QUEUES 0
 
 #define IEEE80211_DEFAULT_MAX_SP_LEN           \
        IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
@@ -453,6 +464,7 @@ struct ieee80211_if_managed {
        unsigned int flags;
 
        bool csa_waiting_bcn;
+       bool csa_ignored_same_chan;
 
        bool beacon_crc_valid;
        u32 beacon_crc;
index 10ac6324c1d014c708749748ce89ef31055561cf..142f66aece18a8789205fc12b0e1d7c7816d0863 100644 (file)
@@ -1150,6 +1150,17 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
+       if (cfg80211_chandef_identical(&csa_ie.chandef,
+                                      &sdata->vif.bss_conf.chandef)) {
+               if (ifmgd->csa_ignored_same_chan)
+                       return;
+               sdata_info(sdata,
+                          "AP %pM tries to chanswitch to same channel, ignore\n",
+                          ifmgd->associated->bssid);
+               ifmgd->csa_ignored_same_chan = true;
+               return;
+       }
+
        mutex_lock(&local->mtx);
        mutex_lock(&local->chanctx_mtx);
        conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
@@ -1210,6 +1221,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        sdata->vif.csa_active = true;
        sdata->csa_chandef = csa_ie.chandef;
        sdata->csa_block_tx = csa_ie.mode;
+       ifmgd->csa_ignored_same_chan = false;
 
        if (sdata->csa_block_tx)
                ieee80211_stop_vif_queues(local, sdata,
@@ -2090,6 +2102,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        sdata->vif.csa_active = false;
        ifmgd->csa_waiting_bcn = false;
+       ifmgd->csa_ignored_same_chan = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -3204,7 +3217,8 @@ static const u64 care_about_ies =
        (1ULL << WLAN_EID_CHANNEL_SWITCH) |
        (1ULL << WLAN_EID_PWR_CONSTRAINT) |
        (1ULL << WLAN_EID_HT_CAPABILITY) |
-       (1ULL << WLAN_EID_HT_OPERATION);
+       (1ULL << WLAN_EID_HT_OPERATION) |
+       (1ULL << WLAN_EID_EXT_CHANSWITCH_ANN);
 
 static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_mgmt *mgmt, size_t len,
index 7c86a002df95fee46be8e7dfdb0d691fff0e9e7f..ef6e8a6c4253c72f6f2398b733e8c427f5b59953 100644 (file)
@@ -373,7 +373,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                rate++;
                mi->sample_deferred++;
        } else {
-               if (!msr->sample_limit != 0)
+               if (!msr->sample_limit)
                        return;
 
                mi->sample_packets++;
index 1101563357eae365f1e1a1df926ecf36fdc0570b..944bdc04e913d2f599b6c5845ee2549abba20a1c 100644 (file)
@@ -2214,6 +2214,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        hdr = (struct ieee80211_hdr *) skb->data;
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
 
+       if (ieee80211_drop_unencrypted(rx, hdr->frame_control))
+               return RX_DROP_MONITOR;
+
        /* frame is in RMC, don't forward */
        if (ieee80211_is_data(hdr->frame_control) &&
            is_multicast_ether_addr(hdr->addr1) &&
index 88a18ffe2975520edbcc80733bc1bbc9b2655f11..07bd8db00af84b820139c644da95eaf29e474b5f 100644 (file)
@@ -566,6 +566,7 @@ ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
                if (tx->sdata->control_port_no_encrypt)
                        info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
                info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
+               info->flags |= IEEE80211_TX_CTL_USE_MINRATE;
        }
 
        return TX_CONTINUE;
index 8428f4a954795657a32a24f77a0f9c9ae6591b7e..747bdcf72e92788574ec3e2e635b5e6b96cb75f0 100644 (file)
@@ -3178,7 +3178,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
                wdev_iter = &sdata_iter->wdev;
 
                if (sdata_iter == sdata ||
-                   rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL ||
+                   !ieee80211_sdata_running(sdata_iter) ||
                    local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
                        continue;
 
index e55759056361c47ed1fcfa5c656541ba39bfd260..ed99448671c3003374fc947bee6e91ab0f0d3fce 100644 (file)
@@ -3402,7 +3402,7 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
                if (udest.af == 0)
                        udest.af = svc->af;
 
-               if (udest.af != svc->af) {
+               if (udest.af != svc->af && cmd != IPVS_CMD_DEL_DEST) {
                        /* The synchronization protocol is incompatible
                         * with mixed family services
                         */
index c47ffd7a0a709cb73834c84652f251960f25db79..d93ceeb3ef04822427004ef0a70549f389d17354 100644 (file)
@@ -896,6 +896,8 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param,
                        IP_VS_DBG(2, "BACKUP, add new conn. failed\n");
                        return;
                }
+               if (!(flags & IP_VS_CONN_F_TEMPLATE))
+                       kfree(param->pe_data);
        }
 
        if (opt)
@@ -1169,6 +1171,7 @@ static inline int ip_vs_proc_sync_conn(struct net *net, __u8 *p, __u8 *msg_end)
                                (opt_flags & IPVS_OPT_F_SEQ_DATA ? &opt : NULL)
                                );
 #endif
+       ip_vs_pe_put(param.pe);
        return 0;
        /* Error exit */
 out:
index 0d8448f19dfe982f64879d9dc55ba7d746696196..675d12c69e325c70e46ca5e5522fb5f8c77b7d8b 100644 (file)
@@ -212,6 +212,30 @@ void nf_log_packet(struct net *net,
 }
 EXPORT_SYMBOL(nf_log_packet);
 
+void nf_log_trace(struct net *net,
+                 u_int8_t pf,
+                 unsigned int hooknum,
+                 const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct nf_loginfo *loginfo, const char *fmt, ...)
+{
+       va_list args;
+       char prefix[NF_LOG_PREFIXLEN];
+       const struct nf_logger *logger;
+
+       rcu_read_lock();
+       logger = rcu_dereference(net->nf.nf_loggers[pf]);
+       if (logger) {
+               va_start(args, fmt);
+               vsnprintf(prefix, sizeof(prefix), fmt, args);
+               va_end(args);
+               logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
+       }
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(nf_log_trace);
+
 #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
 
 struct nf_log_buf {
index 199fd0f27b0e128cfb8674ca331c2dae240e1b1c..ac1a9528dbf2e4af0d33fec5667369d23ed179e4 100644 (file)
@@ -227,7 +227,7 @@ nft_rule_deactivate_next(struct net *net, struct nft_rule *rule)
 
 static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
 {
-       rule->genmask = 0;
+       rule->genmask &= ~(1 << gencursor_next(net));
 }
 
 static int
@@ -1225,7 +1225,10 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
 
        if (nla[NFTA_CHAIN_POLICY]) {
                if ((chain != NULL &&
-                   !(chain->flags & NFT_BASE_CHAIN)) ||
+                   !(chain->flags & NFT_BASE_CHAIN)))
+                       return -EOPNOTSUPP;
+
+               if (chain == NULL &&
                    nla[NFTA_CHAIN_HOOK] == NULL)
                        return -EOPNOTSUPP;
 
@@ -1711,9 +1714,12 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
        }
        nla_nest_end(skb, list);
 
-       if (rule->ulen &&
-           nla_put(skb, NFTA_RULE_USERDATA, rule->ulen, nft_userdata(rule)))
-               goto nla_put_failure;
+       if (rule->udata) {
+               struct nft_userdata *udata = nft_userdata(rule);
+               if (nla_put(skb, NFTA_RULE_USERDATA, udata->len + 1,
+                           udata->data) < 0)
+                       goto nla_put_failure;
+       }
 
        nlmsg_end(skb, nlh);
        return 0;
@@ -1896,11 +1902,12 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
        struct nft_table *table;
        struct nft_chain *chain;
        struct nft_rule *rule, *old_rule = NULL;
+       struct nft_userdata *udata;
        struct nft_trans *trans = NULL;
        struct nft_expr *expr;
        struct nft_ctx ctx;
        struct nlattr *tmp;
-       unsigned int size, i, n, ulen = 0;
+       unsigned int size, i, n, ulen = 0, usize = 0;
        int err, rem;
        bool create;
        u64 handle, pos_handle;
@@ -1968,12 +1975,19 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
                        n++;
                }
        }
+       /* Check for overflow of dlen field */
+       err = -EFBIG;
+       if (size >= 1 << 12)
+               goto err1;
 
-       if (nla[NFTA_RULE_USERDATA])
+       if (nla[NFTA_RULE_USERDATA]) {
                ulen = nla_len(nla[NFTA_RULE_USERDATA]);
+               if (ulen > 0)
+                       usize = sizeof(struct nft_userdata) + ulen;
+       }
 
        err = -ENOMEM;
-       rule = kzalloc(sizeof(*rule) + size + ulen, GFP_KERNEL);
+       rule = kzalloc(sizeof(*rule) + size + usize, GFP_KERNEL);
        if (rule == NULL)
                goto err1;
 
@@ -1981,10 +1995,13 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 
        rule->handle = handle;
        rule->dlen   = size;
-       rule->ulen   = ulen;
+       rule->udata  = ulen ? 1 : 0;
 
-       if (ulen)
-               nla_memcpy(nft_userdata(rule), nla[NFTA_RULE_USERDATA], ulen);
+       if (ulen) {
+               udata = nft_userdata(rule);
+               udata->len = ulen - 1;
+               nla_memcpy(udata->data, nla[NFTA_RULE_USERDATA], ulen);
+       }
 
        expr = nft_expr_first(rule);
        for (i = 0; i < n; i++) {
@@ -2031,12 +2048,6 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 
 err3:
        list_del_rcu(&rule->list);
-       if (trans) {
-               list_del_rcu(&nft_trans_rule(trans)->list);
-               nft_rule_clear(net, nft_trans_rule(trans));
-               nft_trans_destroy(trans);
-               chain->use++;
-       }
 err2:
        nf_tables_rule_destroy(&ctx, rule);
 err1:
@@ -3612,12 +3623,11 @@ static int nf_tables_commit(struct sk_buff *skb)
                                                 &te->elem,
                                                 NFT_MSG_DELSETELEM, 0);
                        te->set->ops->get(te->set, &te->elem);
-                       te->set->ops->remove(te->set, &te->elem);
                        nft_data_uninit(&te->elem.key, NFT_DATA_VALUE);
-                       if (te->elem.flags & NFT_SET_MAP) {
-                               nft_data_uninit(&te->elem.data,
-                                               te->set->dtype);
-                       }
+                       if (te->set->flags & NFT_SET_MAP &&
+                           !(te->elem.flags & NFT_SET_ELEM_INTERVAL_END))
+                               nft_data_uninit(&te->elem.data, te->set->dtype);
+                       te->set->ops->remove(te->set, &te->elem);
                        nft_trans_destroy(trans);
                        break;
                }
@@ -3658,7 +3668,7 @@ static int nf_tables_abort(struct sk_buff *skb)
 {
        struct net *net = sock_net(skb->sk);
        struct nft_trans *trans, *next;
-       struct nft_set *set;
+       struct nft_trans_elem *te;
 
        list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
                switch (trans->msg_type) {
@@ -3719,9 +3729,13 @@ static int nf_tables_abort(struct sk_buff *skb)
                        break;
                case NFT_MSG_NEWSETELEM:
                        nft_trans_elem_set(trans)->nelems--;
-                       set = nft_trans_elem_set(trans);
-                       set->ops->get(set, &nft_trans_elem(trans));
-                       set->ops->remove(set, &nft_trans_elem(trans));
+                       te = (struct nft_trans_elem *)trans->data;
+                       te->set->ops->get(te->set, &te->elem);
+                       nft_data_uninit(&te->elem.key, NFT_DATA_VALUE);
+                       if (te->set->flags & NFT_SET_MAP &&
+                           !(te->elem.flags & NFT_SET_ELEM_INTERVAL_END))
+                               nft_data_uninit(&te->elem.data, te->set->dtype);
+                       te->set->ops->remove(te->set, &te->elem);
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELSETELEM:
index 3b90eb2b2c55453e989c891a3f815be6e1da22d1..2d298dccb6dd3fc5589be16021c843d741a4c025 100644 (file)
@@ -94,10 +94,10 @@ static void nft_trace_packet(const struct nft_pktinfo *pkt,
 {
        struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
 
-       nf_log_packet(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
-                     pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
-                     chain->table->name, chain->name, comments[type],
-                     rulenum);
+       nf_log_trace(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
+                    pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
+                    chain->table->name, chain->name, comments[type],
+                    rulenum);
 }
 
 unsigned int
index a5599fc51a6f3f87db4d63ecd20073481520a238..54330fb5efaf632d39d3e00135ac3360bdfdb80d 100644 (file)
@@ -77,6 +77,9 @@ nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
        if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
                return -EINVAL;
 
+       /* Not all fields are initialized so first zero the tuple */
+       memset(tuple, 0, sizeof(struct nf_conntrack_tuple));
+
        tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM]));
        tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
 
index c598f74063a19ebd51ea786530c0669d6f92b8c3..65f3e2b6be44031448d85323ccf17cddaffd5557 100644 (file)
@@ -123,7 +123,7 @@ static void
 nft_target_set_tgchk_param(struct xt_tgchk_param *par,
                           const struct nft_ctx *ctx,
                           struct xt_target *target, void *info,
-                          union nft_entry *entry, u8 proto, bool inv)
+                          union nft_entry *entry, u16 proto, bool inv)
 {
        par->net        = ctx->net;
        par->table      = ctx->table->name;
@@ -133,11 +133,14 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par,
                entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
                break;
        case AF_INET6:
+               if (proto)
+                       entry->e6.ipv6.flags |= IP6T_F_PROTO;
+
                entry->e6.ipv6.proto = proto;
                entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
                break;
        case NFPROTO_BRIDGE:
-               entry->ebt.ethproto = proto;
+               entry->ebt.ethproto = (__force __be16)proto;
                entry->ebt.invflags = inv ? EBT_IPROTO : 0;
                break;
        }
@@ -171,7 +174,7 @@ static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1]
        [NFTA_RULE_COMPAT_FLAGS]        = { .type = NLA_U32 },
 };
 
-static int nft_parse_compat(const struct nlattr *attr, u8 *proto, bool *inv)
+static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv)
 {
        struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1];
        u32 flags;
@@ -203,7 +206,7 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        struct xt_target *target = expr->ops->data;
        struct xt_tgchk_param par;
        size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO]));
-       u8 proto = 0;
+       u16 proto = 0;
        bool inv = false;
        union nft_entry e = {};
        int ret;
@@ -334,7 +337,7 @@ static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
 static void
 nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
                          struct xt_match *match, void *info,
-                         union nft_entry *entry, u8 proto, bool inv)
+                         union nft_entry *entry, u16 proto, bool inv)
 {
        par->net        = ctx->net;
        par->table      = ctx->table->name;
@@ -344,11 +347,14 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
                entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
                break;
        case AF_INET6:
+               if (proto)
+                       entry->e6.ipv6.flags |= IP6T_F_PROTO;
+
                entry->e6.ipv6.proto = proto;
                entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
                break;
        case NFPROTO_BRIDGE:
-               entry->ebt.ethproto = proto;
+               entry->ebt.ethproto = (__force __be16)proto;
                entry->ebt.invflags = inv ? EBT_IPROTO : 0;
                break;
        }
@@ -385,7 +391,7 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        struct xt_match *match = expr->ops->data;
        struct xt_mtchk_param par;
        size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO]));
-       u8 proto = 0;
+       u16 proto = 0;
        bool inv = false;
        union nft_entry e = {};
        int ret;
@@ -625,8 +631,12 @@ nft_match_select_ops(const struct nft_ctx *ctx,
                struct xt_match *match = nft_match->ops.data;
 
                if (strcmp(match->name, mt_name) == 0 &&
-                   match->revision == rev && match->family == family)
+                   match->revision == rev && match->family == family) {
+                       if (!try_module_get(match->me))
+                               return ERR_PTR(-ENOENT);
+
                        return &nft_match->ops;
+               }
        }
 
        match = xt_request_find_match(family, mt_name, rev);
@@ -695,8 +705,12 @@ nft_target_select_ops(const struct nft_ctx *ctx,
                struct xt_target *target = nft_target->ops.data;
 
                if (strcmp(target->name, tg_name) == 0 &&
-                   target->revision == rev && target->family == family)
+                   target->revision == rev && target->family == family) {
+                       if (!try_module_get(target->me))
+                               return ERR_PTR(-ENOENT);
+
                        return &nft_target->ops;
+               }
        }
 
        target = xt_request_find_target(family, tg_name, rev);
index 61e6c407476a618df386c2f14839033398aae14b..37c15e6748841053df56fe092a49ced6fb06b077 100644 (file)
@@ -153,6 +153,8 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
                                iter->err = err;
                                goto out;
                        }
+
+                       continue;
                }
 
                if (iter->count < iter->skip)
@@ -192,8 +194,6 @@ static int nft_hash_init(const struct nft_set *set,
                .key_offset = offsetof(struct nft_hash_elem, key),
                .key_len = set->klen,
                .hashfn = jhash,
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
 
        return rhashtable_init(priv, &params);
index ef8a926752a97542f6f2f8eeb378e150958bff3d..50e1e5aaf4ce82ff7bbf1ee7171aaa51d54eefd1 100644 (file)
@@ -513,8 +513,8 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par)
 {
        const struct ip6t_ip6 *i = par->entryinfo;
 
-       if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
-           && !(i->flags & IP6T_INV_PROTO))
+       if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) &&
+           !(i->invflags & IP6T_INV_PROTO))
                return 0;
 
        pr_info("Can be used only in combination with "
index 30dbe34915ae2b1fcf4d0ca3149369bdf3913f0f..45e1b30e4fb214f850af2590425ab2a9748c6476 100644 (file)
@@ -378,12 +378,11 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
        mutex_lock(&recent_mutex);
        t = recent_table_lookup(recent_net, info->name);
        if (t != NULL) {
-               if (info->hit_count > t->nstamps_max_mask) {
-                       pr_info("hitcount (%u) is larger than packets to be remembered (%u) for table %s\n",
-                               info->hit_count, t->nstamps_max_mask + 1,
-                               info->name);
-                       ret = -EINVAL;
-                       goto out;
+               if (nstamp_mask > t->nstamps_max_mask) {
+                       spin_lock_bh(&recent_lock);
+                       recent_table_flush(t);
+                       t->nstamps_max_mask = nstamp_mask;
+                       spin_unlock_bh(&recent_lock);
                }
 
                t->refcnt++;
index 1ba67931eb1b168fabfa78790f5ed53713188f9d..13332dbf291d6e530b77c3c8a7d155a07788ebc3 100644 (file)
@@ -243,12 +243,13 @@ static int
 extract_icmp6_fields(const struct sk_buff *skb,
                     unsigned int outside_hdrlen,
                     int *protocol,
-                    struct in6_addr **raddr,
-                    struct in6_addr **laddr,
+                    const struct in6_addr **raddr,
+                    const struct in6_addr **laddr,
                     __be16 *rport,
-                    __be16 *lport)
+                    __be16 *lport,
+                    struct ipv6hdr *ipv6_var)
 {
-       struct ipv6hdr *inside_iph, _inside_iph;
+       const struct ipv6hdr *inside_iph;
        struct icmp6hdr *icmph, _icmph;
        __be16 *ports, _ports[2];
        u8 inside_nexthdr;
@@ -263,12 +264,14 @@ extract_icmp6_fields(const struct sk_buff *skb,
        if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
                return 1;
 
-       inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph), sizeof(_inside_iph), &_inside_iph);
+       inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph),
+                                       sizeof(*ipv6_var), ipv6_var);
        if (inside_iph == NULL)
                return 1;
        inside_nexthdr = inside_iph->nexthdr;
 
-       inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) + sizeof(_inside_iph),
+       inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) +
+                                             sizeof(*ipv6_var),
                                         &inside_nexthdr, &inside_fragoff);
        if (inside_hdrlen < 0)
                return 1; /* hjm: Packet has no/incomplete transport layer headers. */
@@ -315,10 +318,10 @@ xt_socket_get_sock_v6(struct net *net, const u8 protocol,
 static bool
 socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 {
-       struct ipv6hdr *iph = ipv6_hdr(skb);
+       struct ipv6hdr ipv6_var, *iph = ipv6_hdr(skb);
        struct udphdr _hdr, *hp = NULL;
        struct sock *sk = skb->sk;
-       struct in6_addr *daddr = NULL, *saddr = NULL;
+       const struct in6_addr *daddr = NULL, *saddr = NULL;
        __be16 uninitialized_var(dport), uninitialized_var(sport);
        int thoff = 0, uninitialized_var(tproto);
        const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
@@ -342,7 +345,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 
        } else if (tproto == IPPROTO_ICMPV6) {
                if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
-                                        &sport, &dport))
+                                        &sport, &dport, &ipv6_var))
                        return false;
        } else {
                return false;
index 2702673f0f237d7fa43e4649ccc0672f67c895bc..05919bf3f670ed1267e01f14c1de61e78e4d80c4 100644 (file)
@@ -3126,8 +3126,6 @@ static int __init netlink_proto_init(void)
                .key_len = sizeof(u32), /* portid */
                .hashfn = jhash,
                .max_shift = 16, /* 64K */
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
 
        if (err != 0)
index ae5e77cdc0ca1f34ff7f9c99d65ba0c8bda9ace6..5bae7243c5777e38df7be95454b8164724c769cf 100644 (file)
@@ -2194,14 +2194,55 @@ static int __net_init ovs_init_net(struct net *net)
        return 0;
 }
 
-static void __net_exit ovs_exit_net(struct net *net)
+static void __net_exit list_vports_from_net(struct net *net, struct net *dnet,
+                                           struct list_head *head)
 {
-       struct datapath *dp, *dp_next;
        struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
+       struct datapath *dp;
+
+       list_for_each_entry(dp, &ovs_net->dps, list_node) {
+               int i;
+
+               for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
+                       struct vport *vport;
+
+                       hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) {
+                               struct netdev_vport *netdev_vport;
+
+                               if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL)
+                                       continue;
+
+                               netdev_vport = netdev_vport_priv(vport);
+                               if (dev_net(netdev_vport->dev) == dnet)
+                                       list_add(&vport->detach_list, head);
+                       }
+               }
+       }
+}
+
+static void __net_exit ovs_exit_net(struct net *dnet)
+{
+       struct datapath *dp, *dp_next;
+       struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id);
+       struct vport *vport, *vport_next;
+       struct net *net;
+       LIST_HEAD(head);
 
        ovs_lock();
        list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
                __dp_destroy(dp);
+
+       rtnl_lock();
+       for_each_net(net)
+               list_vports_from_net(net, dnet, &head);
+       rtnl_unlock();
+
+       /* Detach all vports from given namespace. */
+       list_for_each_entry_safe(vport, vport_next, &head, detach_list) {
+               list_del(&vport->detach_list);
+               ovs_dp_detach_port(vport);
+       }
+
        ovs_unlock();
 
        cancel_work_sync(&ovs_net->dp_notify_work);
index 216f20b90aa596b49592beee89a996cbe868d8ba..22b18c145c9221675e031de2617fcdd800405170 100644 (file)
@@ -2253,14 +2253,20 @@ static int masked_set_action_to_set_action_attr(const struct nlattr *a,
                                                struct sk_buff *skb)
 {
        const struct nlattr *ovs_key = nla_data(a);
+       struct nlattr *nla;
        size_t key_len = nla_len(ovs_key) / 2;
 
        /* Revert the conversion we did from a non-masked set action to
         * masked set action.
         */
-       if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a) - key_len, ovs_key))
+       nla = nla_nest_start(skb, OVS_ACTION_ATTR_SET);
+       if (!nla)
                return -EMSGSIZE;
 
+       if (nla_put(skb, nla_type(ovs_key), key_len, nla_data(ovs_key)))
+               return -EMSGSIZE;
+
+       nla_nest_end(skb, nla);
        return 0;
 }
 
index f8ae295fb0011f7cc5dea75737833b7086641c77..bc85331a6c60cae9182bd1348d35d81117cf2943 100644 (file)
@@ -103,6 +103,7 @@ struct vport_portids {
  * @ops: Class structure.
  * @percpu_stats: Points to per-CPU statistics used and maintained by vport
  * @err_stats: Points to error statistics used and maintained by vport
+ * @detach_list: list used for detaching vport in net-exit call.
  */
 struct vport {
        struct rcu_head rcu;
@@ -117,6 +118,7 @@ struct vport {
        struct pcpu_sw_netstats __percpu *percpu_stats;
 
        struct vport_err_stats err_stats;
+       struct list_head detach_list;
 };
 
 /**
index 9c28cec1a0838ecf8ea03ceff77fb301c5a425a7..f8db7064d81c770cda356633153230eb905ccb39 100644 (file)
@@ -698,6 +698,10 @@ static void prb_retire_rx_blk_timer_expired(unsigned long data)
 
        if (pkc->last_kactive_blk_num == pkc->kactive_blk_num) {
                if (!frozen) {
+                       if (!BLOCK_NUM_PKTS(pbd)) {
+                               /* An empty block. Just refresh the timer. */
+                               goto refresh_timer;
+                       }
                        prb_retire_current_block(pkc, po, TP_STATUS_BLK_TMO);
                        if (!prb_dispatch_next_block(pkc, po))
                                goto refresh_timer;
@@ -798,7 +802,11 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1,
                h1->ts_last_pkt.ts_sec = last_pkt->tp_sec;
                h1->ts_last_pkt.ts_nsec = last_pkt->tp_nsec;
        } else {
-               /* Ok, we tmo'd - so get the current time */
+               /* Ok, we tmo'd - so get the current time.
+                *
+                * It shouldn't really happen as we don't close empty
+                * blocks. See prb_retire_rx_blk_timer_expired().
+                */
                struct timespec ts;
                getnstimeofday(&ts);
                h1->ts_last_pkt.ts_sec = ts.tv_sec;
@@ -1349,14 +1357,14 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
                return 0;
        }
 
+       if (fanout_has_flag(f, PACKET_FANOUT_FLAG_DEFRAG)) {
+               skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET);
+               if (!skb)
+                       return 0;
+       }
        switch (f->type) {
        case PACKET_FANOUT_HASH:
        default:
-               if (fanout_has_flag(f, PACKET_FANOUT_FLAG_DEFRAG)) {
-                       skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET);
-                       if (!skb)
-                               return 0;
-               }
                idx = fanout_demux_hash(f, skb, num);
                break;
        case PACKET_FANOUT_LB:
@@ -3115,11 +3123,18 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
        return 0;
 }
 
-static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what)
+static void packet_dev_mclist_delete(struct net_device *dev,
+                                    struct packet_mclist **mlp)
 {
-       for ( ; i; i = i->next) {
-               if (i->ifindex == dev->ifindex)
-                       packet_dev_mc(dev, i, what);
+       struct packet_mclist *ml;
+
+       while ((ml = *mlp) != NULL) {
+               if (ml->ifindex == dev->ifindex) {
+                       packet_dev_mc(dev, ml, -1);
+                       *mlp = ml->next;
+                       kfree(ml);
+               } else
+                       mlp = &ml->next;
        }
 }
 
@@ -3196,12 +3211,11 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq)
                                        packet_dev_mc(dev, ml, -1);
                                kfree(ml);
                        }
-                       rtnl_unlock();
-                       return 0;
+                       break;
                }
        }
        rtnl_unlock();
-       return -EADDRNOTAVAIL;
+       return 0;
 }
 
 static void packet_flush_mclist(struct sock *sk)
@@ -3551,7 +3565,7 @@ static int packet_notifier(struct notifier_block *this,
                switch (msg) {
                case NETDEV_UNREGISTER:
                        if (po->mclist)
-                               packet_dev_mclist(dev, po->mclist, -1);
+                               packet_dev_mclist_delete(dev, &po->mclist);
                        /* fallthrough */
 
                case NETDEV_DOWN:
index a817705ce2d0e9246388c2c65d77b4c486a8feba..dba8d0864f18046ee87a168d49cc159518fa2916 100644 (file)
@@ -88,7 +88,9 @@ static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
                        int *unpinned);
 static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
 
-static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwdev, struct rdma_cm_id **cm_id)
+static int rds_iw_get_device(struct sockaddr_in *src, struct sockaddr_in *dst,
+                            struct rds_iw_device **rds_iwdev,
+                            struct rdma_cm_id **cm_id)
 {
        struct rds_iw_device *iwdev;
        struct rds_iw_cm_id *i_cm_id;
@@ -112,15 +114,15 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
                                src_addr->sin_port,
                                dst_addr->sin_addr.s_addr,
                                dst_addr->sin_port,
-                               rs->rs_bound_addr,
-                               rs->rs_bound_port,
-                               rs->rs_conn_addr,
-                               rs->rs_conn_port);
+                               src->sin_addr.s_addr,
+                               src->sin_port,
+                               dst->sin_addr.s_addr,
+                               dst->sin_port);
 #ifdef WORKING_TUPLE_DETECTION
-                       if (src_addr->sin_addr.s_addr == rs->rs_bound_addr &&
-                           src_addr->sin_port == rs->rs_bound_port &&
-                           dst_addr->sin_addr.s_addr == rs->rs_conn_addr &&
-                           dst_addr->sin_port == rs->rs_conn_port) {
+                       if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr &&
+                           src_addr->sin_port == src->sin_port &&
+                           dst_addr->sin_addr.s_addr == dst->sin_addr.s_addr &&
+                           dst_addr->sin_port == dst->sin_port) {
 #else
                        /* FIXME - needs to compare the local and remote
                         * ipaddr/port tuple, but the ipaddr is the only
@@ -128,7 +130,7 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
                         * zero'ed.  It doesn't appear to be properly populated
                         * during connection setup...
                         */
-                       if (src_addr->sin_addr.s_addr == rs->rs_bound_addr) {
+                       if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr) {
 #endif
                                spin_unlock_irq(&iwdev->spinlock);
                                *rds_iwdev = iwdev;
@@ -180,19 +182,13 @@ int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_i
 {
        struct sockaddr_in *src_addr, *dst_addr;
        struct rds_iw_device *rds_iwdev_old;
-       struct rds_sock rs;
        struct rdma_cm_id *pcm_id;
        int rc;
 
        src_addr = (struct sockaddr_in *)&cm_id->route.addr.src_addr;
        dst_addr = (struct sockaddr_in *)&cm_id->route.addr.dst_addr;
 
-       rs.rs_bound_addr = src_addr->sin_addr.s_addr;
-       rs.rs_bound_port = src_addr->sin_port;
-       rs.rs_conn_addr = dst_addr->sin_addr.s_addr;
-       rs.rs_conn_port = dst_addr->sin_port;
-
-       rc = rds_iw_get_device(&rs, &rds_iwdev_old, &pcm_id);
+       rc = rds_iw_get_device(src_addr, dst_addr, &rds_iwdev_old, &pcm_id);
        if (rc)
                rds_iw_remove_cm_id(rds_iwdev, cm_id);
 
@@ -598,9 +594,17 @@ void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
        struct rds_iw_device *rds_iwdev;
        struct rds_iw_mr *ibmr = NULL;
        struct rdma_cm_id *cm_id;
+       struct sockaddr_in src = {
+               .sin_addr.s_addr = rs->rs_bound_addr,
+               .sin_port = rs->rs_bound_port,
+       };
+       struct sockaddr_in dst = {
+               .sin_addr.s_addr = rs->rs_conn_addr,
+               .sin_port = rs->rs_conn_port,
+       };
        int ret;
 
-       ret = rds_iw_get_device(rs, &rds_iwdev, &cm_id);
+       ret = rds_iw_get_device(&src, &dst, &rds_iwdev, &cm_id);
        if (ret || !cm_id) {
                ret = -ENODEV;
                goto out;
index c6be17a959a6e4981ecfff38af85805df6d8b26e..e0547f521f20d79c688c773286d609066c990a1d 100644 (file)
@@ -218,7 +218,8 @@ static void rxrpc_resend(struct rxrpc_call *call)
        struct rxrpc_header *hdr;
        struct sk_buff *txb;
        unsigned long *p_txb, resend_at;
-       int loop, stop;
+       bool stop;
+       int loop;
        u8 resend;
 
        _enter("{%d,%d,%d,%d},",
@@ -226,7 +227,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
               atomic_read(&call->sequence),
               CIRC_CNT(call->acks_head, call->acks_tail, call->acks_winsz));
 
-       stop = 0;
+       stop = false;
        resend = 0;
        resend_at = 0;
 
@@ -255,11 +256,11 @@ static void rxrpc_resend(struct rxrpc_call *call)
                        _proto("Tx DATA %%%u { #%d }",
                               ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
                        if (rxrpc_send_packet(call->conn->trans, txb) < 0) {
-                               stop = 0;
+                               stop = true;
                                sp->resend_at = jiffies + 3;
                        } else {
                                sp->resend_at =
-                                       jiffies + rxrpc_resend_timeout * HZ;
+                                       jiffies + rxrpc_resend_timeout;
                        }
                }
 
index 5394b6be46ecd5ebb6c677b745a4848977433f70..0610efa83d721389fc0f2c3597f3e284fee341d7 100644 (file)
@@ -42,7 +42,8 @@ void rxrpc_UDP_error_report(struct sock *sk)
                _leave("UDP socket errqueue empty");
                return;
        }
-       if (!skb->len) {
+       serr = SKB_EXT_ERR(skb);
+       if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) {
                _leave("UDP empty message");
                kfree_skb(skb);
                return;
@@ -50,7 +51,6 @@ void rxrpc_UDP_error_report(struct sock *sk)
 
        rxrpc_new_skb(skb);
 
-       serr = SKB_EXT_ERR(skb);
        addr = *(__be32 *)(skb_network_header(skb) + serr->addr_offset);
        port = serr->port;
 
index 4575485ad1b4d02796717879e09ad9078e232617..19a560626dc4f4232592e7d34381a859a04b6f4c 100644 (file)
@@ -87,7 +87,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
                if (!skb) {
                        /* nothing remains on the queue */
                        if (copied &&
-                           (msg->msg_flags & MSG_PEEK || timeo == 0))
+                           (flags & MSG_PEEK || timeo == 0))
                                goto out;
 
                        /* wait for a message to turn up */
index 82c5d7fc19881577d888fad3d5b0369e4698172b..5f6288fa3f1247462897cd747364dfbc9e0da843 100644 (file)
@@ -25,21 +25,41 @@ static int tcf_bpf(struct sk_buff *skb, const struct tc_action *a,
                   struct tcf_result *res)
 {
        struct tcf_bpf *b = a->priv;
-       int action;
-       int filter_res;
+       int action, filter_res;
 
        spin_lock(&b->tcf_lock);
+
        b->tcf_tm.lastuse = jiffies;
        bstats_update(&b->tcf_bstats, skb);
-       action = b->tcf_action;
 
        filter_res = BPF_PROG_RUN(b->filter, skb);
-       if (filter_res == 0) {
-               /* Return code 0 from the BPF program
-                * is being interpreted as a drop here.
-                */
-               action = TC_ACT_SHOT;
+
+       /* A BPF program may overwrite the default action opcode.
+        * Similarly as in cls_bpf, if filter_res == -1 we use the
+        * default action specified from tc.
+        *
+        * In case a different well-known TC_ACT opcode has been
+        * returned, it will overwrite the default one.
+        *
+        * For everything else that is unkown, TC_ACT_UNSPEC is
+        * returned.
+        */
+       switch (filter_res) {
+       case TC_ACT_PIPE:
+       case TC_ACT_RECLASSIFY:
+       case TC_ACT_OK:
+               action = filter_res;
+               break;
+       case TC_ACT_SHOT:
+               action = filter_res;
                b->tcf_qstats.drops++;
+               break;
+       case TC_ACT_UNSPEC:
+               action = b->tcf_action;
+               break;
+       default:
+               action = TC_ACT_UNSPEC;
+               break;
        }
 
        spin_unlock(&b->tcf_lock);
index 09487afbfd5187a312ab155df5da43548d0c326b..95fdf4e4005190704dcd405e6b9422f8f56ba796 100644 (file)
@@ -78,8 +78,11 @@ struct tc_u_hnode {
        struct tc_u_common      *tp_c;
        int                     refcnt;
        unsigned int            divisor;
-       struct tc_u_knode __rcu *ht[1];
        struct rcu_head         rcu;
+       /* The 'ht' field MUST be the last field in structure to allow for
+        * more entries allocated at end of structure.
+        */
+       struct tc_u_knode __rcu *ht[1];
 };
 
 struct tc_u_common {
index 6742200b13071b6e63c200767a77a653d2e10c06..fbb7ebfc58c6761f6afb58e62646908b10e2bf09 100644 (file)
@@ -228,6 +228,7 @@ static int tcf_em_validate(struct tcf_proto *tp,
                                 * to replay the request.
                                 */
                                module_put(em->ops->owner);
+                               em->ops = NULL;
                                err = -EAGAIN;
                        }
 #endif
index bbedbfcb42c2505fceb57fa058f262d90e1670ed..245330ca0015c2fd2548ead861d379714151c901 100644 (file)
@@ -1702,6 +1702,8 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
 
        if (len > INT_MAX)
                len = INT_MAX;
+       if (unlikely(!access_ok(VERIFY_READ, buff, len)))
+               return -EFAULT;
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
@@ -1760,6 +1762,8 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
 
        if (size > INT_MAX)
                size = INT_MAX;
+       if (unlikely(!access_ok(VERIFY_WRITE, ubuf, size)))
+               return -EFAULT;
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
index abbb7dcd16897125863098cb48f6a6411488225c..59eeed43eda2d2651916dcc8698c12c7d7249e4e 100644 (file)
@@ -217,6 +217,8 @@ static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg)
 
        for (i = 0; i < arg->npages && arg->pages[i]; i++)
                __free_page(arg->pages[i]);
+
+       kfree(arg->pages);
 }
 
 static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg)
index 224a82f24d3c75e60c702bd89215b7934ded1ea8..1095be9c80ab809900d2bf0afbde9c63b6034a9d 100644 (file)
@@ -463,6 +463,8 @@ static int rsc_parse(struct cache_detail *cd,
                /* number of additional gid's */
                if (get_int(&mesg, &N))
                        goto out;
+               if (N < 0 || N > NGROUPS_MAX)
+                       goto out;
                status = -ENOMEM;
                rsci.cred.cr_group_info = groups_alloc(N);
                if (rsci.cred.cr_group_info == NULL)
index 33fb105d4352627319c604bdd03b7c9493f24adf..5199bb1a017e47b1b7503caf8075191dac1ade57 100644 (file)
@@ -921,7 +921,7 @@ static unsigned int cache_poll(struct file *filp, poll_table *wait,
        poll_wait(filp, &queue_wait, wait);
 
        /* alway allow write */
-       mask = POLL_OUT | POLLWRNORM;
+       mask = POLLOUT | POLLWRNORM;
 
        if (!rp)
                return mask;
index 7e9acd9361c55bae557fcc51681585434b1755ef..91ffde82fa0c49eba3e11385aec9e334eb6b699a 100644 (file)
@@ -738,8 +738,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
        struct rpc_xprt *xprt = rep->rr_xprt;
        struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
        __be32 *iptr;
-       int credits, rdmalen, status;
+       int rdmalen, status;
        unsigned long cwnd;
+       u32 credits;
 
        /* Check status. If bad, signal disconnect and return rep to pool */
        if (rep->rr_len == ~0U) {
index d1b70397c60f0d8cb2ceb31c2feed19f7ca8f99a..0a16fb6f088590c142232ad99b2ac3b29304c169 100644 (file)
@@ -285,7 +285,7 @@ rpcr_to_rdmar(struct rpc_rqst *rqst)
  */
 struct rpcrdma_buffer {
        spinlock_t      rb_lock;        /* protects indexes */
-       int             rb_max_requests;/* client max requests */
+       u32             rb_max_requests;/* client max requests */
        struct list_head rb_mws;        /* optional memory windows/fmrs/frmrs */
        struct list_head rb_all;
        int             rb_send_index;
index a4cf364316de64a2a8df01350d31edf4af0866ea..14f09b3cb87c2fd9c87c67dfb67ce5e8df7d9f0f 100644 (file)
@@ -464,10 +464,11 @@ void tipc_link_reset(struct tipc_link *l_ptr)
        /* Clean up all queues, except inputq: */
        __skb_queue_purge(&l_ptr->outqueue);
        __skb_queue_purge(&l_ptr->deferred_queue);
-       skb_queue_splice_init(&l_ptr->wakeupq, &l_ptr->inputq);
-       if (!skb_queue_empty(&l_ptr->inputq))
+       if (!owner->inputq)
+               owner->inputq = &l_ptr->inputq;
+       skb_queue_splice_init(&l_ptr->wakeupq, owner->inputq);
+       if (!skb_queue_empty(owner->inputq))
                owner->action_flags |= TIPC_MSG_EVT;
-       owner->inputq = &l_ptr->inputq;
        l_ptr->next_out = NULL;
        l_ptr->unacked_window = 0;
        l_ptr->checkpoint = 1;
index f73e975af80b622c48d5ba92ec1e9504af4755e2..b4d4467d0bb051b09243c62aae2b3b2dca6d90a6 100644 (file)
@@ -2364,8 +2364,6 @@ int tipc_sk_rht_init(struct net *net)
                .hashfn = jhash,
                .max_shift = 20, /* 1M */
                .min_shift = 8,  /* 256 */
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
 
        return rhashtable_init(&tn->sk_rht, &rht_params);
index 3af0ecf1cc16859abecb7451df5cabe35d6dbf08..2a0bbd22854bd97b377139200f9e6b5e0ec2662f 100644 (file)
@@ -1199,6 +1199,7 @@ out_fail_wq:
        regulatory_exit();
 out_fail_reg:
        debugfs_remove(ieee80211_debugfs_dir);
+       nl80211_exit();
 out_fail_nl80211:
        unregister_netdevice_notifier(&cfg80211_netdev_notifier);
 out_fail_notifier:
index d78fd8b54515e630b67bf38d710b2b698f703c4c..b6f84f6a2a095ef0c94891f796ef6cf7cf9af65f 100644 (file)
@@ -2654,10 +2654,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-
        err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
                                  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
                                  &flags);
@@ -2666,6 +2662,10 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
            !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
                return -EOPNOTSUPP;
 
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
        wdev = rdev_add_virtual_intf(rdev,
                                nla_data(info->attrs[NL80211_ATTR_IFNAME]),
                                type, err ? NULL : &flags, &params);
@@ -4400,6 +4400,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
+       /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
+        * as userspace might just pass through the capabilities from the IEs
+        * directly, rather than enforcing this restriction and returning an
+        * error in this case.
+        */
+       if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
+               params.ht_capa = NULL;
+               params.vht_capa = NULL;
+       }
+
        /* When you run into this, adjust the code below for the new flag */
        BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
 
@@ -12528,9 +12538,7 @@ static int cfg80211_net_detect_results(struct sk_buff *msg,
                        }
 
                        for (j = 0; j < match->n_channels; j++) {
-                               if (nla_put_u32(msg,
-                                               NL80211_ATTR_WIPHY_FREQ,
-                                               match->channels[j])) {
+                               if (nla_put_u32(msg, j, match->channels[j])) {
                                        nla_nest_cancel(msg, nl_freqs);
                                        nla_nest_cancel(msg, nl_match);
                                        goto out;
index b586d0dcb09ebc9382fa0bd22016264e5bdd21c2..48dfc7b4e98130e4d8d5b265fceadd9004ed4f5e 100644 (file)
@@ -228,7 +228,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work);
 
 /* We keep a static world regulatory domain in case of the absence of CRDA */
 static const struct ieee80211_regdomain world_regdom = {
-       .n_reg_rules = 6,
+       .n_reg_rules = 8,
        .alpha2 =  "00",
        .reg_rules = {
                /* IEEE 802.11b/g, channels 1..11 */
index cee479bc655c4f317edb4e90cbcb06ec3b424b81..638af0655aaf8ec600ae5f6b201e252ca229d89d 100644 (file)
@@ -2269,11 +2269,9 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
                 * have the xfrm_state's. We need to wait for KM to
                 * negotiate new SA's or bail out with error.*/
                if (net->xfrm.sysctl_larval_drop) {
-                       dst_release(dst);
-                       xfrm_pols_put(pols, drop_pols);
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
-
-                       return ERR_PTR(-EREMOTE);
+                       err = -EREMOTE;
+                       goto error;
                }
 
                err = -EAGAIN;
@@ -2324,7 +2322,8 @@ nopol:
 error:
        dst_release(dst);
 dropdst:
-       dst_release(dst_orig);
+       if (!(flags & XFRM_LOOKUP_KEEP_DST_REF))
+               dst_release(dst_orig);
        xfrm_pols_put(pols, drop_pols);
        return ERR_PTR(err);
 }
@@ -2338,7 +2337,8 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
                                    struct sock *sk, int flags)
 {
        struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk,
-                                           flags | XFRM_LOOKUP_QUEUE);
+                                           flags | XFRM_LOOKUP_QUEUE |
+                                           XFRM_LOOKUP_KEEP_DST_REF);
 
        if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
                return make_blackhole(net, dst_orig->ops->family, dst_orig);
diff --git a/scripts/gdb/linux/__init__.py b/scripts/gdb/linux/__init__.py
new file mode 100644 (file)
index 0000000..4680fb1
--- /dev/null
@@ -0,0 +1 @@
+# nothing to do for the initialization of this package
index 1684bcc78b34e42395b1db335c9122c405987c23..5fde34326dcf28312ab4c36cb09623ecb811760b 100644 (file)
@@ -152,7 +152,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
                goto out;
 
        /* No partial writes. */
-       length = EINVAL;
+       length = -EINVAL;
        if (*ppos != 0)
                goto out;
 
index 35324a8e83c867f126256f67b493b5320b9652c7..eeb691d1911f5716bb09b8eecacd24215a31564f 100644 (file)
@@ -1170,6 +1170,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
 
        if (info->count < 1)
                return -EINVAL;
+       if (!*info->id.name)
+               return -EINVAL;
+       if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name))
+               return -EINVAL;
        access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
                (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
                                 SNDRV_CTL_ELEM_ACCESS_INACTIVE|
index b03a638b420c18243776c45fda5884b422392c46..279e24f613051fddb8ca16375ab9031e6a703b03 100644 (file)
@@ -1552,6 +1552,8 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
                        if (! snd_pcm_playback_empty(substream)) {
                                snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING);
                                snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING);
+                       } else {
+                               runtime->status->state = SNDRV_PCM_STATE_SETUP;
                        }
                        break;
                case SNDRV_PCM_STATE_RUNNING:
index f62780ed64adcc85465447838ee3b5d794690937..7821b07415a785c70982e03803ac34601770e3a9 100644 (file)
@@ -105,6 +105,8 @@ static void snd_opl3_calc_pitch(unsigned char *fnum, unsigned char *blocknum,
                int pitchbend = chan->midi_pitchbend;
                int segment;
 
+               if (pitchbend < -0x2000)
+                       pitchbend = -0x2000;
                if (pitchbend > 0x1FFF)
                        pitchbend = 0x1FFF;
 
index 0d580186ef1ac379bcd2cb699ac2f33baeac9029..5cc356db5351d903a7199b233fdfffc2bd8a674e 100644 (file)
@@ -33,7 +33,7 @@
  */
 #define MAX_MIDI_RX_BLOCKS     8
 
-#define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 Ã‚µs */
+#define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 microseconds */
 
 /* isochronous header parameters */
 #define ISO_DATA_LENGTH_SHIFT  16
@@ -78,7 +78,7 @@ static void pcm_period_tasklet(unsigned long data);
 int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
                      enum amdtp_stream_direction dir, enum cip_flags flags)
 {
-       s->unit = fw_unit_get(unit);
+       s->unit = unit;
        s->direction = dir;
        s->flags = flags;
        s->context = ERR_PTR(-1);
@@ -102,7 +102,6 @@ void amdtp_stream_destroy(struct amdtp_stream *s)
 {
        WARN_ON(amdtp_stream_running(s));
        mutex_destroy(&s->mutex);
-       fw_unit_put(s->unit);
 }
 EXPORT_SYMBOL(amdtp_stream_destroy);
 
index fc19c99654aa0284d400e58c51abc1a0c35495ee..611b7dae7ee54c932394c713022fd4501c84f7ca 100644 (file)
@@ -116,11 +116,22 @@ end:
        return err;
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void
 bebob_card_free(struct snd_card *card)
 {
        struct snd_bebob *bebob = card->private_data;
 
+       snd_bebob_stream_destroy_duplex(bebob);
+       fw_unit_put(bebob->unit);
+
+       kfree(bebob->maudio_special_quirk);
+
        if (bebob->card_index >= 0) {
                mutex_lock(&devices_mutex);
                clear_bit(bebob->card_index, devices_used);
@@ -205,7 +216,7 @@ bebob_probe(struct fw_unit *unit,
        card->private_free = bebob_card_free;
 
        bebob->card = card;
-       bebob->unit = unit;
+       bebob->unit = fw_unit_get(unit);
        bebob->spec = spec;
        mutex_init(&bebob->mutex);
        spin_lock_init(&bebob->lock);
@@ -306,10 +317,11 @@ static void bebob_remove(struct fw_unit *unit)
        if (bebob == NULL)
                return;
 
-       kfree(bebob->maudio_special_quirk);
+       /* Awake bus-reset waiters. */
+       if (!completion_done(&bebob->bus_reset))
+               complete_all(&bebob->bus_reset);
 
-       snd_bebob_stream_destroy_duplex(bebob);
-       snd_card_disconnect(bebob->card);
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(bebob->card);
 }
 
index 0ebcabfdc7ce0162c9a77ed30ca038e6588cae63..98e4fc8121a1f4bdad82d892d79fa5c8241086af 100644 (file)
@@ -410,8 +410,6 @@ break_both_connections(struct snd_bebob *bebob)
 static void
 destroy_both_connections(struct snd_bebob *bebob)
 {
-       break_both_connections(bebob);
-
        cmp_connection_destroy(&bebob->in_conn);
        cmp_connection_destroy(&bebob->out_conn);
 }
@@ -712,22 +710,16 @@ void snd_bebob_stream_update_duplex(struct snd_bebob *bebob)
        mutex_unlock(&bebob->mutex);
 }
 
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
 void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
 {
-       mutex_lock(&bebob->mutex);
-
-       amdtp_stream_pcm_abort(&bebob->rx_stream);
-       amdtp_stream_pcm_abort(&bebob->tx_stream);
-
-       amdtp_stream_stop(&bebob->rx_stream);
-       amdtp_stream_stop(&bebob->tx_stream);
-
        amdtp_stream_destroy(&bebob->rx_stream);
        amdtp_stream_destroy(&bebob->tx_stream);
 
        destroy_both_connections(bebob);
-
-       mutex_unlock(&bebob->mutex);
 }
 
 /*
index fa9cf761b610ad81e537634590f6f33cff7e674e..07dbd01d7a6bd336d901fa78b83365b44307b1a0 100644 (file)
@@ -311,14 +311,21 @@ end:
        return err;
 }
 
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
 static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
 {
-       amdtp_stream_destroy(stream);
+       struct fw_iso_resources *resources;
 
        if (stream == &dice->tx_stream)
-               fw_iso_resources_destroy(&dice->tx_resources);
+               resources = &dice->tx_resources;
        else
-               fw_iso_resources_destroy(&dice->rx_resources);
+               resources = &dice->rx_resources;
+
+       amdtp_stream_destroy(stream);
+       fw_iso_resources_destroy(resources);
 }
 
 int snd_dice_stream_init_duplex(struct snd_dice *dice)
@@ -332,6 +339,8 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice)
                goto end;
 
        err = init_stream(dice, &dice->rx_stream);
+       if (err < 0)
+               destroy_stream(dice, &dice->tx_stream);
 end:
        return err;
 }
@@ -340,10 +349,7 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
 {
        snd_dice_transaction_clear_enable(dice);
 
-       stop_stream(dice, &dice->tx_stream);
        destroy_stream(dice, &dice->tx_stream);
-
-       stop_stream(dice, &dice->rx_stream);
        destroy_stream(dice, &dice->rx_stream);
 
        dice->substreams_counter = 0;
index 90d8f40ff72712f2ac67dc8f978855d59fd5f8d6..70a111d7f428af4a0487f80cf350767935c8cac0 100644 (file)
@@ -226,11 +226,20 @@ static void dice_card_strings(struct snd_dice *dice)
        strcpy(card->mixername, "DICE");
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void dice_card_free(struct snd_card *card)
 {
        struct snd_dice *dice = card->private_data;
 
+       snd_dice_stream_destroy_duplex(dice);
        snd_dice_transaction_destroy(dice);
+       fw_unit_put(dice->unit);
+
        mutex_destroy(&dice->mutex);
 }
 
@@ -251,7 +260,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 
        dice = card->private_data;
        dice->card = card;
-       dice->unit = unit;
+       dice->unit = fw_unit_get(unit);
        card->private_free = dice_card_free;
 
        spin_lock_init(&dice->lock);
@@ -305,10 +314,7 @@ static void dice_remove(struct fw_unit *unit)
 {
        struct snd_dice *dice = dev_get_drvdata(&unit->device);
 
-       snd_card_disconnect(dice->card);
-
-       snd_dice_stream_destroy_duplex(dice);
-
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(dice->card);
 }
 
index 3e2ed8e82cbc49b4699c82ad30776ef8a4300253..2682e7e3e5c98511e8bd26fddf452427f1e83a6a 100644 (file)
@@ -173,11 +173,23 @@ end:
        return err;
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void
 efw_card_free(struct snd_card *card)
 {
        struct snd_efw *efw = card->private_data;
 
+       snd_efw_stream_destroy_duplex(efw);
+       snd_efw_transaction_remove_instance(efw);
+       fw_unit_put(efw->unit);
+
+       kfree(efw->resp_buf);
+
        if (efw->card_index >= 0) {
                mutex_lock(&devices_mutex);
                clear_bit(efw->card_index, devices_used);
@@ -185,7 +197,6 @@ efw_card_free(struct snd_card *card)
        }
 
        mutex_destroy(&efw->mutex);
-       kfree(efw->resp_buf);
 }
 
 static int
@@ -218,7 +229,7 @@ efw_probe(struct fw_unit *unit,
        card->private_free = efw_card_free;
 
        efw->card = card;
-       efw->unit = unit;
+       efw->unit = fw_unit_get(unit);
        mutex_init(&efw->mutex);
        spin_lock_init(&efw->lock);
        init_waitqueue_head(&efw->hwdep_wait);
@@ -289,10 +300,7 @@ static void efw_remove(struct fw_unit *unit)
 {
        struct snd_efw *efw = dev_get_drvdata(&unit->device);
 
-       snd_efw_stream_destroy_duplex(efw);
-       snd_efw_transaction_remove_instance(efw);
-
-       snd_card_disconnect(efw->card);
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(efw->card);
 }
 
index 4f440e16366780f097d8c03daeb45e01fb5e7eb0..c55db1bddc80a0ceab4997279643f73840943cef 100644 (file)
@@ -100,17 +100,22 @@ end:
        return err;
 }
 
+/*
+ * This function should be called before starting the stream or after stopping
+ * the streams.
+ */
 static void
 destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
 {
-       stop_stream(efw, stream);
-
-       amdtp_stream_destroy(stream);
+       struct cmp_connection *conn;
 
        if (stream == &efw->tx_stream)
-               cmp_connection_destroy(&efw->out_conn);
+               conn = &efw->out_conn;
        else
-               cmp_connection_destroy(&efw->in_conn);
+               conn = &efw->in_conn;
+
+       amdtp_stream_destroy(stream);
+       cmp_connection_destroy(&efw->out_conn);
 }
 
 static int
@@ -319,12 +324,8 @@ void snd_efw_stream_update_duplex(struct snd_efw *efw)
 
 void snd_efw_stream_destroy_duplex(struct snd_efw *efw)
 {
-       mutex_lock(&efw->mutex);
-
        destroy_stream(efw, &efw->rx_stream);
        destroy_stream(efw, &efw->tx_stream);
-
-       mutex_unlock(&efw->mutex);
 }
 
 void snd_efw_stream_lock_changed(struct snd_efw *efw)
index 5f17b77ee15222ad0e43c3c6b5b13688b386417f..f0e4d502d60482ae8374cf9f830b739eb9e38753 100644 (file)
@@ -26,7 +26,7 @@
 int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
 {
        r->channels_mask = ~0uLL;
-       r->unit = fw_unit_get(unit);
+       r->unit = unit;
        mutex_init(&r->mutex);
        r->allocated = false;
 
@@ -42,7 +42,6 @@ void fw_iso_resources_destroy(struct fw_iso_resources *r)
 {
        WARN_ON(r->allocated);
        mutex_destroy(&r->mutex);
-       fw_unit_put(r->unit);
 }
 EXPORT_SYMBOL(fw_iso_resources_destroy);
 
index bda845afb470703ff0c05bd69f1caac5bfeabbd6..e6757cd8572422813b1627f3c5718ec4c53f2aac 100644 (file)
@@ -171,9 +171,10 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
        }
 
        /* Wait first packet */
-       err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT);
-       if (err < 0)
+       if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
                stop_stream(oxfw, stream);
+               err = -ETIMEDOUT;
+       }
 end:
        return err;
 }
@@ -337,6 +338,10 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
        stop_stream(oxfw, stream);
 }
 
+/*
+ * This function should be called before starting the stream or after stopping
+ * the streams.
+ */
 void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
                                     struct amdtp_stream *stream)
 {
@@ -347,8 +352,6 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
        else
                conn = &oxfw->in_conn;
 
-       stop_stream(oxfw, stream);
-
        amdtp_stream_destroy(stream);
        cmp_connection_destroy(conn);
 }
index 60e5cad0531aeb181d4cc6558f44b4cd6896f070..8c6ce019f437c310043a3686b634def68c92e424 100644 (file)
@@ -104,11 +104,23 @@ end:
        return err;
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void oxfw_card_free(struct snd_card *card)
 {
        struct snd_oxfw *oxfw = card->private_data;
        unsigned int i;
 
+       snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
+       if (oxfw->has_output)
+               snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
+
+       fw_unit_put(oxfw->unit);
+
        for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
                kfree(oxfw->tx_stream_formats[i]);
                kfree(oxfw->rx_stream_formats[i]);
@@ -136,7 +148,7 @@ static int oxfw_probe(struct fw_unit *unit,
        oxfw = card->private_data;
        oxfw->card = card;
        mutex_init(&oxfw->mutex);
-       oxfw->unit = unit;
+       oxfw->unit = fw_unit_get(unit);
        oxfw->device_info = (const struct device_info *)id->driver_data;
        spin_lock_init(&oxfw->lock);
        init_waitqueue_head(&oxfw->hwdep_wait);
@@ -212,12 +224,7 @@ static void oxfw_remove(struct fw_unit *unit)
 {
        struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
 
-       snd_card_disconnect(oxfw->card);
-
-       snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
-       if (oxfw->has_output)
-               snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
-
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(oxfw->card);
 }
 
index 17e49a071af4497e5f39e0341cdee1db229cbc59..b408540798c1648d04a4ec1c36086844326affe1 100644 (file)
@@ -306,11 +306,12 @@ int snd_msndmix_new(struct snd_card *card)
        spin_lock_init(&chip->mixer_lock);
        strcpy(card->mixername, "MSND Pinnacle Mixer");
 
-       for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++)
+       for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++) {
                err = snd_ctl_add(card,
                                  snd_ctl_new1(snd_msnd_controls + idx, chip));
                if (err < 0)
                        return err;
+       }
 
        return 0;
 }
index dfcb5e929f9fc9643701eb33f04aa8efd7f101d3..17c2637d842c1c366275683f30d2a3cb743560b6 100644 (file)
@@ -961,7 +961,6 @@ static int azx_alloc_cmd_io(struct azx *chip)
                dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
        return err;
 }
-EXPORT_SYMBOL_GPL(azx_alloc_cmd_io);
 
 static void azx_init_cmd_io(struct azx *chip)
 {
@@ -1026,7 +1025,6 @@ static void azx_init_cmd_io(struct azx *chip)
        azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
        spin_unlock_irq(&chip->reg_lock);
 }
-EXPORT_SYMBOL_GPL(azx_init_cmd_io);
 
 static void azx_free_cmd_io(struct azx *chip)
 {
@@ -1036,7 +1034,6 @@ static void azx_free_cmd_io(struct azx *chip)
        azx_writeb(chip, CORBCTL, 0);
        spin_unlock_irq(&chip->reg_lock);
 }
-EXPORT_SYMBOL_GPL(azx_free_cmd_io);
 
 static unsigned int azx_command_addr(u32 cmd)
 {
@@ -1167,7 +1164,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
                }
        }
 
-       if (!bus->no_response_fallback)
+       if (bus->no_response_fallback)
                return -1;
 
        if (!chip->polling_mode && chip->poll_count < 2) {
@@ -1316,7 +1313,6 @@ static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
        else
                return azx_corb_send_cmd(bus, val);
 }
-EXPORT_SYMBOL_GPL(azx_send_cmd);
 
 /* get a response */
 static unsigned int azx_get_response(struct hda_bus *bus,
@@ -1330,7 +1326,6 @@ static unsigned int azx_get_response(struct hda_bus *bus,
        else
                return azx_rirb_get_response(bus, addr);
 }
-EXPORT_SYMBOL_GPL(azx_get_response);
 
 #ifdef CONFIG_SND_HDA_DSP_LOADER
 /*
index b680b4ec63313c8b1152390dbbf602018a212952..8ec5289f8e058538892aa04c402a4db9967c94c7 100644 (file)
@@ -687,12 +687,45 @@ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
        return val;
 }
 
+/* is this a stereo widget or a stereo-to-mono mix? */
+static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir)
+{
+       unsigned int wcaps = get_wcaps(codec, nid);
+       hda_nid_t conn;
+
+       if (wcaps & AC_WCAP_STEREO)
+               return true;
+       if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
+               return false;
+       if (snd_hda_get_num_conns(codec, nid) != 1)
+               return false;
+       if (snd_hda_get_connections(codec, nid, &conn, 1) < 0)
+               return false;
+       return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO);
+}
+
 /* initialize the amp value (only at the first time) */
 static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
 {
        unsigned int caps = query_amp_caps(codec, nid, dir);
        int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
-       snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
+
+       if (is_stereo_amps(codec, nid, dir))
+               snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
+       else
+               snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
+}
+
+/* update the amp, doing in stereo or mono depending on NID */
+static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
+                     unsigned int mask, unsigned int val)
+{
+       if (is_stereo_amps(codec, nid, dir))
+               return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
+                                               mask, val);
+       else
+               return snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
+                                               mask, val);
 }
 
 /* calculate amp value mask we can modify;
@@ -732,7 +765,7 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
                return;
 
        val &= mask;
-       snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val);
+       update_amp(codec, nid, dir, idx, mask, val);
 }
 
 static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
@@ -4424,13 +4457,11 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
        has_amp = nid_has_mute(codec, mix, HDA_INPUT);
        for (i = 0; i < nums; i++) {
                if (has_amp)
-                       snd_hda_codec_amp_stereo(codec, mix,
-                                                HDA_INPUT, i,
-                                                0xff, HDA_AMP_MUTE);
+                       update_amp(codec, mix, HDA_INPUT, i,
+                                  0xff, HDA_AMP_MUTE);
                else if (nid_has_volume(codec, conn[i], HDA_OUTPUT))
-                       snd_hda_codec_amp_stereo(codec, conn[i],
-                                                HDA_OUTPUT, 0,
-                                                0xff, HDA_AMP_MUTE);
+                       update_amp(codec, conn[i], HDA_OUTPUT, 0,
+                                  0xff, HDA_AMP_MUTE);
        }
 }
 
index 36d2f20db7a4201b999155e759e3e22b6fe3f753..a8a1e14272a1e574302da56ad0ad7540bf8fd60d 100644 (file)
@@ -1966,7 +1966,7 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* Panther Point */
        { PCI_DEVICE(0x8086, 0x1e20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* Lynx Point */
        { PCI_DEVICE(0x8086, 0x8c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -1989,7 +1989,7 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
        /* Sunrise Point */
        { PCI_DEVICE(0x8086, 0xa170),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
        /* Sunrise Point-LP */
        { PCI_DEVICE(0x8086, 0x9d70),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
index ce5a6da834199bd2acd7e6ee18fd123b4f078820..05e19f78b4cb8689ff8ac1b0b4f699bdbf5759da 100644 (file)
@@ -134,13 +134,38 @@ static void print_amp_caps(struct snd_info_buffer *buffer,
                    (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT);
 }
 
+/* is this a stereo widget or a stereo-to-mono mix? */
+static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid,
+                          int dir, unsigned int wcaps, int indices)
+{
+       hda_nid_t conn;
+
+       if (wcaps & AC_WCAP_STEREO)
+               return true;
+       /* check for a stereo-to-mono mix; it must be:
+        * only a single connection, only for input, and only a mixer widget
+        */
+       if (indices != 1 || dir != HDA_INPUT ||
+           get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
+               return false;
+
+       if (snd_hda_get_raw_connections(codec, nid, &conn, 1) < 0)
+               return false;
+       /* the connection source is a stereo? */
+       wcaps = snd_hda_param_read(codec, conn, AC_PAR_AUDIO_WIDGET_CAP);
+       return !!(wcaps & AC_WCAP_STEREO);
+}
+
 static void print_amp_vals(struct snd_info_buffer *buffer,
                           struct hda_codec *codec, hda_nid_t nid,
-                          int dir, int stereo, int indices)
+                          int dir, unsigned int wcaps, int indices)
 {
        unsigned int val;
+       bool stereo;
        int i;
 
+       stereo = is_stereo_amps(codec, nid, dir, wcaps, indices);
+
        dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
        for (i = 0; i < indices; i++) {
                snd_iprintf(buffer, " [");
@@ -757,12 +782,10 @@ static void print_codec_info(struct snd_info_entry *entry,
                            (codec->single_adc_amp &&
                             wid_type == AC_WID_AUD_IN))
                                print_amp_vals(buffer, codec, nid, HDA_INPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              1);
+                                              wid_caps, 1);
                        else
                                print_amp_vals(buffer, codec, nid, HDA_INPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              conn_len);
+                                              wid_caps, conn_len);
                }
                if (wid_caps & AC_WCAP_OUT_AMP) {
                        snd_iprintf(buffer, "  Amp-Out caps: ");
@@ -771,11 +794,10 @@ static void print_codec_info(struct snd_info_entry *entry,
                        if (wid_type == AC_WID_PIN &&
                            codec->pin_amp_workaround)
                                print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              conn_len);
+                                              wid_caps, conn_len);
                        else
                                print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
-                                              wid_caps & AC_WCAP_STEREO, 1);
+                                              wid_caps, 1);
                }
 
                switch (wid_type) {
index 1589c9bcce3e15a230f87d352f2ae165252c358d..dd2b3d92071f698f41a75d2d7b7877eb6b357c00 100644 (file)
@@ -393,6 +393,7 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
        SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
        SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
+       SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81),
        SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42),
        SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
        {} /* terminator */
@@ -584,6 +585,7 @@ static int patch_cs420x(struct hda_codec *codec)
                return -ENOMEM;
 
        spec->gen.automute_hook = cs_automute;
+       codec->single_adc_amp = 1;
 
        snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
                           cs420x_fixups);
index fd3ed18670e9c4005d115a26f6410c7efd4faff8..da67ea8645a6e8462f23b8f8b1e96044e66812f7 100644 (file)
@@ -223,6 +223,7 @@ enum {
        CXT_PINCFG_LENOVO_TP410,
        CXT_PINCFG_LEMOTE_A1004,
        CXT_PINCFG_LEMOTE_A1205,
+       CXT_PINCFG_COMPAQ_CQ60,
        CXT_FIXUP_STEREO_DMIC,
        CXT_FIXUP_INC_MIC_BOOST,
        CXT_FIXUP_HEADPHONE_MIC_PIN,
@@ -660,6 +661,15 @@ static const struct hda_fixup cxt_fixups[] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = cxt_pincfg_lemote,
        },
+       [CXT_PINCFG_COMPAQ_CQ60] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* 0x17 was falsely set up as a mic, it should 0x1d */
+                       { 0x17, 0x400001f0 },
+                       { 0x1d, 0x97a70120 },
+                       { }
+               }
+       },
        [CXT_FIXUP_STEREO_DMIC] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cxt_fixup_stereo_dmic,
@@ -769,6 +779,7 @@ static const struct hda_model_fixup cxt5047_fixup_models[] = {
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
+       SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
        {}
 };
index b2b24a8b3dac8c49d2bb55c3142eecd967e73608..74382137b9f5abcd67b9c4c44581c9a80f26d17d 100644 (file)
@@ -396,7 +396,7 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
 {
        /* We currently only handle front, HP */
        static hda_nid_t pins[] = {
-               0x0f, 0x10, 0x14, 0x15, 0
+               0x0f, 0x10, 0x14, 0x15, 0x17, 0
        };
        hda_nid_t *p;
        for (p = pins; *p; p++)
@@ -5036,6 +5036,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
@@ -5209,6 +5210,13 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x17, 0x40000000},
                {0x1d, 0x40700001},
                {0x21, 0x02211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
+               {0x12, 0x90a60170},
+               {0x14, 0x90170140},
+               {0x17, 0x40000000},
+               {0x1d, 0x40700001},
+               {0x21, 0x02211050}),
        SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
                {0x12, 0x90a60130},
                {0x13, 0x40000000},
index 6d36c5b7880504457430718a8f23f2dbc0e9a9ba..87eff3173ce924ae89596068b5bf8dcd38e7482e 100644 (file)
@@ -79,6 +79,7 @@ enum {
        STAC_ALIENWARE_M17X,
        STAC_92HD89XX_HP_FRONT_JACK,
        STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
+       STAC_92HD73XX_ASUS_MOBO,
        STAC_92HD73XX_MODELS
 };
 
@@ -1911,7 +1912,18 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
        [STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs,
-       }
+       },
+       [STAC_92HD73XX_ASUS_MOBO] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* enable 5.1 and SPDIF out */
+                       { 0x0c, 0x01014411 },
+                       { 0x0d, 0x01014410 },
+                       { 0x0e, 0x01014412 },
+                       { 0x22, 0x014b1180 },
+                       { }
+               }
+       },
 };
 
 static const struct hda_model_fixup stac92hd73xx_models[] = {
@@ -1923,6 +1935,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = {
        { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
        { .id = STAC_DELL_EQ, .name = "dell-eq" },
        { .id = STAC_ALIENWARE_M17X, .name = "alienware" },
+       { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
        {}
 };
 
@@ -1975,6 +1988,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
                                "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
                                "unknown HP", STAC_92HD89XX_HP_FRONT_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_ASUSTEK, 0x83f8, "ASUS AT4NM10",
+                     STAC_92HD73XX_ASUS_MOBO),
        {} /* terminator */
 };
 
index f5ad214663f98b4dbbdc3c2a4180d6142d09688c..8de836165cf2ed1978c4846ac56e84bcbae4e6d1 100644 (file)
@@ -46,8 +46,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
-#include <asm/mach-types.h>
-
 #include "../codecs/wm8731.h"
 #include "atmel-pcm.h"
 #include "atmel_ssc_dai.h"
@@ -171,9 +169,7 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
        int ret;
 
        if (!np) {
-               if (!(machine_is_at91sam9g20ek() ||
-                       machine_is_at91sam9g20ek_2mmc()))
-                       return -ENODEV;
+               return -ENODEV;
        }
 
        ret = atmel_ssc_set_audio(0);
@@ -210,39 +206,37 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
        card->dev = &pdev->dev;
 
        /* Parse device node info */
-       if (np) {
-               ret = snd_soc_of_parse_card_name(card, "atmel,model");
-               if (ret)
-                       goto err;
-
-               ret = snd_soc_of_parse_audio_routing(card,
-                       "atmel,audio-routing");
-               if (ret)
-                       goto err;
-
-               /* Parse codec info */
-               at91sam9g20ek_dai.codec_name = NULL;
-               codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
-               if (!codec_np) {
-                       dev_err(&pdev->dev, "codec info missing\n");
-                       return -EINVAL;
-               }
-               at91sam9g20ek_dai.codec_of_node = codec_np;
-
-               /* Parse dai and platform info */
-               at91sam9g20ek_dai.cpu_dai_name = NULL;
-               at91sam9g20ek_dai.platform_name = NULL;
-               cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
-               if (!cpu_np) {
-                       dev_err(&pdev->dev, "dai and pcm info missing\n");
-                       return -EINVAL;
-               }
-               at91sam9g20ek_dai.cpu_of_node = cpu_np;
-               at91sam9g20ek_dai.platform_of_node = cpu_np;
-
-               of_node_put(codec_np);
-               of_node_put(cpu_np);
+       ret = snd_soc_of_parse_card_name(card, "atmel,model");
+       if (ret)
+               goto err;
+
+       ret = snd_soc_of_parse_audio_routing(card,
+               "atmel,audio-routing");
+       if (ret)
+               goto err;
+
+       /* Parse codec info */
+       at91sam9g20ek_dai.codec_name = NULL;
+       codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+       if (!codec_np) {
+               dev_err(&pdev->dev, "codec info missing\n");
+               return -EINVAL;
+       }
+       at91sam9g20ek_dai.codec_of_node = codec_np;
+
+       /* Parse dai and platform info */
+       at91sam9g20ek_dai.cpu_dai_name = NULL;
+       at91sam9g20ek_dai.platform_name = NULL;
+       cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
+       if (!cpu_np) {
+               dev_err(&pdev->dev, "dai and pcm info missing\n");
+               return -EINVAL;
        }
+       at91sam9g20ek_dai.cpu_of_node = cpu_np;
+       at91sam9g20ek_dai.platform_of_node = cpu_np;
+
+       of_node_put(codec_np);
+       of_node_put(cpu_np);
 
        ret = snd_soc_register_card(card);
        if (ret) {
index 7b7fbcd49e5e424c25e47d9e6a1aee77065358d5..c7cd60f009e93e69ef2220eec3eb6ec97a9e6500 100644 (file)
@@ -16,7 +16,7 @@ config SND_EP93XX_SOC_AC97
 
 config SND_EP93XX_SOC_SNAPPERCL15
         tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
-        depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
+        depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C
         select SND_EP93XX_SOC_I2S
         select SND_SOC_TLV320AIC23_I2C
         help
index 064e6c18e10923fd75609b750405dbc33f9db6af..ea9f0e31f9d40d4cf4d8e626371698cb857fcb3a 100644 (file)
@@ -69,7 +69,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_MAX98088 if I2C
        select SND_SOC_MAX98090 if I2C
        select SND_SOC_MAX98095 if I2C
-       select SND_SOC_MAX98357A
+       select SND_SOC_MAX98357A if GPIOLIB
        select SND_SOC_MAX9850 if I2C
        select SND_SOC_MAX9768 if I2C
        select SND_SOC_MAX9877 if I2C
index b67480f1b1aa4a7dcfb6c03b10b2ecd826875989..4373ada95648e6890f013582b97c355b45e76dd1 100644 (file)
@@ -317,7 +317,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
-       unsigned int deemph = ucontrol->value.enumerated.item[0];
+       unsigned int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
@@ -333,7 +333,7 @@ static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = adav80x->deemph;
+       ucontrol->value.integer.value[0] = adav80x->deemph;
        return 0;
 };
 
index 70861c7b1631ab577acf506f8af18f2386a0852a..81b54a270bd8f800637108d027f9edfffb464d04 100644 (file)
@@ -76,7 +76,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
@@ -92,7 +92,7 @@ static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = ak4641->deemph;
+       ucontrol->value.integer.value[0] = ak4641->deemph;
        return 0;
 };
 
index 632e89f793a78d2691dfb2e33b3516f0f483aeee..2a58b1dccd2f18cb41221c45ac4d026e731240c9 100644 (file)
@@ -343,25 +343,25 @@ static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route ak4671_intercon[] = {
-       {"DAC Left", "NULL", "PMPLL"},
-       {"DAC Right", "NULL", "PMPLL"},
-       {"ADC Left", "NULL", "PMPLL"},
-       {"ADC Right", "NULL", "PMPLL"},
+       {"DAC Left", NULL, "PMPLL"},
+       {"DAC Right", NULL, "PMPLL"},
+       {"ADC Left", NULL, "PMPLL"},
+       {"ADC Right", NULL, "PMPLL"},
 
        /* Outputs */
-       {"LOUT1", "NULL", "LOUT1 Mixer"},
-       {"ROUT1", "NULL", "ROUT1 Mixer"},
-       {"LOUT2", "NULL", "LOUT2 Mix Amp"},
-       {"ROUT2", "NULL", "ROUT2 Mix Amp"},
-       {"LOUT3", "NULL", "LOUT3 Mixer"},
-       {"ROUT3", "NULL", "ROUT3 Mixer"},
+       {"LOUT1", NULL, "LOUT1 Mixer"},
+       {"ROUT1", NULL, "ROUT1 Mixer"},
+       {"LOUT2", NULL, "LOUT2 Mix Amp"},
+       {"ROUT2", NULL, "ROUT2 Mix Amp"},
+       {"LOUT3", NULL, "LOUT3 Mixer"},
+       {"ROUT3", NULL, "ROUT3 Mixer"},
 
        {"LOUT1 Mixer", "DACL", "DAC Left"},
        {"ROUT1 Mixer", "DACR", "DAC Right"},
        {"LOUT2 Mixer", "DACHL", "DAC Left"},
        {"ROUT2 Mixer", "DACHR", "DAC Right"},
-       {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"},
-       {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"},
+       {"LOUT2 Mix Amp", NULL, "LOUT2 Mixer"},
+       {"ROUT2 Mix Amp", NULL, "ROUT2 Mixer"},
        {"LOUT3 Mixer", "DACSL", "DAC Left"},
        {"ROUT3 Mixer", "DACSR", "DAC Right"},
 
@@ -381,18 +381,18 @@ static const struct snd_soc_dapm_route ak4671_intercon[] = {
        {"LIN2", NULL, "Mic Bias"},
        {"RIN2", NULL, "Mic Bias"},
 
-       {"ADC Left", "NULL", "LIN MUX"},
-       {"ADC Right", "NULL", "RIN MUX"},
+       {"ADC Left", NULL, "LIN MUX"},
+       {"ADC Right", NULL, "RIN MUX"},
 
        /* Analog Loops */
-       {"LIN1 Mixing Circuit", "NULL", "LIN1"},
-       {"RIN1 Mixing Circuit", "NULL", "RIN1"},
-       {"LIN2 Mixing Circuit", "NULL", "LIN2"},
-       {"RIN2 Mixing Circuit", "NULL", "RIN2"},
-       {"LIN3 Mixing Circuit", "NULL", "LIN3"},
-       {"RIN3 Mixing Circuit", "NULL", "RIN3"},
-       {"LIN4 Mixing Circuit", "NULL", "LIN4"},
-       {"RIN4 Mixing Circuit", "NULL", "RIN4"},
+       {"LIN1 Mixing Circuit", NULL, "LIN1"},
+       {"RIN1 Mixing Circuit", NULL, "RIN1"},
+       {"LIN2 Mixing Circuit", NULL, "LIN2"},
+       {"RIN2 Mixing Circuit", NULL, "RIN2"},
+       {"LIN3 Mixing Circuit", NULL, "LIN3"},
+       {"RIN3 Mixing Circuit", NULL, "RIN3"},
+       {"LIN4 Mixing Circuit", NULL, "LIN4"},
+       {"RIN4 Mixing Circuit", NULL, "RIN4"},
 
        {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"},
        {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"},
index 79a4efcb894c192c763c649083081e4c75fbece3..7d3a6accaf9a4a583dcacbb934e275092933c026 100644 (file)
@@ -286,7 +286,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = cs4271->deemph;
+       ucontrol->value.integer.value[0] = cs4271->deemph;
        return 0;
 }
 
@@ -296,7 +296,7 @@ static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 
-       cs4271->deemph = ucontrol->value.enumerated.item[0];
+       cs4271->deemph = ucontrol->value.integer.value[0];
        return cs4271_set_deemph(codec);
 }
 
index ffe96175a8a5ac62ee4721c1f17a54c305d447c7..911c26c705fc8d226e819d469c669b72f989517a 100644 (file)
@@ -876,11 +876,11 @@ static const struct snd_soc_dapm_widget da732x_dapm_widgets[] = {
 
 static const struct snd_soc_dapm_route da732x_dapm_routes[] = {
        /* Inputs */
-       {"AUX1L PGA", "NULL", "AUX1L"},
-       {"AUX1R PGA", "NULL", "AUX1R"},
+       {"AUX1L PGA", NULL, "AUX1L"},
+       {"AUX1R PGA", NULL, "AUX1R"},
        {"MIC1 PGA", NULL, "MIC1"},
-       {"MIC2 PGA", "NULL", "MIC2"},
-       {"MIC3 PGA", "NULL", "MIC3"},
+       {"MIC2 PGA", NULL, "MIC2"},
+       {"MIC3 PGA", NULL, "MIC3"},
 
        /* Capture Path */
        {"ADC1 Left MUX", "MIC1", "MIC1 PGA"},
index f27325155acef31e1f4a7fff4ea970b9405ca8a7..c5f35a07e8e48106335df49153acd81e104f7aa9 100644 (file)
@@ -120,7 +120,7 @@ static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = es8328->deemph;
+       ucontrol->value.integer.value[0] = es8328->deemph;
        return 0;
 }
 
@@ -129,7 +129,7 @@ static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret;
 
        if (deemph > 1)
index 1806333ea29e5a6b49e2a0adb8c58257d34b7508..e9e6efbc21dd527299fb459ec01903fa8c24dae2 100644 (file)
  * max98357a.c -- MAX98357A ALSA SoC Codec driver
  */
 
-#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
 #include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
 
 #define DRV_NAME "max98357a"
 
index a722a023c26280a3c89f7a198e95c818f0c2fe6a..477e13d309713e56a5a4416d054350185fea0007 100644 (file)
@@ -118,7 +118,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = priv->deemph;
+       ucontrol->value.integer.value[0] = priv->deemph;
 
        return 0;
 }
@@ -129,7 +129,7 @@ static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       priv->deemph = ucontrol->value.enumerated.item[0];
+       priv->deemph = ucontrol->value.integer.value[0];
 
        return pcm1681_set_deemph(codec);
 }
index f374840a5a7ce376272d8f7e3290f91c099cb19f..9b541e52da8c77da4134fdf8e0c551d35a2a402b 100644 (file)
@@ -1198,7 +1198,7 @@ static struct dmi_system_id dmi_dell_dino[] = {
                .ident = "Dell Dino",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_BOARD_NAME, "0144P8")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343")
                }
        },
        { }
index e1a4a45c57e229b12dcd174ac8453f8772b6e3b1..fd102613d20d8747c7554f5a3882c027fd0024c8 100644 (file)
@@ -225,7 +225,6 @@ static bool rt5670_volatile_register(struct device *dev, unsigned int reg)
        case RT5670_ADC_EQ_CTRL1:
        case RT5670_EQ_CTRL1:
        case RT5670_ALC_CTRL_1:
-       case RT5670_IRQ_CTRL1:
        case RT5670_IRQ_CTRL2:
        case RT5670_INT_IRQ_ST:
        case RT5670_IL_CMD:
@@ -2703,6 +2702,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
 
        regmap_write(rt5670->regmap, RT5670_RESET, 0);
 
+       regmap_read(rt5670->regmap, RT5670_VENDOR_ID, &val);
+       if (val >= 4)
+               regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0980);
+       else
+               regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0d00);
+
        ret = regmap_register_patch(rt5670->regmap, init_list,
                                    ARRAY_SIZE(init_list));
        if (ret != 0)
index 5d0bb8748dd1df5cd6a262d7e3a925fe4b4b5efd..fb9c20eace3fbe9d7bb009862a17c0e8644ec296 100644 (file)
@@ -3284,8 +3284,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "IB45 Bypass Mux", "Bypass", "IB45 Mux" },
        { "IB45 Bypass Mux", "Pass SRC", "IB45 Mux" },
 
-       { "IB6 Mux", "IF1 DAC 6", "IF1 DAC6" },
-       { "IB6 Mux", "IF2 DAC 6", "IF2 DAC6" },
+       { "IB6 Mux", "IF1 DAC 6", "IF1 DAC6 Mux" },
+       { "IB6 Mux", "IF2 DAC 6", "IF2 DAC6 Mux" },
        { "IB6 Mux", "SLB DAC 6", "SLB DAC6" },
        { "IB6 Mux", "STO4 ADC MIX L", "Stereo4 ADC MIXL" },
        { "IB6 Mux", "IF4 DAC L", "IF4 DAC L" },
@@ -3293,8 +3293,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "IB6 Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" },
        { "IB6 Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" },
 
-       { "IB7 Mux", "IF1 DAC 7", "IF1 DAC7" },
-       { "IB7 Mux", "IF2 DAC 7", "IF2 DAC7" },
+       { "IB7 Mux", "IF1 DAC 7", "IF1 DAC7 Mux" },
+       { "IB7 Mux", "IF2 DAC 7", "IF2 DAC7 Mux" },
        { "IB7 Mux", "SLB DAC 7", "SLB DAC7" },
        { "IB7 Mux", "STO4 ADC MIX R", "Stereo4 ADC MIXR" },
        { "IB7 Mux", "IF4 DAC R", "IF4 DAC R" },
@@ -3635,15 +3635,15 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "DAC1 FS", NULL, "DAC1 MIXL" },
        { "DAC1 FS", NULL, "DAC1 MIXR" },
 
-       { "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2" },
-       { "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2" },
+       { "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2 Mux" },
+       { "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2 Mux" },
        { "DAC2 L Mux", "IF3 DAC L", "IF3 DAC L" },
        { "DAC2 L Mux", "IF4 DAC L", "IF4 DAC L" },
        { "DAC2 L Mux", "SLB DAC 2", "SLB DAC2" },
        { "DAC2 L Mux", "OB 2", "OutBound2" },
 
-       { "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3" },
-       { "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3" },
+       { "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3 Mux" },
+       { "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3 Mux" },
        { "DAC2 R Mux", "IF3 DAC R", "IF3 DAC R" },
        { "DAC2 R Mux", "IF4 DAC R", "IF4 DAC R" },
        { "DAC2 R Mux", "SLB DAC 3", "SLB DAC3" },
@@ -3651,29 +3651,29 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "DAC2 R Mux", "Haptic Generator", "Haptic Generator" },
        { "DAC2 R Mux", "VAD ADC", "VAD ADC Mux" },
 
-       { "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4" },
-       { "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4" },
+       { "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4 Mux" },
+       { "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4 Mux" },
        { "DAC3 L Mux", "IF3 DAC L", "IF3 DAC L" },
        { "DAC3 L Mux", "IF4 DAC L", "IF4 DAC L" },
        { "DAC3 L Mux", "SLB DAC 4", "SLB DAC4" },
        { "DAC3 L Mux", "OB 4", "OutBound4" },
 
-       { "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC4" },
-       { "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC4" },
+       { "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC5 Mux" },
+       { "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC5 Mux" },
        { "DAC3 R Mux", "IF3 DAC R", "IF3 DAC R" },
        { "DAC3 R Mux", "IF4 DAC R", "IF4 DAC R" },
        { "DAC3 R Mux", "SLB DAC 5", "SLB DAC5" },
        { "DAC3 R Mux", "OB 5", "OutBound5" },
 
-       { "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6" },
-       { "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6" },
+       { "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6 Mux" },
+       { "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6 Mux" },
        { "DAC4 L Mux", "IF3 DAC L", "IF3 DAC L" },
        { "DAC4 L Mux", "IF4 DAC L", "IF4 DAC L" },
        { "DAC4 L Mux", "SLB DAC 6", "SLB DAC6" },
        { "DAC4 L Mux", "OB 6", "OutBound6" },
 
-       { "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7" },
-       { "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7" },
+       { "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7 Mux" },
+       { "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7 Mux" },
        { "DAC4 R Mux", "IF3 DAC R", "IF3 DAC R" },
        { "DAC4 R Mux", "IF4 DAC R", "IF4 DAC R" },
        { "DAC4 R Mux", "SLB DAC 7", "SLB DAC7" },
index e182e6569bbd138713ec0047de606136254d81c4..3593a1496056d2aa7648142c67bd7952d5b589f6 100644 (file)
@@ -1151,13 +1151,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
                /* Enable VDDC charge pump */
                ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP;
        } else if (vddio >= 3100 && vdda >= 3100) {
-               /*
-                * if vddio and vddd > 3.1v,
-                * charge pump should be clean before set ana_pwr
-                */
-               snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
-                               SGTL5000_VDDC_CHRGPMP_POWERUP, 0);
-
+               ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP;
                /* VDDC use VDDIO rail */
                lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD;
                lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO <<
index 47b257e4180965f38be5c393cab204945f444b7f..82095d6cd07036d0ad81bf63cdc9e41746c630c3 100644 (file)
@@ -538,8 +538,8 @@ static const struct snd_soc_dapm_route sn95031_audio_map[] = {
        /* speaker map */
        { "IHFOUTL", NULL, "Speaker Rail"},
        { "IHFOUTR", NULL, "Speaker Rail"},
-       { "IHFOUTL", "NULL", "Speaker Left Playback"},
-       { "IHFOUTR", "NULL", "Speaker Right Playback"},
+       { "IHFOUTL", NULL, "Speaker Left Playback"},
+       { "IHFOUTR", NULL, "Speaker Right Playback"},
        { "Speaker Left Playback", NULL, "Speaker Left Filter"},
        { "Speaker Right Playback", NULL, "Speaker Right Filter"},
        { "Speaker Left Filter", NULL, "IHFDAC Left"},
index 3a1343fa109b482860811baea1566d354e574399..007a0e3bc2735c0c6f9d8325f15445657fcfd374 100644 (file)
@@ -106,13 +106,11 @@ static const struct reg_default sta32x_regs[] = {
 };
 
 static const struct regmap_range sta32x_write_regs_range[] = {
-       regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
-       regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+       regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
 };
 
 static const struct regmap_range sta32x_read_regs_range[] = {
-       regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
-       regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+       regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
 };
 
 static const struct regmap_range sta32x_volatile_regs_range[] = {
index 249ef5c4c762795bfb19f3545ce8398868f4dba3..32942bed34b1e9bb67227adddd5c662b92aa2a9b 100644 (file)
@@ -281,7 +281,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = priv->deemph;
+       ucontrol->value.integer.value[0] = priv->deemph;
 
        return 0;
 }
@@ -292,7 +292,7 @@ static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       priv->deemph = ucontrol->value.enumerated.item[0];
+       priv->deemph = ucontrol->value.integer.value[0];
 
        return tas5086_set_deemph(codec);
 }
index 8d9de49a50524bb4e88ebd62cb580e17239b07d6..21d5402e343fbcdd7a433931bc9a78d0edac45e9 100644 (file)
@@ -610,7 +610,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       ucontrol->value.enumerated.item[0] = wm2000->anc_active;
+       ucontrol->value.integer.value[0] = wm2000->anc_active;
 
        return 0;
 }
@@ -620,7 +620,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
-       int anc_active = ucontrol->value.enumerated.item[0];
+       int anc_active = ucontrol->value.integer.value[0];
        int ret;
 
        if (anc_active > 1)
@@ -643,7 +643,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       ucontrol->value.enumerated.item[0] = wm2000->spk_ena;
+       ucontrol->value.integer.value[0] = wm2000->spk_ena;
 
        return 0;
 }
@@ -653,7 +653,7 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
-       int val = ucontrol->value.enumerated.item[0];
+       int val = ucontrol->value.integer.value[0];
        int ret;
 
        if (val > 1)
index 098c143f44d653d99c33f36e02edde9eca6600d8..c6d10533e2bde5170f8ac963333b52c62782c27f 100644 (file)
@@ -125,7 +125,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8731->deemph;
+       ucontrol->value.integer.value[0] = wm8731->deemph;
 
        return 0;
 }
@@ -135,7 +135,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret = 0;
 
        if (deemph > 1)
index dde462c082be0eb6124e0f881b9a1ed936e34c77..04b04f8e147c6bdeada6decdca981a026ce57afa 100644 (file)
@@ -442,7 +442,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8903->deemph;
+       ucontrol->value.integer.value[0] = wm8903->deemph;
 
        return 0;
 }
@@ -452,7 +452,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret = 0;
 
        if (deemph > 1)
index d3b3f57668ccae412f0a75d61f91f9f34f1f0fb0..215e93c1ddf0358f42dc5581fd01b1d9a3d7e1e0 100644 (file)
@@ -525,7 +525,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8904->deemph;
+       ucontrol->value.integer.value[0] = wm8904->deemph;
        return 0;
 }
 
@@ -534,7 +534,7 @@ static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index 1ab2d462afadfb24a7205638a779bb0152eb702a..00bec915d6522152a5d40dcc3d2df52ef16424eb 100644 (file)
@@ -393,7 +393,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8955->deemph;
+       ucontrol->value.integer.value[0] = wm8955->deemph;
        return 0;
 }
 
@@ -402,7 +402,7 @@ static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index cf8fecf97f2c7ee06fff2741bea074bd32ceb7fc..3035d98564156746bc4e814f744e1ea0f236564a 100644 (file)
@@ -184,7 +184,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8960->deemph;
+       ucontrol->value.integer.value[0] = wm8960->deemph;
        return 0;
 }
 
@@ -193,7 +193,7 @@ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index 9517571e820d9576b9505be863a73f3c02116cb8..98c9525bd751fbacb0eec07f6465869cbc3e2aa5 100644 (file)
@@ -180,7 +180,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val = ucontrol->value.enumerated.item[0];
+       unsigned int val = ucontrol->value.integer.value[0];
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mixer, mask, shift, old;
@@ -193,7 +193,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&wm9712->lock);
        old = wm9712->hp_mixer[mixer];
-       if (ucontrol->value.enumerated.item[0])
+       if (ucontrol->value.integer.value[0])
                wm9712->hp_mixer[mixer] |= mask;
        else
                wm9712->hp_mixer[mixer] &= ~mask;
@@ -231,7 +231,7 @@ static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
        mixer = mc->shift >> 8;
        shift = mc->shift & 0xff;
 
-       ucontrol->value.enumerated.item[0] =
+       ucontrol->value.integer.value[0] =
                (wm9712->hp_mixer[mixer] >> shift) & 1;
 
        return 0;
index 68222917b396666b975cc2aa96e13d983bf52fc2..79552953e1bdc607e4d25c95aa5ab473637be6cc 100644 (file)
@@ -255,7 +255,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val = ucontrol->value.enumerated.item[0];
+       unsigned int val = ucontrol->value.integer.value[0];
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mixer, mask, shift, old;
@@ -268,7 +268,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&wm9713->lock);
        old = wm9713->hp_mixer[mixer];
-       if (ucontrol->value.enumerated.item[0])
+       if (ucontrol->value.integer.value[0])
                wm9713->hp_mixer[mixer] |= mask;
        else
                wm9713->hp_mixer[mixer] &= ~mask;
@@ -306,7 +306,7 @@ static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol,
        mixer = mc->shift >> 8;
        shift = mc->shift & 0xff;
 
-       ucontrol->value.enumerated.item[0] =
+       ucontrol->value.integer.value[0] =
                (wm9713->hp_mixer[mixer] >> shift) & 1;
 
        return 0;
index 75870c0ea2c9f613d9b4ebe3e10efd53430e5363..91eb3aef7f02f84d4dd2ec92cb46a9ce2ad67e55 100644 (file)
@@ -1049,7 +1049,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
                                enum spdif_txrate index, bool round)
 {
        const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
-       bool is_sysclk = clk == spdif_priv->sysclk;
+       bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
        u64 rate_ideal, rate_actual, sub;
        u32 sysclk_dfmin, sysclk_dfmax;
        u32 txclk_df, sysclk_df, arate;
@@ -1143,7 +1143,7 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
                        spdif_priv->txclk_src[index], rate[index]);
        dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n",
                        spdif_priv->txclk_df[index], rate[index]);
-       if (spdif_priv->txclk[index] == spdif_priv->sysclk)
+       if (clk_is_match(spdif_priv->txclk[index], spdif_priv->sysclk))
                dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n",
                                spdif_priv->sysclk_df[index], rate[index]);
        dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n",
index 2595611e8a6ded3876345767bde2ce51e079c9ee..6b0c8f717ec2c0781af066cfb1bc3bcce8567791 100644 (file)
@@ -603,17 +603,20 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
        factor = (div2 + 1) * (7 * psr + 1) * 2;
 
        for (i = 0; i < 255; i++) {
-               /* The bclk rate must be smaller than 1/5 sysclk rate */
-               if (factor * (i + 1) < 5)
-                       continue;
-
-               tmprate = freq * factor * (i + 2);
+               tmprate = freq * factor * (i + 1);
 
                if (baudclk_is_used)
                        clkrate = clk_get_rate(ssi_private->baudclk);
                else
                        clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
 
+               /*
+                * Hardware limitation: The bclk rate must be
+                * never greater than 1/5 IPG clock rate
+                */
+               if (clkrate * 5 > clk_get_rate(ssi_private->clk))
+                       continue;
+
                clkrate /= factor;
                afreq = clkrate / (i + 1);
 
@@ -1224,7 +1227,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
        ssi_private->dma_params_tx.addr = ssi_private->ssi_phys + CCSR_SSI_STX0;
        ssi_private->dma_params_rx.addr = ssi_private->ssi_phys + CCSR_SSI_SRX0;
 
-       ret = !of_property_read_u32_array(np, "dmas", dmas, 4);
+       ret = of_property_read_u32_array(np, "dmas", dmas, 4);
        if (ssi_private->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) {
                ssi_private->use_dual_fifo = true;
                /* When using dual fifo mode, we need to keep watermark
index f7c6734bd5daee1dafd76ba8b6feafa05b2a6c52..fb550b5869d21f73307d36d2edc88ebcffa61f0c 100644 (file)
@@ -372,6 +372,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
                            strlen(dai_link->cpu_dai_name)   +
                            strlen(dai_link->codec_dai_name) + 2,
                            GFP_KERNEL);
+       if (!name) {
+               ret = -ENOMEM;
+               goto dai_link_of_err;
+       }
+
        sprintf(name, "%s-%s", dai_link->cpu_dai_name,
                                dai_link->codec_dai_name);
        dai_link->name = dai_link->stream_name = name;
index dfebfdd5eb2aaa65e1f21aa5d65d2c9052486b75..daecc58f28afafb28c8172649355ff9b30749783 100644 (file)
@@ -150,7 +150,7 @@ enum sst_cmd_type {
 
 enum sst_task {
        SST_TASK_SBA = 1,
-       SST_TASK_MMX,
+       SST_TASK_MMX = 3,
 };
 
 enum sst_type {
index c42ffae5fe9f6acab9ebe5723862c4e3a3b4bf8d..402b728c0a06479213425c2daf88eafe4caa2877 100644 (file)
@@ -207,9 +207,6 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
                module = (void *)module + sizeof(*module) + module->mod_size;
        }
 
-       /* allocate scratch mem regions */
-       sst_block_alloc_scratch(dsp);
-
        return 0;
 }
 
index 394af5684c05e37403b50b67ebaa7ead69d14f1f..863a9ca34b8e37fee393930812845e672e717b8f 100644 (file)
@@ -1732,6 +1732,7 @@ static void sst_hsw_drop_all(struct sst_hsw *hsw)
 int sst_hsw_dsp_load(struct sst_hsw *hsw)
 {
        struct sst_dsp *dsp = hsw->dsp;
+       struct sst_fw *sst_fw, *t;
        int ret;
 
        dev_dbg(hsw->dev, "loading audio DSP....");
@@ -1748,12 +1749,17 @@ int sst_hsw_dsp_load(struct sst_hsw *hsw)
                return ret;
        }
 
-       ret = sst_fw_reload(hsw->sst_fw);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: SST FW reload failed\n");
-               sst_dsp_dma_put_channel(dsp);
-               return -ENOMEM;
+       list_for_each_entry_safe_reverse(sst_fw, t, &dsp->fw_list, list) {
+               ret = sst_fw_reload(sst_fw);
+               if (ret < 0) {
+                       dev_err(hsw->dev, "error: SST FW reload failed\n");
+                       sst_dsp_dma_put_channel(dsp);
+                       return -ENOMEM;
+               }
        }
+       ret = sst_block_alloc_scratch(hsw->dsp);
+       if (ret < 0)
+               return -EINVAL;
 
        sst_dsp_dma_put_channel(dsp);
        return 0;
@@ -1809,12 +1815,17 @@ int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw)
 
 int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw)
 {
-       sst_fw_unload(hsw->sst_fw);
-       sst_block_free_scratch(hsw->dsp);
+       struct sst_fw *sst_fw, *t;
+       struct sst_dsp *dsp = hsw->dsp;
+
+       list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) {
+               sst_fw_unload(sst_fw);
+       }
+       sst_block_free_scratch(dsp);
 
        hsw->boot_complete = false;
 
-       sst_dsp_sleep(hsw->dsp);
+       sst_dsp_sleep(dsp);
 
        return 0;
 }
@@ -1943,6 +1954,11 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
                goto fw_err;
        }
 
+       /* allocate scratch mem regions */
+       ret = sst_block_alloc_scratch(hsw->dsp);
+       if (ret < 0)
+               goto boot_err;
+
        /* wait for DSP boot completion */
        sst_dsp_boot(hsw->dsp);
        ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
index 8a8d56a146e75a19d4587e169cb967b730b3eb36..11c578651c1c8cc778904ebb7665587cde44beef 100644 (file)
@@ -350,7 +350,9 @@ static inline void sst_save_shim64(struct intel_sst_drv *ctx,
 
        spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
 
-       shim_regs->imrx = sst_shim_read64(shim, SST_IMRX),
+       shim_regs->imrx = sst_shim_read64(shim, SST_IMRX);
+       shim_regs->csr = sst_shim_read64(shim, SST_CSR);
+
 
        spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
 }
@@ -367,6 +369,7 @@ static inline void sst_restore_shim64(struct intel_sst_drv *ctx,
         */
        spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
        sst_shim_write64(shim, SST_IMRX, shim_regs->imrx),
+       sst_shim_write64(shim, SST_CSR, shim_regs->csr),
        spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
 }
 
@@ -379,6 +382,10 @@ void sst_configure_runtime_pm(struct intel_sst_drv *ctx)
         * initially active. So change the state to active before
         * enabling the pm
         */
+
+       if (!acpi_disabled)
+               pm_runtime_set_active(ctx->dev);
+
        pm_runtime_enable(ctx->dev);
 
        if (acpi_disabled)
@@ -409,6 +416,7 @@ static int intel_sst_runtime_suspend(struct device *dev)
        synchronize_irq(ctx->irq_num);
        flush_workqueue(ctx->post_msg_wq);
 
+       ctx->ops->reset(ctx);
        /* save the shim registers because PMC doesn't save state */
        sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
 
index def7d8260c4e579c06eeba8ba45f422e1fb482c5..d19483081f9bb8ffce6c9fdf8bc3a3d70b40faf3 100644 (file)
@@ -579,7 +579,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
                if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
        } else {
-               if (priv->extclk == priv->clk) {
+               if (clk_is_match(priv->extclk, priv->clk)) {
                        devm_clk_put(&pdev->dev, priv->extclk);
                        priv->extclk = ERR_PTR(-EINVAL);
                } else {
index ccfb41c22e53b11cedbf5d8272a56a757ad283d1..f7eb42aa3f3893ca7cfd76fd2f8a96ff986d68b2 100644 (file)
@@ -352,6 +352,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
                return ret;
 
        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
        card->name = devm_kasprintf(dev, GFP_KERNEL,
                                    "HDMI %s", dev_name(ad->dssdev));
        card->owner = THIS_MODULE;
index c7eb9dd67f608c47ffa93a97c1824e3dae3c867b..fd99d89de6a854606357b50c44deeb43bcfb04ab 100644 (file)
@@ -530,8 +530,19 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 
        case OMAP_MCBSP_SYSCLK_CLKX_EXT:
                regs->srgr2     |= CLKSM;
+               regs->pcr0      |= SCLKME;
+               /*
+                * If McBSP is master but yet the CLKX/CLKR pin drives the SRG,
+                * disable output on those pins. This enables to inject the
+                * reference clock through CLKX/CLKR. For this to work
+                * set_dai_sysclk() _needs_ to be called after set_dai_fmt().
+                */
+               regs->pcr0      &= ~CLKXM;
+               break;
        case OMAP_MCBSP_SYSCLK_CLKR_EXT:
                regs->pcr0      |= SCLKME;
+               /* Disable ouput on CLKR pin in master mode */
+               regs->pcr0      &= ~CLKRM;
                break;
        default:
                err = -ENODEV;
index f4b05bc23e4bfb4d27adf8dea4702539c2696609..1343ecbf0bd5ee307d78d05f8a2e44abadc6c877 100644 (file)
@@ -201,7 +201,7 @@ static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
        struct snd_pcm *pcm = rtd->pcm;
        int ret;
 
-       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(64));
+       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
        if (ret)
                return ret;
 
index 3cebf6ca03dfb91891cd6e6d5eb51649b504c0b1..0632a36852c8476416f8fcb78d625abb98d658cf 100644 (file)
@@ -174,7 +174,7 @@ config SND_SOC_SMDK_WM8994_PCM
 
 config SND_SOC_SPEYSIDE
        tristate "Audio support for Wolfson Speyside"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C && SPI_MASTER
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8996
        select SND_SOC_WM9081
@@ -189,7 +189,7 @@ config SND_SOC_TOBERMORY
 
 config SND_SOC_BELLS
        tristate "Audio support for Wolfson Bells"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA && I2C && SPI_MASTER
        select SND_SAMSUNG_I2S
        select SND_SOC_WM5102
        select SND_SOC_WM5110
@@ -206,7 +206,7 @@ config SND_SOC_LOWLAND
 
 config SND_SOC_LITTLEMILL
        tristate "Audio support for Wolfson Littlemill"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C
        select SND_SAMSUNG_I2S
        select MFD_WM8994
        select SND_SOC_WM8994
@@ -223,7 +223,7 @@ config SND_SOC_SNOW
 
 config SND_SOC_ODROIDX2
        tristate "Audio support for Odroid-X2 and Odroid-U3"
-       depends on SND_SOC_SAMSUNG
+       depends on SND_SOC_SAMSUNG && I2C
        select SND_SOC_MAX98090
        select SND_SAMSUNG_I2S
        help
@@ -231,6 +231,6 @@ config SND_SOC_ODROIDX2
 
 config SND_SOC_ARNDALE_RT5631_ALC5631
         tristate "Audio support for RT5631(ALC5631) on Arndale Board"
-        depends on SND_SOC_SAMSUNG
+        depends on SND_SOC_SAMSUNG && I2C
         select SND_SAMSUNG_I2S
         select SND_SOC_RT5631
index 1b53605f7154394d1746cb0a692953e296848c2a..110577c523179c3974a2ebe45ef577ea651aa5ce 100644 (file)
@@ -1252,6 +1252,8 @@ static int rsnd_probe(struct platform_device *pdev)
                        goto exit_snd_probe;
        }
 
+       dev_set_drvdata(dev, priv);
+
        /*
         *      asoc register
         */
@@ -1268,8 +1270,6 @@ static int rsnd_probe(struct platform_device *pdev)
                goto exit_snd_soc;
        }
 
-       dev_set_drvdata(dev, priv);
-
        pm_runtime_enable(dev);
 
        dev_info(dev, "probed\n");
index 30579ca5bacb985c7dfa9b9ad30f58cee45d6e1a..e5c990889dcc5e6d9a1ecca2682acf4384ab5ae5 100644 (file)
@@ -347,6 +347,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(codec, &codec_list, list) {
                len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
                               codec->component.name);
@@ -358,6 +360,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        if (ret >= 0)
                ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
@@ -382,6 +386,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(component, &component_list, list) {
                list_for_each_entry(dai, &component->dai_list, list) {
                        len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
@@ -395,6 +401,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
        kfree(buf);
@@ -418,6 +426,8 @@ static ssize_t platform_list_read_file(struct file *file,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(platform, &platform_list, list) {
                len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
                               platform->component.name);
@@ -429,6 +439,8 @@ static ssize_t platform_list_read_file(struct file *file,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
        kfree(buf);
@@ -836,6 +848,8 @@ static struct snd_soc_component *soc_find_component(
 {
        struct snd_soc_component *component;
 
+       lockdep_assert_held(&client_mutex);
+
        list_for_each_entry(component, &component_list, list) {
                if (of_node) {
                        if (component->dev->of_node == of_node)
@@ -854,6 +868,8 @@ static struct snd_soc_dai *snd_soc_find_dai(
        struct snd_soc_component *component;
        struct snd_soc_dai *dai;
 
+       lockdep_assert_held(&client_mutex);
+
        /* Find CPU DAI from registered DAIs*/
        list_for_each_entry(component, &component_list, list) {
                if (dlc->of_node && component->dev->of_node != dlc->of_node)
@@ -1508,6 +1524,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        struct snd_soc_codec *codec;
        int ret, i, order;
 
+       mutex_lock(&client_mutex);
        mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 
        /* bind DAIs */
@@ -1662,6 +1679,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        card->instantiated = 1;
        snd_soc_dapm_sync(&card->dapm);
        mutex_unlock(&card->mutex);
+       mutex_unlock(&client_mutex);
 
        return 0;
 
@@ -1680,6 +1698,7 @@ card_probe_error:
 
 base_error:
        mutex_unlock(&card->mutex);
+       mutex_unlock(&client_mutex);
 
        return ret;
 }
@@ -2713,13 +2732,6 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
        list_del(&component->list);
 }
 
-static void snd_soc_component_del(struct snd_soc_component *component)
-{
-       mutex_lock(&client_mutex);
-       snd_soc_component_del_unlocked(component);
-       mutex_unlock(&client_mutex);
-}
-
 int snd_soc_register_component(struct device *dev,
                               const struct snd_soc_component_driver *cmpnt_drv,
                               struct snd_soc_dai_driver *dai_drv,
@@ -2767,14 +2779,17 @@ void snd_soc_unregister_component(struct device *dev)
 {
        struct snd_soc_component *cmpnt;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(cmpnt, &component_list, list) {
                if (dev == cmpnt->dev && cmpnt->registered_as_component)
                        goto found;
        }
+       mutex_unlock(&client_mutex);
        return;
 
 found:
-       snd_soc_component_del(cmpnt);
+       snd_soc_component_del_unlocked(cmpnt);
+       mutex_unlock(&client_mutex);
        snd_soc_component_cleanup(cmpnt);
        kfree(cmpnt);
 }
@@ -2882,10 +2897,14 @@ struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev)
 {
        struct snd_soc_platform *platform;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(platform, &platform_list, list) {
-               if (dev == platform->dev)
+               if (dev == platform->dev) {
+                       mutex_unlock(&client_mutex);
                        return platform;
+               }
        }
+       mutex_unlock(&client_mutex);
 
        return NULL;
 }
@@ -3090,15 +3109,15 @@ void snd_soc_unregister_codec(struct device *dev)
 {
        struct snd_soc_codec *codec;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(codec, &codec_list, list) {
                if (dev == codec->dev)
                        goto found;
        }
+       mutex_unlock(&client_mutex);
        return;
 
 found:
-
-       mutex_lock(&client_mutex);
        list_del(&codec->list);
        snd_soc_component_del_unlocked(&codec->component);
        mutex_unlock(&client_mutex);
index 05dee690f4876167ace542fe500bb077bec26762..97ed593f6010f6dccf4e5eb5db39e4a2381a7692 100644 (file)
@@ -39,7 +39,7 @@ static void change_volume(struct urb *urb_out, int volume[],
                for (; p < buf_end; ++p) {
                        short pv = le16_to_cpu(*p);
                        int val = (pv * volume[chn & 1]) >> 8;
-                       pv = clamp(val, 0x7fff, -0x8000);
+                       pv = clamp(val, -0x8000, 0x7fff);
                        *p = cpu_to_le16(pv);
                        ++chn;
                }
@@ -54,7 +54,7 @@ static void change_volume(struct urb *urb_out, int volume[],
 
                        val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
                        val = (val * volume[chn & 1]) >> 8;
-                       val = clamp(val, 0x7fffff, -0x800000);
+                       val = clamp(val, -0x800000, 0x7fffff);
                        p[0] = val;
                        p[1] = val >> 8;
                        p[2] = val >> 16;
@@ -126,7 +126,7 @@ static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
                        short pov = le16_to_cpu(*po);
                        short piv = le16_to_cpu(*pi);
                        int val = pov + ((piv * volume) >> 8);
-                       pov = clamp(val, 0x7fff, -0x8000);
+                       pov = clamp(val, -0x8000, 0x7fff);
                        *po = cpu_to_le16(pov);
                }
        }
index 67d476548dcf9094acd61e0ff74f0f320af1556a..07f984d5f5162809ee6124f651585df5c3a4496f 100644 (file)
@@ -1773,6 +1773,36 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       USB_DEVICE(0x0582, 0x0159),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Roland", */
+               /* .product_name = "UA-22", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 /* this catches most recent vendor-specific Roland devices */
 {
        .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
index 6c14afe8c1b18ea1ab4a50aa4b6dc46925d304a1..db1d3a29d97fec67c47a4dd84eca2f7779ec1865 100644 (file)
@@ -289,7 +289,7 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault)
        memcpy_t fn = r->fn.memcpy;
        int i;
 
-       memcpy_alloc_mem(&src, &dst, len);
+       memcpy_alloc_mem(&dst, &src, len);
 
        if (prefault)
                fn(dst, src, len);
@@ -312,7 +312,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len,
        void *src = NULL, *dst = NULL;
        int i;
 
-       memcpy_alloc_mem(&src, &dst, len);
+       memcpy_alloc_mem(&dst, &src, len);
 
        if (prefault)
                fn(dst, src, len);
index ff95a68741d1ccdb54e54d929f2292e88963a5d1..ac8721ffa6c8c681ccdb563607d5b80917062438 100644 (file)
@@ -21,6 +21,10 @@ ifeq ($(RAW_ARCH),x86_64)
   endif
 endif
 
+ifeq ($(RAW_ARCH),sparc64)
+  ARCH ?= sparc
+endif
+
 ARCH ?= $(RAW_ARCH)
 
 LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
index 42ac05aaf8ac1a8bf004c1e664aa10a1853111bc..b32ff3372514da7da33da49cfc2d52755f1db935 100644 (file)
@@ -49,7 +49,7 @@ test-hello.bin:
        $(BUILD)
 
 test-pthread-attr-setaffinity-np.bin:
-       $(BUILD) -Werror -lpthread
+       $(BUILD) -D_GNU_SOURCE -Werror -lpthread
 
 test-stackprotector-all.bin:
        $(BUILD) -Werror -fstack-protector-all
index 0a0d3ecb4e8af81b77222c29f92efcbf4485313b..2b81b72eca23726a03b263fb21efa649c13c9495 100644 (file)
@@ -5,10 +5,11 @@ int main(void)
 {
        int ret = 0;
        pthread_attr_t thread_attr;
+       cpu_set_t cs;
 
        pthread_attr_init(&thread_attr);
        /* don't care abt exact args, just the API itself in libpthread */
-       ret = pthread_attr_setaffinity_np(&thread_attr, 0, NULL);
+       ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cs), &cs);
 
        return ret;
 }
index 61bf9128e1f28ce40d3d694ef5d9de8bb9cda1f8..9d9db3b296dd6b50ed27e581c0d78aab65dfec49 100644 (file)
@@ -30,6 +30,8 @@ static int disasm_line__parse(char *line, char **namep, char **rawp);
 
 static void ins__delete(struct ins_operands *ops)
 {
+       if (ops == NULL)
+               return;
        zfree(&ops->source.raw);
        zfree(&ops->source.name);
        zfree(&ops->target.raw);
index 47b78b3f03257385023629696dda95e57d2b5ab7..6da965bdbc2caf8762b5018c6837422a00aac456 100644 (file)
@@ -25,6 +25,10 @@ static int perf_flag_probe(void)
        if (cpu < 0)
                cpu = 0;
 
+       /*
+        * Using -1 for the pid is a workaround to avoid gratuitous jump label
+        * changes.
+        */
        while (1) {
                /* check cloexec flag */
                fd = sys_perf_event_open(&attr, pid, cpu, -1,
@@ -47,16 +51,24 @@ static int perf_flag_probe(void)
                  err, strerror_r(err, sbuf, sizeof(sbuf)));
 
        /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
-       fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
+       while (1) {
+               fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
+               if (fd < 0 && pid == -1 && errno == EACCES) {
+                       pid = 0;
+                       continue;
+               }
+               break;
+       }
        err = errno;
 
+       if (fd >= 0)
+               close(fd);
+
        if (WARN_ONCE(fd < 0 && err != EBUSY,
                      "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
                      err, strerror_r(err, sbuf, sizeof(sbuf))))
                return -1;
 
-       close(fd);
-
        return 0;
 }
 
index c94a9e03ecf15744800d4a6bc68cca28ca70259e..e99a67632831a8e6548fae8a40b654f01b009d1e 100644 (file)
@@ -28,7 +28,7 @@ struct perf_mmap {
        int              mask;
        int              refcnt;
        unsigned int     prev;
-       char             event_copy[PERF_SAMPLE_MAX_SIZE];
+       char             event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8)));
 };
 
 struct perf_evlist {
index b24f9d8727a894ccae13353abad0b951ec1b0916..33b7a2aef71322ab88b93e675c070bfc4a7c7da7 100644 (file)
 #include <symbol/kallsyms.h>
 #include "debug.h"
 
+#ifndef EM_AARCH64
+#define EM_AARCH64     183  /* ARM 64 bit */
+#endif
+
+
 #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
 extern char *cplus_demangle(const char *, int);
 
index 3ed7c0476d486d21dcb1c735478191ffa88c2fc7..2e2ba2efa0d9f97629ec5af9fb1136b3dee8962d 100644 (file)
@@ -209,7 +209,7 @@ $(OUTPUT)%.o: %.c
 
 $(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ)
        $(ECHO) "  CC      " $@
-       $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -Wl,-rpath=./ -lrt -lpci -L$(OUTPUT) -o $@
+       $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@
        $(QUIET) $(STRIPCMD) $@
 
 $(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC)
index 4e511221a0c11cd53588fc2ae507848ab94339cb..0db571340edbd94a7042a63f517f410b42c127d7 100644 (file)
@@ -22,6 +22,14 @@ TARGETS += vm
 TARGETS_HOTPLUG = cpu-hotplug
 TARGETS_HOTPLUG += memory-hotplug
 
+# Clear LDFLAGS and MAKEFLAGS if called from main
+# Makefile to avoid test build failures when test
+# Makefile doesn't have explicit build rules.
+ifeq (1,$(MAKELEVEL))
+undefine LDFLAGS
+override MAKEFLAGS =
+endif
+
 all:
        for TARGET in $(TARGETS); do \
                make -C $$TARGET; \
index e238c9559caf9a7757d2d389e0bda57cd73229a8..8d5d1d2ee7c1d793405685e8266045363bcce960 100644 (file)
@@ -30,7 +30,7 @@ static int execveat_(int fd, const char *path, char **argv, char **envp,
 #ifdef __NR_execveat
        return syscall(__NR_execveat, fd, path, argv, envp, flags);
 #else
-       errno = -ENOSYS;
+       errno = ENOSYS;
        return -1;
 #endif
 }
@@ -234,6 +234,14 @@ static int run_tests(void)
        int fd_cloexec = open_or_die("execveat", O_RDONLY|O_CLOEXEC);
        int fd_script_cloexec = open_or_die("script", O_RDONLY|O_CLOEXEC);
 
+       /* Check if we have execveat at all, and bail early if not */
+       errno = 0;
+       execveat_(-1, NULL, NULL, NULL, 0);
+       if (errno == ENOSYS) {
+               printf("[FAIL] ENOSYS calling execveat - no kernel support?\n");
+               return 1;
+       }
+
        /* Change file position to confirm it doesn't affect anything */
        lseek(fd, 10, SEEK_SET);
 
diff --git a/tools/thermal/tmon/.gitignore b/tools/thermal/tmon/.gitignore
new file mode 100644 (file)
index 0000000..06e96be
--- /dev/null
@@ -0,0 +1 @@
+/tmon
index e775adcbd29fdd3c0fccb66a09efc86e1fd95216..0788621c8d760f01f714d377a18c6a390a990fde 100644 (file)
@@ -2,8 +2,8 @@ VERSION = 1.0
 
 BINDIR=usr/bin
 WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
-CFLAGS= -O1 ${WARNFLAGS} -fstack-protector
-CC=gcc
+CFLAGS+= -O1 ${WARNFLAGS} -fstack-protector
+CC=$(CROSS_COMPILE)gcc
 
 CFLAGS+=-D VERSION=\"$(VERSION)\"
 LDFLAGS+=
@@ -16,12 +16,21 @@ INSTALL_CONFIGFILE=install -m 644 -p
 CONFIG_FILE=
 CONFIG_PATH=
 
+# Static builds might require -ltinfo, for instance
+ifneq ($(findstring -static, $(LDFLAGS)),)
+STATIC := --static
+endif
+
+TMON_LIBS=-lm -lpthread
+TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null || \
+                    pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \
+                    echo -lpanel -lncurses)
 
 OBJS = tmon.o tui.o sysfs.o pid.o
 OBJS +=
 
 tmon: $(OBJS) Makefile tmon.h
-       $(CC) ${CFLAGS} $(LDFLAGS) $(OBJS)  -o $(TARGET) -lm -lpanel -lncursesw -ltinfo -lpthread
+       $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS)  -o $(TARGET) $(TMON_LIBS)
 
 valgrind: tmon
         sudo valgrind -v --track-origins=yes --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./$(TARGET)  1> /dev/null
index 0be727cb9892ccc50e412a8a8cdb28f3f2476c68..02d5179803aae1cdfa43ecf23e25bc8e1c9b9e43 100644 (file)
@@ -55,6 +55,8 @@ The \fB-l --log\fP option write data to /var/tmp/tmon.log
 .PP
 The \fB-t --time-interval\fP option sets the polling interval in seconds
 .PP
+The \fB-T --target-temp\fP option sets the initial target temperature
+.PP
 The \fB-v --version\fP option shows the version of \fBtmon \fP
 .PP
 The \fB-z --zone\fP option sets the target therma zone instance to be controlled
index 09b7c3218334ba29dad1192d5dbd5a963dd51553..9aa19652e8e859a34a5db1edbae0c02170499967 100644 (file)
@@ -64,6 +64,7 @@ void usage()
        printf("  -h, --help            show this help message\n");
        printf("  -l, --log             log data to /var/tmp/tmon.log\n");
        printf("  -t, --time-interval   sampling time interval, > 1 sec.\n");
+       printf("  -T, --target-temp     initial target temperature\n");
        printf("  -v, --version         show version\n");
        printf("  -z, --zone            target thermal zone id\n");
 
@@ -219,6 +220,7 @@ static struct option opts[] = {
        { "control", 1, NULL, 'c' },
        { "daemon", 0, NULL, 'd' },
        { "time-interval", 1, NULL, 't' },
+       { "target-temp", 1, NULL, 'T' },
        { "log", 0, NULL, 'l' },
        { "help", 0, NULL, 'h' },
        { "version", 0, NULL, 'v' },
@@ -231,7 +233,7 @@ int main(int argc, char **argv)
 {
        int err = 0;
        int id2 = 0, c;
-       double yk = 0.0; /* controller output */
+       double yk = 0.0, temp; /* controller output */
        int target_tz_index;
 
        if (geteuid() != 0) {
@@ -239,7 +241,7 @@ int main(int argc, char **argv)
                exit(EXIT_FAILURE);
        }
 
-       while ((c = getopt_long(argc, argv, "c:dlht:vgz:", opts, &id2)) != -1) {
+       while ((c = getopt_long(argc, argv, "c:dlht:T:vgz:", opts, &id2)) != -1) {
                switch (c) {
                case 'c':
                        no_control = 0;
@@ -254,6 +256,14 @@ int main(int argc, char **argv)
                        if (ticktime < 1)
                                ticktime = 1;
                        break;
+               case 'T':
+                       temp = strtod(optarg, NULL);
+                       if (temp < 0) {
+                               fprintf(stderr, "error: temperature must be positive\n");
+                               return 1;
+                       }
+                       target_temp_user = temp;
+                       break;
                case 'l':
                        printf("Logging data to /var/tmp/tmon.log\n");
                        logging = 1;
index 89f8ef0e15c810936737a51f49f1a87f1f2c5648..b5d1c6b22dd3c8781c7cadd590f2121dfb8328cc 100644 (file)
 
 #include "tmon.h"
 
+#define min(x, y) ({                           \
+       typeof(x) _min1 = (x);                  \
+       typeof(y) _min2 = (y);                  \
+       (void) (&_min1 == &_min2);              \
+       _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({                           \
+       typeof(x) _max1 = (x);                  \
+       typeof(y) _max2 = (y);                  \
+       (void) (&_max1 == &_max2);              \
+       _max1 > _max2 ? _max1 : _max2; })
+
 static PANEL *data_panel;
 static PANEL *dialogue_panel;
 static PANEL *top;
@@ -98,6 +110,18 @@ void write_status_bar(int x, char *line)
        wrefresh(status_bar_window);
 }
 
+/* wrap at 5 */
+#define DIAG_DEV_ROWS  5
+/*
+ * list cooling devices + "set temp" entry; wraps after 5 rows, if they fit
+ */
+static int diag_dev_rows(void)
+{
+       int entries = ptdata.nr_cooling_dev + 1;
+       int rows = max(DIAG_DEV_ROWS, (entries + 1) / 2);
+       return min(rows, entries);
+}
+
 void setup_windows(void)
 {
        int y_begin = 1;
@@ -122,7 +146,7 @@ void setup_windows(void)
         * dialogue window is a pop-up, when needed it lays on top of cdev win
         */
 
-       dialogue_window = subwin(stdscr, ptdata.nr_cooling_dev+5, maxx-50,
+       dialogue_window = subwin(stdscr, diag_dev_rows() + 5, maxx-50,
                                DIAG_Y, DIAG_X);
 
        thermal_data_window = subwin(stdscr, ptdata.nr_tz_sensor *
@@ -258,21 +282,26 @@ void show_cooling_device(void)
 }
 
 const char DIAG_TITLE[] = "[ TUNABLES ]";
-#define DIAG_DEV_ROWS  5
 void show_dialogue(void)
 {
        int j, x = 0, y = 0;
+       int rows, cols;
        WINDOW *w = dialogue_window;
 
        if (tui_disabled || !w)
                return;
 
+       getmaxyx(w, rows, cols);
+
+       /* Silence compiler 'unused' warnings */
+       (void)cols;
+
        werase(w);
        box(w, 0, 0);
        mvwprintw(w, 0, maxx/4, DIAG_TITLE);
        /* list all the available tunables */
        for (j = 0; j <= ptdata.nr_cooling_dev; j++) {
-               y = j % DIAG_DEV_ROWS;
+               y = j % diag_dev_rows();
                if (y == 0 && j != 0)
                        x += 20;
                if (j == ptdata.nr_cooling_dev)
@@ -283,12 +312,10 @@ void show_dialogue(void)
                                ptdata.cdi[j].type, ptdata.cdi[j].instance);
        }
        wattron(w, A_BOLD);
-       mvwprintw(w, DIAG_DEV_ROWS+1, 1, "Enter Choice [A-Z]?");
+       mvwprintw(w, diag_dev_rows()+1, 1, "Enter Choice [A-Z]?");
        wattroff(w, A_BOLD);
-       /* y size of dialogue win is nr cdev + 5, so print legend
-        * at the bottom line
-        */
-       mvwprintw(w, ptdata.nr_cooling_dev+3, 1,
+       /* print legend at the bottom line */
+       mvwprintw(w, rows - 2, 1,
                "Legend: A=Active, P=Passive, C=Critical");
 
        wrefresh(dialogue_window);
@@ -437,7 +464,7 @@ static void handle_input_choice(int ch)
                        snprintf(buf, sizeof(buf), "New Value for %.10s-%2d: ",
                                ptdata.cdi[cdev_id].type,
                                ptdata.cdi[cdev_id].instance);
-               write_dialogue_win(buf, DIAG_DEV_ROWS+2, 2);
+               write_dialogue_win(buf, diag_dev_rows() + 2, 2);
                handle_input_val(cdev_id);
        } else {
                snprintf(buf, sizeof(buf), "Invalid selection %d", ch);
index a0a7b5d1a0703a00f81c9421856c0fdf1b1f6aaa..f9b9c7c5137214cb56bcc0cf7455d2d712dc6848 100644 (file)
@@ -72,6 +72,8 @@ static void vgic_v2_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
 {
        if (!(lr_desc.state & LR_STATE_MASK))
                vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr |= (1ULL << lr);
+       else
+               vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr &= ~(1ULL << lr);
 }
 
 static u64 vgic_v2_get_elrsr(const struct kvm_vcpu *vcpu)
@@ -84,6 +86,11 @@ static u64 vgic_v2_get_eisr(const struct kvm_vcpu *vcpu)
        return vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr;
 }
 
+static void vgic_v2_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr = 0;
+}
+
 static u32 vgic_v2_get_interrupt_status(const struct kvm_vcpu *vcpu)
 {
        u32 misr = vcpu->arch.vgic_cpu.vgic_v2.vgic_misr;
@@ -148,6 +155,7 @@ static const struct vgic_ops vgic_v2_ops = {
        .sync_lr_elrsr          = vgic_v2_sync_lr_elrsr,
        .get_elrsr              = vgic_v2_get_elrsr,
        .get_eisr               = vgic_v2_get_eisr,
+       .clear_eisr             = vgic_v2_clear_eisr,
        .get_interrupt_status   = vgic_v2_get_interrupt_status,
        .enable_underflow       = vgic_v2_enable_underflow,
        .disable_underflow      = vgic_v2_disable_underflow,
index 3a62d8a9a2c6fce0cc2f94a6e558115785c03811..dff06021e74855a2d6cb9b8830fd30818a63c927 100644 (file)
@@ -104,6 +104,8 @@ static void vgic_v3_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
 {
        if (!(lr_desc.state & LR_STATE_MASK))
                vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
+       else
+               vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr &= ~(1U << lr);
 }
 
 static u64 vgic_v3_get_elrsr(const struct kvm_vcpu *vcpu)
@@ -116,6 +118,11 @@ static u64 vgic_v3_get_eisr(const struct kvm_vcpu *vcpu)
        return vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr;
 }
 
+static void vgic_v3_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr = 0;
+}
+
 static u32 vgic_v3_get_interrupt_status(const struct kvm_vcpu *vcpu)
 {
        u32 misr = vcpu->arch.vgic_cpu.vgic_v3.vgic_misr;
@@ -192,6 +199,7 @@ static const struct vgic_ops vgic_v3_ops = {
        .sync_lr_elrsr          = vgic_v3_sync_lr_elrsr,
        .get_elrsr              = vgic_v3_get_elrsr,
        .get_eisr               = vgic_v3_get_eisr,
+       .clear_eisr             = vgic_v3_clear_eisr,
        .get_interrupt_status   = vgic_v3_get_interrupt_status,
        .enable_underflow       = vgic_v3_enable_underflow,
        .disable_underflow      = vgic_v3_disable_underflow,
index 0cc6ab6005a07bb2e9453106a672e9efd4e237a6..c9f60f52458802f4a66a3912732d8665bc4a3e32 100644 (file)
@@ -883,6 +883,11 @@ static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
        return vgic_ops->get_eisr(vcpu);
 }
 
+static inline void vgic_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vgic_ops->clear_eisr(vcpu);
+}
+
 static inline u32 vgic_get_interrupt_status(struct kvm_vcpu *vcpu)
 {
        return vgic_ops->get_interrupt_status(vcpu);
@@ -922,6 +927,7 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
        vgic_set_lr(vcpu, lr_nr, vlr);
        clear_bit(lr_nr, vgic_cpu->lr_used);
        vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
+       vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
 }
 
 /*
@@ -978,6 +984,7 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
                        BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
                        vlr.state |= LR_STATE_PENDING;
                        vgic_set_lr(vcpu, lr, vlr);
+                       vgic_sync_lr_elrsr(vcpu, lr, vlr);
                        return true;
                }
        }
@@ -999,6 +1006,7 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
                vlr.state |= LR_EOI_INT;
 
        vgic_set_lr(vcpu, lr, vlr);
+       vgic_sync_lr_elrsr(vcpu, lr, vlr);
 
        return true;
 }
@@ -1136,6 +1144,14 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
        if (status & INT_STATUS_UNDERFLOW)
                vgic_disable_underflow(vcpu);
 
+       /*
+        * In the next iterations of the vcpu loop, if we sync the vgic state
+        * after flushing it, but before entering the guest (this happens for
+        * pending signals and vmid rollovers), then make sure we don't pick
+        * up any old maintenance interrupts here.
+        */
+       vgic_clear_eisr(vcpu);
+
        return level_pending;
 }
 
@@ -1583,8 +1599,10 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
         * emulation. So check this here again. KVM_CREATE_DEVICE does
         * the proper checks already.
         */
-       if (type == KVM_DEV_TYPE_ARM_VGIC_V2 && !vgic->can_emulate_gicv2)
-               return -ENODEV;
+       if (type == KVM_DEV_TYPE_ARM_VGIC_V2 && !vgic->can_emulate_gicv2) {
+               ret = -ENODEV;
+               goto out;
+       }
 
        /*
         * Any time a vcpu is run, vcpu_load is called which tries to grab the
index a1093700f3a41b84fc71591a7465940fdd4a017f..cc6a25d95fbff532bf5b00b0c339bec91ddc5bcf 100644 (file)
@@ -471,7 +471,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
        BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX);
 
        r = -ENOMEM;
-       kvm->memslots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
+       kvm->memslots = kvm_kvzalloc(sizeof(struct kvm_memslots));
        if (!kvm->memslots)
                goto out_err_no_srcu;
 
@@ -522,7 +522,7 @@ out_err_no_srcu:
 out_err_no_disable:
        for (i = 0; i < KVM_NR_BUSES; i++)
                kfree(kvm->buses[i]);
-       kfree(kvm->memslots);
+       kvfree(kvm->memslots);
        kvm_arch_free_vm(kvm);
        return ERR_PTR(r);
 }
@@ -578,7 +578,7 @@ static void kvm_free_physmem(struct kvm *kvm)
        kvm_for_each_memslot(memslot, slots)
                kvm_free_physmem_slot(kvm, memslot, NULL);
 
-       kfree(kvm->memslots);
+       kvfree(kvm->memslots);
 }
 
 static void kvm_destroy_devices(struct kvm *kvm)
@@ -871,10 +871,10 @@ int __kvm_set_memory_region(struct kvm *kvm,
                        goto out_free;
        }
 
-       slots = kmemdup(kvm->memslots, sizeof(struct kvm_memslots),
-                       GFP_KERNEL);
+       slots = kvm_kvzalloc(sizeof(struct kvm_memslots));
        if (!slots)
                goto out_free;
+       memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
 
        if ((change == KVM_MR_DELETE) || (change == KVM_MR_MOVE)) {
                slot = id_to_memslot(slots, mem->slot);
@@ -917,7 +917,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        kvm_arch_commit_memory_region(kvm, mem, &old, change);
 
        kvm_free_physmem_slot(kvm, &old, &new);
-       kfree(old_memslots);
+       kvfree(old_memslots);
 
        /*
         * IOMMU mapping:  New slots need to be mapped.  Old slots need to be
@@ -936,7 +936,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        return 0;
 
 out_slots:
-       kfree(slots);
+       kvfree(slots);
 out_free:
        kvm_free_physmem_slot(kvm, &new, &old);
 out:
@@ -2492,6 +2492,7 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
        case KVM_CAP_SIGNAL_MSI:
 #endif
 #ifdef CONFIG_HAVE_KVM_IRQFD
+       case KVM_CAP_IRQFD:
        case KVM_CAP_IRQFD_RESAMPLE:
 #endif
        case KVM_CAP_CHECK_EXTENSION_VM: