Merge branch 'ttm-next-3.13' of git://people.freedesktop.org/~thomash/linux into...
authorDave Airlie <airlied@redhat.com>
Wed, 13 Nov 2013 23:52:10 +0000 (09:52 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 13 Nov 2013 23:52:10 +0000 (09:52 +1000)
The page-prot bit fix.

* 'ttm-next-3.13' of git://people.freedesktop.org/~thomash/linux:
  drm/ttm: Fix vma page_prot bit manipulation

1173 files changed:
Documentation/ABI/stable/sysfs-bus-usb
Documentation/ABI/testing/sysfs-devices-power
Documentation/ABI/testing/sysfs-power
Documentation/acpi/dsdt-override.txt
Documentation/block/00-INDEX
Documentation/block/cmdline-partition.txt
Documentation/connector/ucon.c
Documentation/devicetree/bindings/memory.txt [deleted file]
Documentation/devicetree/bindings/mmc/tmio_mmc.txt
Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
Documentation/kernel-parameters.txt
Documentation/sound/alsa/HD-Audio-Models.txt
MAINTAINERS
Makefile
arch/arc/include/asm/spinlock.h
arch/arc/include/asm/uaccess.h
arch/arc/kernel/ptrace.c
arch/arc/kernel/signal.c
arch/arc/kernel/time.c
arch/arc/kernel/unaligned.c
arch/arc/mm/fault.c
arch/arm/Makefile
arch/arm/boot/Makefile
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/armada-370-netgear-rn102.dts
arch/arm/boot/dts/armada-xp.dtsi
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/atlas6.dtsi
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/integratorcp.dts
arch/arm/boot/dts/kirkwood.dtsi
arch/arm/boot/dts/omap3-beagle-xm.dts
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/prima2.dtsi
arch/arm/boot/dts/r8a73a4.dtsi
arch/arm/boot/dts/r8a7778.dtsi
arch/arm/boot/dts/r8a7779.dtsi
arch/arm/boot/dts/r8a7790.dtsi
arch/arm/boot/dts/sh73a0.dtsi
arch/arm/boot/install.sh
arch/arm/common/edma.c
arch/arm/common/mcpm_entry.c
arch/arm/common/sharpsl_param.c
arch/arm/configs/multi_v7_defconfig
arch/arm/include/asm/Kbuild
arch/arm/include/asm/jump_label.h
arch/arm/include/asm/mcpm.h
arch/arm/include/asm/syscall.h
arch/arm/kernel/head.S
arch/arm/kvm/reset.c
arch/arm/mach-at91/at91rm9200_time.c
arch/arm/mach-at91/at91sam926x_time.c
arch/arm/mach-at91/at91sam9g45_reset.S
arch/arm/mach-at91/at91x40_time.c
arch/arm/mach-davinci/board-dm365-evm.c
arch/arm/mach-davinci/include/mach/serial.h
arch/arm/mach-integrator/pci_v3.h
arch/arm/mach-mvebu/coherency.c
arch/arm/mach-mvebu/pmsu.c
arch/arm/mach-mvebu/system-controller.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/gpmc-onenand.c
arch/arm/mach-omap2/mux.h
arch/arm/mach-omap2/timer.c
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-lager.c
arch/arm/mach-vexpress/tc2_pm.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/init.c
arch/arm/net/bpf_jit_32.c
arch/arm64/Kconfig.debug
arch/arm64/configs/defconfig
arch/arm64/include/asm/uaccess.h
arch/arm64/kernel/fpsimd.c
arch/arm64/mm/tlb.S
arch/avr32/include/asm/Kbuild
arch/avr32/include/asm/cputime.h [deleted file]
arch/avr32/include/asm/delay.h [deleted file]
arch/avr32/include/asm/device.h [deleted file]
arch/avr32/include/asm/div64.h [deleted file]
arch/avr32/include/asm/emergency-restart.h [deleted file]
arch/avr32/include/asm/futex.h [deleted file]
arch/avr32/include/asm/irq_regs.h [deleted file]
arch/avr32/include/asm/local.h [deleted file]
arch/avr32/include/asm/local64.h [deleted file]
arch/avr32/include/asm/percpu.h [deleted file]
arch/avr32/include/asm/scatterlist.h [deleted file]
arch/avr32/include/asm/sections.h [deleted file]
arch/avr32/include/asm/topology.h [deleted file]
arch/avr32/include/asm/xor.h [deleted file]
arch/avr32/kernel/process.c
arch/avr32/kernel/time.c
arch/mips/alchemy/board-mtx1.c
arch/mips/include/asm/jump_label.h
arch/mips/kernel/octeon_switch.S
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/r2300_switch.S
arch/mips/kernel/r4k_switch.S
arch/mips/mm/c-r4k.c
arch/mips/mti-malta/malta-int.c
arch/mips/ralink/timer.c
arch/parisc/configs/712_defconfig
arch/parisc/configs/a500_defconfig
arch/parisc/configs/b180_defconfig
arch/parisc/configs/c3000_defconfig
arch/parisc/configs/c8000_defconfig
arch/parisc/configs/default_defconfig
arch/parisc/include/asm/traps.h
arch/parisc/kernel/head.S
arch/parisc/kernel/smp.c
arch/parisc/kernel/traps.c
arch/parisc/lib/memcpy.c
arch/parisc/mm/fault.c
arch/powerpc/include/asm/jump_label.h
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/tm.S
arch/powerpc/kernel/vio.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/e500_mmu_host.c
arch/powerpc/lib/checksum_64.S
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/net/bpf_jit_comp.c
arch/powerpc/perf/power8-pmu.c
arch/s390/include/asm/jump_label.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/timex.h
arch/s390/kernel/compat_signal.c
arch/s390/kernel/crash_dump.c
arch/s390/kernel/debug.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/kprobes.c
arch/s390/kvm/interrupt.c
arch/s390/lib/delay.c
arch/s390/net/bpf_jit_comp.c
arch/score/Kconfig
arch/score/Makefile
arch/score/include/asm/checksum.h
arch/score/include/asm/io.h
arch/score/include/asm/pgalloc.h
arch/score/kernel/entry.S
arch/score/kernel/process.c
arch/sparc/Kconfig
arch/sparc/include/asm/floppy_64.h
arch/sparc/include/asm/jump_label.h
arch/sparc/kernel/Makefile
arch/sparc/kernel/ds.c
arch/sparc/kernel/ldc.c
arch/sparc/net/bpf_jit_comp.c
arch/tile/include/asm/atomic.h
arch/tile/include/asm/atomic_32.h
arch/tile/include/asm/cmpxchg.h
arch/tile/include/asm/percpu.h
arch/tile/kernel/hardwall.c
arch/tile/kernel/intvec_32.S
arch/tile/kernel/intvec_64.S
arch/tile/kernel/stack.c
arch/tile/lib/atomic_32.c
arch/um/kernel/exitcode.c
arch/x86/Kconfig
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/jump_label.h
arch/x86/include/asm/mutex_64.h
arch/x86/include/asm/percpu.h
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/kvm.c
arch/x86/kernel/nmi.c
arch/x86/kernel/reboot.c
arch/x86/kernel/sysfb_simplefb.c
arch/x86/kvm/vmx.c
arch/x86/net/bpf_jit_comp.c
arch/x86/pci/mmconfig-shared.c
arch/x86/xen/smp.c
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/signal.c
arch/xtensa/platforms/iss/network.c
block/Kconfig
block/Makefile
block/partitions/Kconfig
block/partitions/cmdline.c
block/partitions/efi.c
drivers/acpi/Kconfig
drivers/acpi/device_pm.c
drivers/acpi/power.c
drivers/acpi/scan.c
drivers/ata/ahci.c
drivers/ata/ahci_platform.c
drivers/ata/libahci.c
drivers/ata/libata-acpi.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata.h
drivers/ata/pata_isapnp.c
drivers/base/memory.c
drivers/bcma/driver_pci.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/bus/mvebu-mbus.c
drivers/char/random.c
drivers/char/tpm/xen-tpmfront.c
drivers/clk/clk-nomadik.c
drivers/clk/mvebu/armada-370.c
drivers/clk/socfpga/clk.c
drivers/clk/versatile/clk-icst.c
drivers/connector/cn_proc.c
drivers/connector/connector.c
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/cpufreq-cpu0.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/s3c64xx-cpufreq.c
drivers/cpufreq/spear-cpufreq.c
drivers/dma/Kconfig
drivers/dma/edma.c
drivers/dma/imx-dma.c
drivers/dma/sh/rcar-hpbdma.c
drivers/gpio/gpio-lynxpoint.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/gma500/cdv_device.c
drivers/gpu/drm/gma500/framebuffer.c
drivers/gpu/drm/gma500/gtt.c
drivers/gpu/drm/gma500/intel_gmbus.c
drivers/gpu/drm/gma500/oaktrail_crtc.c
drivers/gpu/drm/gma500/oaktrail_device.c
drivers/gpu/drm/gma500/oaktrail_lvds.c
drivers/gpu/drm/gma500/psb_device.c
drivers/gpu/drm/gma500/psb_drv.c
drivers/gpu/drm/gma500/psb_drv.h
drivers/gpu/drm/gma500/psb_intel_sdvo.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_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_bios.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/adreno/a2xx.xml.h
drivers/gpu/drm/msm/adreno/a3xx.xml.h
drivers/gpu/drm/msm/adreno/adreno_common.xml.h
drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
drivers/gpu/drm/msm/dsi/dsi.xml.h
drivers/gpu/drm/msm/dsi/mmss_cc.xml.h
drivers/gpu/drm/msm/dsi/sfpb.xml.h
drivers/gpu/drm/msm/hdmi/hdmi.xml.h
drivers/gpu/drm/msm/hdmi/qfprom.xml.h
drivers/gpu/drm/msm/mdp4/mdp4.xml.h
drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/mdp4/mdp4_format.c
drivers/gpu/drm/msm/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/mdp4/mdp4_kms.h
drivers/gpu/drm/msm/mdp4/mdp4_plane.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem.h
drivers/gpu/drm/msm/msm_gem_prime.c [new file with mode: 0644]
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/core/event.c
drivers/gpu/drm/nouveau/core/core/option.c
drivers/gpu/drm/nouveau/core/core/printk.c
drivers/gpu/drm/nouveau/core/engine/device/base.c
drivers/gpu/drm/nouveau/core/engine/device/ctrl.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/device/nv04.c
drivers/gpu/drm/nouveau/core/engine/device/nv10.c
drivers/gpu/drm/nouveau/core/engine/device/nv20.c
drivers/gpu/drm/nouveau/core/engine/device/nv30.c
drivers/gpu/drm/nouveau/core/engine/device/nv40.c
drivers/gpu/drm/nouveau/core/engine/device/nv50.c
drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
drivers/gpu/drm/nouveau/core/engine/device/nve0.c
drivers/gpu/drm/nouveau/core/engine/device/priv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/disp/dport.c
drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c
drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c
drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/base.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/software/nv04.c
drivers/gpu/drm/nouveau/core/engine/software/nv10.c
drivers/gpu/drm/nouveau/core/engine/software/nv50.c
drivers/gpu/drm/nouveau/core/engine/software/nv50.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
drivers/gpu/drm/nouveau/core/include/core/class.h
drivers/gpu/drm/nouveau/core/include/core/debug.h
drivers/gpu/drm/nouveau/core/include/core/device.h
drivers/gpu/drm/nouveau/core/include/core/event.h
drivers/gpu/drm/nouveau/core/include/core/option.h
drivers/gpu/drm/nouveau/core/include/core/printk.h
drivers/gpu/drm/nouveau/core/include/engine/fifo.h
drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
drivers/gpu/drm/nouveau/core/include/engine/perfmon.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/engine/software.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bus.h
drivers/gpu/drm/nouveau/core/include/subdev/clock.h
drivers/gpu/drm/nouveau/core/include/subdev/fb.h
drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
drivers/gpu/drm/nouveau/core/include/subdev/mc.h
drivers/gpu/drm/nouveau/core/include/subdev/pwr.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/therm.h
drivers/gpu/drm/nouveau/core/include/subdev/volt.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/boost.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
drivers/gpu/drm/nouveau/core/subdev/bios/init.c
drivers/gpu/drm/nouveau/core/subdev/bios/perf.c
drivers/gpu/drm/nouveau/core/subdev/bios/pll.c
drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/timing.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/volt.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c
drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c
drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c
drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/clock/base.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
drivers/gpu/drm/nouveau/core/subdev/clock/seq.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
drivers/gpu/drm/nouveau/core/subdev/fb/base.c
drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
drivers/gpu/drm/nouveau/core/subdev/mc/base.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/base.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/therm/base.c
drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c
drivers/gpu/drm/nouveau/core/subdev/therm/ic.c
drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c
drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c
drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c
drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
drivers/gpu/drm/nouveau/core/subdev/therm/temp.c
drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
drivers/gpu/drm/nouveau/core/subdev/volt/base.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/dispnv04/Makefile
drivers/gpu/drm/nouveau/dispnv04/dfp.c
drivers/gpu/drm/nouveau/dispnv04/disp.c
drivers/gpu/drm/nouveau/dispnv04/disp.h
drivers/gpu/drm/nouveau/dispnv04/hw.c
drivers/gpu/drm/nouveau/dispnv04/overlay.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_agp.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_display.h
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_hwmon.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_hwmon.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_hwsq.h [deleted file]
drivers/gpu/drm/nouveau/nouveau_mem.c [deleted file]
drivers/gpu/drm/nouveau/nouveau_perf.c [deleted file]
drivers/gpu/drm/nouveau/nouveau_pm.c [deleted file]
drivers/gpu/drm/nouveau/nouveau_pm.h [deleted file]
drivers/gpu/drm/nouveau/nouveau_sysfs.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_sysfs.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_volt.c [deleted file]
drivers/gpu/drm/nouveau/nv04_pm.c [deleted file]
drivers/gpu/drm/nouveau/nv40_pm.c [deleted file]
drivers/gpu/drm/nouveau/nv50_pm.c [deleted file]
drivers/gpu/drm/nouveau/nva3_pm.c [deleted file]
drivers/gpu/drm/nouveau/nvc0_pm.c [deleted file]
drivers/gpu/drm/radeon/atombios.h
drivers/gpu/drm/radeon/atombios_crtc.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/ci_smc.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/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/r600.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_family.h
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_test.c
drivers/gpu/drm/radeon/radeon_ucode.h
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/radeon/trinity_dpm.c
drivers/gpu/drm/radeon/uvd_v1_0.c
drivers/gpu/drm/shmobile/shmob_drm_crtc.c
drivers/gpu/drm/ttm/Makefile
drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/hid/Kconfig
drivers/hid/hid-core.c
drivers/hid/hid-holtek-mouse.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-roccat-koneplus.c
drivers/hid/hid-roccat-kovaplus.c
drivers/hid/hid-roccat-pyra.c
drivers/hid/hid-wiimote-core.c
drivers/hid/hid-wiimote-modules.c
drivers/hid/hid-wiimote.h
drivers/hid/hidraw.c
drivers/hid/uhid.c
drivers/hid/usbhid/hid-quirks.c
drivers/hwmon/applesmc.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-stu300.c
drivers/i2c/i2c-core.c
drivers/i2c/muxes/i2c-arb-gpio-challenge.c
drivers/i2c/muxes/i2c-mux-gpio.c
drivers/i2c/muxes/i2c-mux-pinctrl.c
drivers/iio/amplifiers/ad8366.c
drivers/iio/frequency/adf4350.c
drivers/iio/industrialio-buffer.c
drivers/iio/industrialio-core.c
drivers/iio/magnetometer/st_magn_core.c
drivers/infiniband/Kconfig
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/amso1100/c2_ae.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/mlx5/srq.c
drivers/infiniband/hw/mthca/mthca_eq.c
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/input.c
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/misc/cm109.c
drivers/input/mouse/alps.c
drivers/input/serio/i8042.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/iommu/Kconfig
drivers/iommu/arm-smmu.c
drivers/md/bcache/request.c
drivers/md/dm-snap-persistent.c
drivers/md/md.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/media/dvb-frontends/tda10071.c
drivers/media/i2c/ad9389b.c
drivers/media/i2c/adv7511.c
drivers/media/i2c/adv7842.c
drivers/media/i2c/ths8200.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/platform/s5p-jpeg/jpeg-core.c
drivers/media/platform/sh_vou.c
drivers/media/platform/soc_camera/mx3_camera.c
drivers/media/tuners/e4000.c
drivers/media/usb/stkwebcam/stk-webcam.c
drivers/media/usb/uvc/uvc_driver.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/media/v4l2-core/videobuf2-dma-contig.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mtd/devices/m25p80.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/net/bonding/bond_main.c
drivers/net/can/at91_can.c
drivers/net/can/dev.c
drivers/net/can/flexcan.c
drivers/net/can/slcan.c
drivers/net/can/usb/peak_usb/pcan_usb_core.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
drivers/net/ethernet/calxeda/xgmac.c
drivers/net/ethernet/davicom/dm9000.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/gianfar.c
drivers/net/ethernet/freescale/gianfar_ptp.c
drivers/net/ethernet/intel/i40e/i40e_adminq.c
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/moxa/moxart_ether.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
drivers/net/ethernet/qlogic/qlge/qlge_mpi.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/mcdi.c
drivers/net/ethernet/sfc/mcdi_pcol.h
drivers/net/ethernet/sfc/nic.c
drivers/net/ethernet/sfc/nic.h
drivers/net/ethernet/smsc/smc91x.h
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/hamradio/yam.c
drivers/net/ieee802154/mrf24j40.c
drivers/net/slip/slip.c
drivers/net/tun.c
drivers/net/usb/ax88179_178a.c
drivers/net/usb/dm9601.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/vxlan.c
drivers/net/wan/farsync.c
drivers/net/wan/wanxl.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/cw1200/cw1200_spi.c
drivers/net/wireless/cw1200/fwio.c
drivers/net/wireless/cw1200/hwbus.h
drivers/net/wireless/cw1200/hwio.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/11n_aggr.h
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/xen-netback/xenbus.c
drivers/of/Kconfig
drivers/of/Makefile
drivers/of/base.c
drivers/of/fdt.c
drivers/of/of_reserved_mem.c [deleted file]
drivers/of/platform.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pinctrl/pinconf.c
drivers/pinctrl/pinctrl-exynos.c
drivers/pinctrl/pinctrl-palmas.c
drivers/pinctrl/pinctrl-tegra114.c
drivers/platform/x86/Kconfig
drivers/platform/x86/sony-laptop.c
drivers/regulator/da9063-regulator.c
drivers/regulator/palmas-regulator.c
drivers/regulator/ti-abb-regulator.c
drivers/regulator/wm831x-ldo.c
drivers/regulator/wm8350-regulator.c
drivers/s390/block/dasd_eckd.c
drivers/s390/char/sclp.c
drivers/s390/char/sclp_cmd.c
drivers/s390/char/tty3270.c
drivers/s390/char/vmlogrdr.c
drivers/s390/cio/cio.c
drivers/s390/cio/qdio_main.c
drivers/scsi/BusLogic.c
drivers/scsi/aacraid/linit.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/spi/spi-atmel.c
drivers/spi/spi-clps711x.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-mpc512x-psc.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sh-hspi.c
drivers/staging/bcm/Bcmchar.c
drivers/staging/comedi/drivers/ni_65xx.c
drivers/staging/media/msi3101/Kconfig
drivers/staging/media/msi3101/sdr-msi3101.c
drivers/staging/ozwpan/ozcdev.c
drivers/staging/sb105x/sb_pci_mp.c
drivers/staging/wlags49_h2/wl_priv.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_sbc.c
drivers/target/target_core_transport.c
drivers/target/target_core_xcopy.c
drivers/thermal/samsung/exynos_thermal_common.c
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/samsung/exynos_tmu.h
drivers/thermal/samsung/exynos_tmu_data.c
drivers/thermal/samsung/exynos_tmu_data.h
drivers/thermal/thermal_hwmon.c
drivers/thermal/ti-soc-thermal/ti-thermal-common.c
drivers/thermal/x86_pkg_temp_thermal.c
drivers/tty/hvc/hvc_xen.c
drivers/tty/n_tty.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/imx.c
drivers/tty/serial/vt8500_serial.c
drivers/uio/uio.c
drivers/usb/chipidea/ci_hdrc_pci.c
drivers/usb/chipidea/host.c
drivers/usb/core/quirks.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/Kconfig
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_virthub.c
drivers/usb/phy/phy-gpio-vbus-usb.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/unusual_devs.h
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/scsi.c
drivers/video/au1100fb.c
drivers/video/au1200fb.c
drivers/w1/w1.c
drivers/watchdog/hpwdt.c
drivers/watchdog/kempld_wdt.c
drivers/watchdog/sunxi_wdt.c
drivers/watchdog/ts72xx_wdt.c
fs/afs/dir.c
fs/aio.c
fs/binfmt_elf.c
fs/btrfs/async-thread.c
fs/btrfs/async-thread.h
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/transaction.c
fs/btrfs/volumes.c
fs/buffer.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifssmb.c
fs/cifs/file.c
fs/cifs/fscache.c
fs/cifs/fscache.h
fs/cifs/inode.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/smb2pdu.c
fs/cifs/smbfsctl.h
fs/cifs/transport.c
fs/dcache.c
fs/ecryptfs/crypto.c
fs/ecryptfs/keystore.c
fs/eventpoll.c
fs/ext3/namei.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/xattr.c
fs/file_table.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/jfs/jfs_inode.c
fs/namei.c
fs/nfs/dir.c
fs/nfs/nfs4file.c
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nilfs2/page.c
fs/nilfs2/segment.c
fs/ocfs2/dcache.c
fs/proc/inode.c
fs/proc/task_mmu.c
fs/select.c
fs/seq_file.c
fs/statfs.c
fs/super.c
fs/sysv/super.c
fs/xfs/xfs_dir2_block.c
fs/xfs/xfs_dir2_format.h
fs/xfs/xfs_dir2_readdir.c
fs/xfs/xfs_dir2_sf.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_log_recover.c
include/acpi/acpi_bus.h
include/asm-generic/hugetlb.h
include/asm-generic/vtime.h
include/drm/drm_pciids.h
include/drm/i915_drm.h
include/drm/i915_pciids.h
include/drm/ttm/ttm_page_alloc.h
include/dt-bindings/pinctrl/omap.h
include/linux/balloon_compaction.h
include/linux/bcma/bcma_driver_pci.h
include/linux/compiler-gcc4.h
include/linux/filter.h
include/linux/intel-iommu.h
include/linux/ipc_namespace.h
include/linux/kernel.h
include/linux/memcontrol.h
include/linux/miscdevice.h
include/linux/mlx5/device.h
include/linux/mlx5/driver.h
include/linux/netdevice.h
include/linux/nfs_xdr.h
include/linux/of_reserved_mem.h [deleted file]
include/linux/percpu.h
include/linux/perf_event.h
include/linux/random.h
include/linux/regulator/driver.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/tc_act/tc_defact.h [deleted file]
include/linux/timex.h
include/linux/usb/usb_phy_gen_xceiv.h
include/linux/usb/usbnet.h
include/linux/usb_usual.h
include/linux/vgaarb.h
include/linux/yam.h
include/net/addrconf.h
include/net/bluetooth/hci.h
include/net/cipso_ipv4.h
include/net/dst.h
include/net/ip6_route.h
include/net/ip_vs.h
include/net/mac802154.h
include/net/mrp.h
include/net/net_namespace.h
include/net/netfilter/nf_conntrack_synproxy.h
include/net/secure_seq.h
include/net/sock.h
include/sound/rcar_snd.h
include/trace/events/target.h
include/uapi/drm/drm_mode.h
include/uapi/linux/perf_event.h
include/uapi/linux/tc_act/Kbuild
include/uapi/linux/tc_act/tc_defact.h [new file with mode: 0644]
include/uapi/rdma/ib_user_verbs.h
init/main.c
ipc/ipc_sysctl.c
ipc/msg.c
ipc/sem.c
ipc/util.c
kernel/cgroup.c
kernel/events/core.c
kernel/events/ring_buffer.c
kernel/kmod.c
kernel/mutex.c
kernel/pid.c
kernel/power/hibernate.c
kernel/power/snapshot.c
kernel/power/user.c
kernel/softirq.c
kernel/time/clockevents.c
lib/Kconfig.debug
lib/hexdump.c
lib/kobject.c
lib/percpu-refcount.c
lib/scatterlist.c
mm/Kconfig
mm/bounce.c
mm/compaction.c
mm/filemap.c
mm/huge_memory.c
mm/hugetlb.c
mm/hwpoison-inject.c
mm/list_lru.c
mm/madvise.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/migrate.c
mm/mlock.c
mm/mprotect.c
mm/mremap.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/pagewalk.c
mm/slab_common.c
mm/swapfile.c
mm/vmscan.c
mm/zswap.c
net/802/mrp.c
net/8021q/vlan_netlink.c
net/batman-adv/main.c
net/batman-adv/network-coding.c
net/batman-adv/network-coding.h
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/rfcomm/tty.c
net/bridge/br_fdb.c
net/bridge/br_mdb.c
net/bridge/br_multicast.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/bridge/br_stp_if.c
net/bridge/br_vlan.c
net/compat.c
net/core/dev.c
net/core/filter.c
net/core/flow_dissector.c
net/core/secure_seq.c
net/core/sock.c
net/ieee802154/6lowpan.c
net/ipv4/af_inet.c
net/ipv4/igmp.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_output.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_tunnel_core.c
net/ipv4/ip_vti.c
net/ipv4/netfilter/ipt_SYNPROXY.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv4/xfrm4_policy.c
net/ipv6/addrconf.c
net/ipv6/ah6.c
net/ipv6/esp6.c
net/ipv6/inet6_hashtables.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ipcomp6.c
net/ipv6/mcast.c
net/ipv6/netfilter/ip6t_SYNPROXY.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/udp.c
net/ipv6/xfrm6_policy.c
net/key/af_key.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/l2tp/l2tp_ppp.c
net/lapb/lapb_timer.c
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/offchannel.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_est.c
net/netfilter/ipvs/ip_vs_lblc.c
net/netfilter/ipvs/ip_vs_lblcr.c
net/netfilter/ipvs/ip_vs_nq.c
net/netfilter/ipvs/ip_vs_sed.c
net/netfilter/ipvs/ip_vs_wlc.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_synproxy_core.c
net/sched/sch_fq.c
net/sched/sch_netem.c
net/sctp/output.c
net/socket.c
net/sysctl_net.c
net/unix/af_unix.c
net/unix/diag.c
net/wireless/core.c
net/wireless/core.h
net/wireless/ibss.c
net/wireless/nl80211.c
net/wireless/radiotap.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_replay.c
net/xfrm/xfrm_user.c
scripts/kallsyms.c
scripts/link-vmlinux.sh
security/apparmor/apparmorfs.c
security/apparmor/crypto.c
security/apparmor/include/policy.h
security/apparmor/policy.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/avc.h
sound/core/pcm.c
sound/pci/ac97/ac97_codec.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_generic.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/rme9652/hdsp.c
sound/soc/blackfin/bf6xx-i2s.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/max98095.c
sound/soc/codecs/pcm1681.c
sound/soc/codecs/pcm1792a.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/wm_hubs.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-mc13783.c
sound/soc/fsl/imx-sgtl5000.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/imx-ssi.h
sound/soc/omap/Kconfig
sound/soc/sh/rcar/rsnd.h
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/usb/usx2y/us122l.c
sound/usb/usx2y/usbusx2yaudio.c
sound/usb/usx2y/usx2yhwdeppcm.c
tools/perf/Documentation/perf-record.txt
tools/perf/Documentation/perf-top.txt
tools/perf/Makefile
tools/perf/builtin-kvm.c
tools/perf/builtin-record.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/config/feature-tests.mak
tools/perf/tests/code-reading.c
tools/perf/tests/keep-tracking.c
tools/perf/tests/mmap-basic.c
tools/perf/tests/open-syscall-tp-fields.c
tools/perf/tests/perf-record.c
tools/perf/tests/perf-time-to-tsc.c
tools/perf/tests/sw-clock.c
tools/perf/tests/task-exit.c
tools/perf/ui/stdio/hist.c
tools/perf/util/callchain.h
tools/perf/util/dwarf-aux.c
tools/perf/util/dwarf-aux.h
tools/perf/util/event.c
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/header.c
tools/perf/util/hist.h
tools/perf/util/probe-finder.c
tools/perf/util/python.c
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/testing/selftests/timers/posix_timers.c
virt/kvm/kvm_main.c

index 2be603c..a6b6857 100644 (file)
@@ -37,8 +37,8 @@ Description:
                that the USB device has been connected to the machine.  This
                file is read-only.
 Users:
-               PowerTOP <power@bughost.org>
-               http://www.lesswatts.org/projects/powertop/
+               PowerTOP <powertop@lists.01.org>
+               https://01.org/powertop/
 
 What:          /sys/bus/usb/device/.../power/active_duration
 Date:          January 2008
@@ -57,8 +57,8 @@ Description:
                will give an integer percentage.  Note that this does not
                account for counter wrap.
 Users:
-               PowerTOP <power@bughost.org>
-               http://www.lesswatts.org/projects/powertop/
+               PowerTOP <powertop@lists.01.org>
+               https://01.org/powertop/
 
 What:          /sys/bus/usb/devices/<busnum>-<port[.port]>...:<config num>-<interface num>/supports_autosuspend
 Date:          January 2008
index 9d43e76..efe449b 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/devices/.../power/
 Date:          January 2009
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power directory contains attributes
                allowing the user space to check and modify some power
@@ -8,7 +8,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup
 Date:          January 2009
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power/wakeup attribute allows the user
                space to check if the device is enabled to wake up the system
@@ -34,7 +34,7 @@ Description:
 
 What:          /sys/devices/.../power/control
 Date:          January 2009
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power/control attribute allows the user
                space to control the run-time power management of the device.
@@ -53,7 +53,7 @@ Description:
 
 What:          /sys/devices/.../power/async
 Date:          January 2009
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../async attribute allows the user space to
                enable or diasble the device's suspend and resume callbacks to
@@ -79,7 +79,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_count
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_count attribute contains the number
                of signaled wakeup events associated with the device.  This
@@ -88,7 +88,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_active_count
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_active_count attribute contains the
                number of times the processing of wakeup events associated with
@@ -98,7 +98,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_abort_count
 Date:          February 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_abort_count attribute contains the
                number of times the processing of a wakeup event associated with
@@ -109,7 +109,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_expire_count
 Date:          February 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_expire_count attribute contains the
                number of times a wakeup event associated with the device has
@@ -119,7 +119,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_active
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_active attribute contains either 1,
                or 0, depending on whether or not a wakeup event associated with
@@ -129,7 +129,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_total_time_ms
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_total_time_ms attribute contains
                the total time of processing wakeup events associated with the
@@ -139,7 +139,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_max_time_ms
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_max_time_ms attribute contains
                the maximum time of processing a single wakeup event associated
@@ -149,7 +149,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_last_time_ms
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_last_time_ms attribute contains
                the value of the monotonic clock corresponding to the time of
@@ -160,7 +160,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_prevent_sleep_time_ms
 Date:          February 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute
                contains the total time the device has been preventing
@@ -189,7 +189,7 @@ Description:
 
 What:          /sys/devices/.../power/pm_qos_latency_us
 Date:          March 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power/pm_qos_resume_latency_us attribute
                contains the PM QoS resume latency limit for the given device,
@@ -207,7 +207,7 @@ Description:
 
 What:          /sys/devices/.../power/pm_qos_no_power_off
 Date:          September 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power/pm_qos_no_power_off attribute
                is used for manipulating the PM QoS "no power off" flag.  If
@@ -222,7 +222,7 @@ Description:
 
 What:          /sys/devices/.../power/pm_qos_remote_wakeup
 Date:          September 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power/pm_qos_remote_wakeup attribute
                is used for manipulating the PM QoS "remote wakeup required"
index 2177726..205a738 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/power/
 Date:          August 2006
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power directory will contain files that will
                provide a unified interface to the power management
@@ -8,7 +8,7 @@ Description:
 
 What:          /sys/power/state
 Date:          August 2006
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/state file controls the system power state.
                Reading from this file returns what states are supported,
@@ -22,7 +22,7 @@ Description:
 
 What:          /sys/power/disk
 Date:          September 2006
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/disk file controls the operating mode of the
                suspend-to-disk mechanism.  Reading from this file returns
@@ -67,7 +67,7 @@ Description:
 
 What:          /sys/power/image_size
 Date:          August 2006
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/image_size file controls the size of the image
                created by the suspend-to-disk mechanism.  It can be written a
@@ -84,7 +84,7 @@ Description:
 
 What:          /sys/power/pm_trace
 Date:          August 2006
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/pm_trace file controls the code which saves the
                last PM event point in the RTC across reboots, so that you can
@@ -133,7 +133,7 @@ Description:
 
 What:          /sys/power/pm_async
 Date:          January 2009
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/pm_async file controls the switch allowing the
                user space to enable or disable asynchronous suspend and resume
@@ -146,7 +146,7 @@ Description:
 
 What:          /sys/power/wakeup_count
 Date:          July 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/wakeup_count file allows user space to put the
                system into a sleep state while taking into account the
@@ -161,7 +161,7 @@ Description:
 
 What:          /sys/power/reserved_size
 Date:          May 2011
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/reserved_size file allows user space to control
                the amount of memory reserved for allocations made by device
@@ -175,7 +175,7 @@ Description:
 
 What:          /sys/power/autosleep
 Date:          April 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/autosleep file can be written one of the strings
                returned by reads from /sys/power/state.  If that happens, a
@@ -192,7 +192,7 @@ Description:
 
 What:          /sys/power/wake_lock
 Date:          February 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/wake_lock file allows user space to create
                wakeup source objects and activate them on demand (if one of
@@ -219,7 +219,7 @@ Description:
 
 What:          /sys/power/wake_unlock
 Date:          February 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/wake_unlock file allows user space to deactivate
                wakeup sources created with the help of /sys/power/wake_lock.
index febbb1b..784841c 100644 (file)
@@ -4,4 +4,4 @@ CONFIG_ACPI_CUSTOM_DSDT builds the image into the kernel.
 
 When to use this method is described in detail on the
 Linux/ACPI home page:
-http://www.lesswatts.org/projects/acpi/overridingDSDT.php
+https://01.org/linux-acpi/documentation/overriding-dsdt
index d18ecd8..929d990 100644 (file)
@@ -6,6 +6,8 @@ capability.txt
        - Generic Block Device Capability (/sys/block/<device>/capability)
 cfq-iosched.txt
        - CFQ IO scheduler tunables
+cmdline-partition.txt
+       - how to specify block device partitions on kernel command line
 data-integrity.txt
        - Block data integrity
 deadline-iosched.txt
index 2bbf4cc..525b9f6 100644 (file)
@@ -1,9 +1,9 @@
-Embedded device command line partition
+Embedded device command line partition parsing
 =====================================================================
 
-Read block device partition table from command line.
-The partition used for fixed block device (eMMC) embedded device.
-It is no MBR, save storage space. Bootloader can be easily accessed
+Support for reading the block device partition table from the command line.
+It is typically used for fixed block (eMMC) embedded devices.
+It has no MBR, so saves storage space. Bootloader can be easily accessed
 by absolute address of data on the block device.
 Users can easily change the partition.
 
index 4848db8..8a4da64 100644 (file)
@@ -71,7 +71,7 @@ static int netlink_send(int s, struct cn_msg *msg)
        nlh->nlmsg_seq = seq++;
        nlh->nlmsg_pid = getpid();
        nlh->nlmsg_type = NLMSG_DONE;
-       nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
+       nlh->nlmsg_len = size;
        nlh->nlmsg_flags = 0;
 
        m = NLMSG_DATA(nlh);
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
deleted file mode 100644 (file)
index eb24693..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-*** Memory binding ***
-
-The /memory node provides basic information about the address and size
-of the physical memory. This node is usually filled or updated by the
-bootloader, depending on the actual memory configuration of the given
-hardware.
-
-The memory layout is described by the following node:
-
-/ {
-       #address-cells = <(n)>;
-       #size-cells = <(m)>;
-       memory {
-               device_type = "memory";
-               reg =  <(baseaddr1) (size1)
-                       (baseaddr2) (size2)
-                       ...
-                       (baseaddrN) (sizeN)>;
-       };
-       ...
-};
-
-A memory node follows the typical device tree rules for "reg" property:
-n:             number of cells used to store base address value
-m:             number of cells used to store size value
-baseaddrX:     defines a base address of the defined memory bank
-sizeX:         the size of the defined memory bank
-
-
-More than one memory bank can be defined.
-
-
-*** Reserved memory regions ***
-
-In /memory/reserved-memory node one can create child nodes describing
-particular reserved (excluded from normal use) memory regions. Such
-memory regions are usually designed for the special usage by various
-device drivers. A good example are contiguous memory allocations or
-memory sharing with other operating system on the same hardware board.
-Those special memory regions might depend on the board configuration and
-devices used on the target system.
-
-Parameters for each memory region can be encoded into the device tree
-with the following convention:
-
-[(label):] (name) {
-       compatible = "linux,contiguous-memory-region", "reserved-memory-region";
-       reg = <(address) (size)>;
-       (linux,default-contiguous-region);
-};
-
-compatible:    one or more of:
-       - "linux,contiguous-memory-region" - enables binding of this
-         region to Contiguous Memory Allocator (special region for
-         contiguous memory allocations, shared with movable system
-         memory, Linux kernel-specific).
-       - "reserved-memory-region" - compatibility is defined, given
-         region is assigned for exclusive usage for by the respective
-         devices.
-
-reg:   standard property defining the base address and size of
-       the memory region
-
-linux,default-contiguous-region: property indicating that the region
-       is the default region for all contiguous memory
-       allocations, Linux specific (optional)
-
-It is optional to specify the base address, so if one wants to use
-autoconfiguration of the base address, '0' can be specified as a base
-address in the 'reg' property.
-
-The /memory/reserved-memory node must contain the same #address-cells
-and #size-cells value as the root node.
-
-
-*** Device node's properties ***
-
-Once regions in the /memory/reserved-memory node have been defined, they
-may be referenced by other device nodes. Bindings that wish to reference
-memory regions should explicitly document their use of the following
-property:
-
-memory-region = <&phandle_to_defined_region>;
-
-This property indicates that the device driver should use the memory
-region pointed by the given phandle.
-
-
-*** Example ***
-
-This example defines a memory consisting of 4 memory banks. 3 contiguous
-regions are defined for Linux kernel, one default of all device drivers
-(named contig_mem, placed at 0x72000000, 64MiB), one dedicated to the
-framebuffer device (labelled display_mem, placed at 0x78000000, 8MiB)
-and one for multimedia processing (labelled multimedia_mem, placed at
-0x77000000, 64MiB). 'display_mem' region is then assigned to fb@12300000
-device for DMA memory allocations (Linux kernel drivers will use CMA is
-available or dma-exclusive usage otherwise). 'multimedia_mem' is
-assigned to scaler@12500000 and codec@12600000 devices for contiguous
-memory allocations when CMA driver is enabled.
-
-The reason for creating a separate region for framebuffer device is to
-match the framebuffer base address to the one configured by bootloader,
-so once Linux kernel drivers starts no glitches on the displayed boot
-logo appears. Scaller and codec drivers should share the memory
-allocations.
-
-/ {
-       #address-cells = <1>;
-       #size-cells = <1>;
-
-       /* ... */
-
-       memory {
-               reg =  <0x40000000 0x10000000
-                       0x50000000 0x10000000
-                       0x60000000 0x10000000
-                       0x70000000 0x10000000>;
-
-               reserved-memory {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       /*
-                        * global autoconfigured region for contiguous allocations
-                        * (used only with Contiguous Memory Allocator)
-                        */
-                       contig_region@0 {
-                               compatible = "linux,contiguous-memory-region";
-                               reg = <0x0 0x4000000>;
-                               linux,default-contiguous-region;
-                       };
-
-                       /*
-                        * special region for framebuffer
-                        */
-                       display_region: region@78000000 {
-                               compatible = "linux,contiguous-memory-region", "reserved-memory-region";
-                               reg = <0x78000000 0x800000>;
-                       };
-
-                       /*
-                        * special region for multimedia processing devices
-                        */
-                       multimedia_region: region@77000000 {
-                               compatible = "linux,contiguous-memory-region";
-                               reg = <0x77000000 0x4000000>;
-                       };
-               };
-       };
-
-       /* ... */
-
-       fb0: fb@12300000 {
-               status = "okay";
-               memory-region = <&display_region>;
-       };
-
-       scaler: scaler@12500000 {
-               status = "okay";
-               memory-region = <&multimedia_region>;
-       };
-
-       codec: codec@12600000 {
-               status = "okay";
-               memory-region = <&multimedia_region>;
-       };
-};
index df204e1..6a2a116 100644 (file)
@@ -9,12 +9,15 @@ compulsory and any optional properties, common to all SD/MMC drivers, as
 described in mmc.txt, can be used. Additionally the following tmio_mmc-specific
 optional bindings can be used.
 
+Required properties:
+- compatible:  "renesas,sdhi-shmobile" - a generic sh-mobile SDHI unit
+               "renesas,sdhi-sh7372" - SDHI IP on SH7372 SoC
+               "renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
+               "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
+               "renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
+               "renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
+               "renesas,sdhi-r8a7779" - SDHI IP on R8A7779 SoC
+               "renesas,sdhi-r8a7790" - SDHI IP on R8A7790 SoC
+
 Optional properties:
 - toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
-
-When used with Renesas SDHI hardware, the following compatibility strings
-configure various model-specific properties:
-
-"renesas,sh7372-sdhi": (default) compatible with SH7372
-"renesas,r8a7740-sdhi":        compatible with R8A7740: certain MMC/SD commands have to
-                       wait for the interface to become idle.
index 2c6be03..d2ea460 100644 (file)
@@ -86,6 +86,7 @@ General Properties:
 
 Clock Properties:
 
+  - fsl,cksel        Timer reference clock source.
   - fsl,tclk-period  Timer reference clock period in nanoseconds.
   - fsl,tmr-prsc     Prescaler, divides the output clock.
   - fsl,tmr-add      Frequency compensation value.
@@ -97,7 +98,7 @@ Clock Properties:
   clock. You must choose these carefully for the clock to work right.
   Here is how to figure good values:
 
-  TimerOsc     = system clock               MHz
+  TimerOsc     = selected reference clock   MHz
   tclk_period  = desired clock period       nanoseconds
   NominalFreq  = 1000 / tclk_period         MHz
   FreqDivRatio = TimerOsc / NominalFreq     (must be greater that 1.0)
@@ -114,6 +115,20 @@ Clock Properties:
   Pulse Per Second (PPS) signal, since this will be offered to the PPS
   subsystem to synchronize the Linux clock.
 
+  Reference clock source is determined by the value, which is holded
+  in CKSEL bits in TMR_CTRL register. "fsl,cksel" property keeps the
+  value, which will be directly written in those bits, that is why,
+  according to reference manual, the next clock sources can be used:
+
+  <0> - external high precision timer reference clock (TSEC_TMR_CLK
+        input is used for this purpose);
+  <1> - eTSEC system clock;
+  <2> - eTSEC1 transmit clock;
+  <3> - RTC clock input.
+
+  When this attribute is not used, eTSEC system clock will serve as
+  IEEE 1588 timer reference clock.
+
 Example:
 
        ptp_clock@24E00 {
@@ -121,6 +136,7 @@ Example:
                reg = <0x24E00 0xB0>;
                interrupts = <12 0x8 13 0x8>;
                interrupt-parent = < &ipic >;
+               fsl,cksel       = <1>;
                fsl,tclk-period = <10>;
                fsl,tmr-prsc    = <100>;
                fsl,tmr-add     = <0x999999A4>;
index 539a236..fcbb736 100644 (file)
@@ -480,6 +480,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Format: <io>,<irq>,<mode>
                        See header of drivers/net/hamradio/baycom_ser_hdx.c.
 
+       blkdevparts=    Manual partition parsing of block device(s) for
+                       embedded devices based on command line input.
+                       See Documentation/block/cmdline-partition.txt
+
        boot_delay=     Milliseconds to delay each printk during boot.
                        Values larger than 10 seconds (10000) are changed to
                        no delay (0).
@@ -1357,7 +1361,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        pages. In the event, a node is too small to have both
                        kernelcore and Movable pages, kernelcore pages will
                        take priority and other nodes will have a larger number
-                       of kernelcore pages.  The Movable zone is used for the
+                       of Movable pages.  The Movable zone is used for the
                        allocation of pages that may be reclaimed or moved
                        by the page migration subsystem.  This means that
                        HugeTLB pages may not be allocated from this zone.
index f911e36..85c362d 100644 (file)
@@ -28,6 +28,7 @@ ALC269/270/275/276/28x/29x
   alc269-dmic          Enable ALC269(VA) digital mic workaround
   alc271-dmic          Enable ALC271X digital mic workaround
   inv-dmic             Inverted internal mic workaround
+  headset-mic          Indicates a combined headset (headphone+mic) jack
   lenovo-dock          Enables docking station I/O for some Lenovos
   dell-headset-multi   Headset jack, which can also be used as mic-in
   dell-headset-dock    Headset jack (without mic-in), and also dock I/O
index 4907a74..63dbfc3 100644 (file)
@@ -237,11 +237,11 @@ F:        drivers/platform/x86/acer-wmi.c
 
 ACPI
 M:     Len Brown <lenb@kernel.org>
-M:     Rafael J. Wysocki <rjw@sisk.pl>
+M:     Rafael J. Wysocki <rjw@rjwysocki.net>
 L:     linux-acpi@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
-Q:     http://patchwork.kernel.org/project/linux-acpi/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
+W:     https://01.org/linux-acpi
+Q:     https://patchwork.kernel.org/project/linux-acpi/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
 S:     Supported
 F:     drivers/acpi/
 F:     drivers/pnp/pnpacpi/
@@ -256,21 +256,21 @@ F:        drivers/pci/*/*/*acpi*
 ACPI FAN DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
+W:     https://01.org/linux-acpi
 S:     Supported
 F:     drivers/acpi/fan.c
 
 ACPI THERMAL DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
+W:     https://01.org/linux-acpi
 S:     Supported
 F:     drivers/acpi/*thermal*
 
 ACPI VIDEO DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
+W:     https://01.org/linux-acpi
 S:     Supported
 F:     drivers/acpi/video.c
 
@@ -824,15 +824,21 @@ S:        Maintained
 F:     arch/arm/mach-gemini/
 
 ARM/CSR SIRFPRIMA2 MACHINE SUPPORT
-M:     Barry Song <baohua.song@csr.com>
+M:     Barry Song <baohua@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/baohua/linux.git
 S:     Maintained
 F:     arch/arm/mach-prima2/
+F:     drivers/clk/clk-prima2.c
+F:     drivers/clocksource/timer-prima2.c
+F:     drivers/clocksource/timer-marco.c
 F:     drivers/dma/sirf-dma.c
 F:     drivers/i2c/busses/i2c-sirf.c
+F:     drivers/input/misc/sirfsoc-onkey.c
+F:     drivers/irqchip/irq-sirfsoc.c
 F:     drivers/mmc/host/sdhci-sirf.c
 F:     drivers/pinctrl/sirf/
+F:     drivers/rtc/rtc-sirfsoc.c
 F:     drivers/spi/spi-sirf.c
 
 ARM/EBSA110 MACHINE SUPPORT
@@ -1003,6 +1009,7 @@ ARM/Marvell Armada 370 and Armada XP SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
 M:     Andrew Lunn <andrew@lunn.ch>
 M:     Gregory Clement <gregory.clement@free-electrons.com>
+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/
@@ -1010,6 +1017,7 @@ F:        arch/arm/mach-mvebu/
 ARM/Marvell Dove/Kirkwood/MV78xx0/Orion SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
 M:     Andrew Lunn <andrew@lunn.ch>
+M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-dove/
@@ -1142,6 +1150,13 @@ F:       drivers/net/ethernet/i825xx/ether1*
 F:     drivers/net/ethernet/seeq/ether3*
 F:     drivers/scsi/arm/
 
+ARM/Rockchip SoC support
+M:     Heiko Stuebner <heiko@sntech.de>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-rockchip/
+F:     drivers/*/*rockchip*
+
 ARM/SHARK MACHINE SUPPORT
 M:     Alexander Schulz <alex@shark-linux.de>
 W:     http://www.shark-linux.de/shark.html
@@ -1785,6 +1800,7 @@ F:        include/net/bluetooth/
 
 BONDING DRIVER
 M:     Jay Vosburgh <fubar@us.ibm.com>
+M:     Veaceslav Falico <vfalico@redhat.com>
 M:     Andy Gospodarek <andy@greyhouse.net>
 L:     netdev@vger.kernel.org
 W:     http://sourceforge.net/projects/bonding/
@@ -2294,7 +2310,7 @@ S:        Maintained
 F:     drivers/net/ethernet/ti/cpmac.c
 
 CPU FREQUENCY DRIVERS
-M:     Rafael J. Wysocki <rjw@sisk.pl>
+M:     Rafael J. Wysocki <rjw@rjwysocki.net>
 M:     Viresh Kumar <viresh.kumar@linaro.org>
 L:     cpufreq@vger.kernel.org
 L:     linux-pm@vger.kernel.org
@@ -2325,7 +2341,7 @@ S:      Maintained
 F:      drivers/cpuidle/cpuidle-big_little.c
 
 CPUIDLE DRIVERS
-M:     Rafael J. Wysocki <rjw@sisk.pl>
+M:     Rafael J. Wysocki <rjw@rjwysocki.net>
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
@@ -2712,6 +2728,8 @@ T:        git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
 M:     Vinod Koul <vinod.koul@intel.com>
 M:     Dan Williams <dan.j.williams@intel.com>
+L:     dmaengine@vger.kernel.org
+Q:     https://patchwork.kernel.org/project/linux-dmaengine/list/
 S:     Supported
 F:     drivers/dma/
 F:     include/linux/dma*
@@ -2815,7 +2833,7 @@ M:        Terje Bergström <tbergstrom@nvidia.com>
 L:     dri-devel@lists.freedesktop.org
 L:     linux-tegra@vger.kernel.org
 T:     git git://anongit.freedesktop.org/tegra/linux.git
-S:     Maintained
+S:     Supported
 F:     drivers/gpu/drm/tegra/
 F:     drivers/gpu/host1x/
 F:     include/linux/host1x.h
@@ -3549,7 +3567,7 @@ F:        fs/freevxfs/
 
 FREEZER
 M:     Pavel Machek <pavel@ucw.cz>
-M:     "Rafael J. Wysocki" <rjw@sisk.pl>
+M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     Documentation/power/freezing-of-tasks.txt
@@ -3620,6 +3638,12 @@ L:       linux-scsi@vger.kernel.org
 S:     Odd Fixes (e.g., new signatures)
 F:     drivers/scsi/fdomain.*
 
+GCOV BASED KERNEL PROFILING
+M:     Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+S:     Maintained
+F:     kernel/gcov/
+F:     Documentation/gcov.txt
+
 GDT SCSI DISK ARRAY CONTROLLER DRIVER
 M:     Achim Leubner <achim_leubner@adaptec.com>
 L:     linux-scsi@vger.kernel.org
@@ -3885,7 +3909,7 @@ F:        drivers/video/hgafb.c
 
 HIBERNATION (aka Software Suspend, aka swsusp)
 M:     Pavel Machek <pavel@ucw.cz>
-M:     "Rafael J. Wysocki" <rjw@sisk.pl>
+M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     arch/x86/power/
@@ -4335,7 +4359,7 @@ F:        drivers/video/i810/
 INTEL MENLOW THERMAL DRIVER
 M:     Sujith Thomas <sujith.thomas@intel.com>
 L:     platform-driver-x86@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
+W:     https://01.org/linux-acpi
 S:     Supported
 F:     drivers/platform/x86/intel_menlow.c
 
@@ -4347,7 +4371,10 @@ F:       arch/x86/kernel/microcode_intel.c
 
 INTEL I/OAT DMA DRIVER
 M:     Dan Williams <dan.j.williams@intel.com>
-S:     Maintained
+M:     Dave Jiang <dave.jiang@intel.com>
+L:     dmaengine@vger.kernel.org
+Q:     https://patchwork.kernel.org/project/linux-dmaengine/list/
+S:     Supported
 F:     drivers/dma/ioat*
 
 INTEL IOMMU (VT-d)
@@ -4472,6 +4499,13 @@ L:       linux-serial@vger.kernel.org
 S:     Maintained
 F:     drivers/tty/serial/ioc3_serial.c
 
+IOMMU DRIVERS
+M:     Joerg Roedel <joro@8bytes.org>
+L:     iommu@lists.linux-foundation.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
+S:     Maintained
+F:     drivers/iommu/
+
 IP MASQUERADING
 M:     Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
 S:     Maintained
@@ -7273,9 +7307,9 @@ F:        include/linux/sched.h
 F:     include/uapi/linux/sched.h
 
 SCORE ARCHITECTURE
-M:     Chen Liqin <liqin.chen@sunplusct.com>
+M:     Chen Liqin <liqin.linux@gmail.com>
 M:     Lennox Wu <lennox.wu@gmail.com>
-W:     http://www.sunplusct.com
+W:     http://www.sunplus.com
 S:     Supported
 F:     arch/score/
 
@@ -7805,6 +7839,13 @@ F:       Documentation/sound/alsa/soc/
 F:     sound/soc/
 F:     include/sound/soc*
 
+SOUND - DMAENGINE HELPERS
+M:     Lars-Peter Clausen <lars@metafoo.de>
+S:     Supported
+F:     include/sound/dmaengine_pcm.h
+F:     sound/core/pcm_dmaengine.c
+F:     sound/soc/soc-generic-dmaengine-pcm.c
+
 SPARC + UltraSPARC (sparc/sparc64)
 M:     "David S. Miller" <davem@davemloft.net>
 L:     sparclinux@vger.kernel.org
@@ -8084,7 +8125,7 @@ F:        drivers/sh/
 SUSPEND TO RAM
 M:     Len Brown <len.brown@intel.com>
 M:     Pavel Machek <pavel@ucw.cz>
-M:     "Rafael J. Wysocki" <rjw@sisk.pl>
+M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     Documentation/power/
@@ -8277,14 +8318,72 @@ L:      linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/rc/ttusbir.c
 
-TEGRA SUPPORT
+TEGRA ARCHITECTURE SUPPORT
 M:     Stephen Warren <swarren@wwwdotorg.org>
+M:     Thierry Reding <thierry.reding@gmail.com>
 L:     linux-tegra@vger.kernel.org
 Q:     http://patchwork.ozlabs.org/project/linux-tegra/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra.git
 S:     Supported
 N:     [^a-z]tegra
 
+TEGRA ASOC DRIVER
+M:     Stephen Warren <swarren@wwwdotorg.org>
+S:     Supported
+F:     sound/soc/tegra/
+
+TEGRA CLOCK DRIVER
+M:     Peter De Schrijver <pdeschrijver@nvidia.com>
+M:     Prashant Gaikwad <pgaikwad@nvidia.com>
+S:     Supported
+F:     drivers/clk/tegra/
+
+TEGRA DMA DRIVER
+M:     Laxman Dewangan <ldewangan@nvidia.com>
+S:     Supported
+F:     drivers/dma/tegra20-apb-dma.c
+
+TEGRA GPIO DRIVER
+M:     Stephen Warren <swarren@wwwdotorg.org>
+S:     Supported
+F:     drivers/gpio/gpio-tegra.c
+
+TEGRA I2C DRIVER
+M:     Laxman Dewangan <ldewangan@nvidia.com>
+S:     Supported
+F:     drivers/i2c/busses/i2c-tegra.c
+
+TEGRA IOMMU DRIVERS
+M:     Hiroshi Doyu <hdoyu@nvidia.com>
+S:     Supported
+F:     drivers/iommu/tegra*
+
+TEGRA KBC DRIVER
+M:     Rakesh Iyer <riyer@nvidia.com>
+M:     Laxman Dewangan <ldewangan@nvidia.com>
+S:     Supported
+F:     drivers/input/keyboard/tegra-kbc.c
+
+TEGRA PINCTRL DRIVER
+M:     Stephen Warren <swarren@wwwdotorg.org>
+S:     Supported
+F:     drivers/pinctrl/pinctrl-tegra*
+
+TEGRA PWM DRIVER
+M:     Thierry Reding <thierry.reding@gmail.com>
+S:     Supported
+F:     drivers/pwm/pwm-tegra.c
+
+TEGRA SERIAL DRIVER
+M:     Laxman Dewangan <ldewangan@nvidia.com>
+S:     Supported
+F:     drivers/tty/serial/serial-tegra.c
+
+TEGRA SPI DRIVER
+M:     Laxman Dewangan <ldewangan@nvidia.com>
+S:     Supported
+F:     drivers/spi/spi-tegra*
+
 TEHUTI ETHERNET DRIVER
 M:     Andy Gospodarek <andy@greyhouse.net>
 L:     netdev@vger.kernel.org
@@ -8820,61 +8919,14 @@ W:      http://pegasus2.sourceforge.net/
 S:     Maintained
 F:     drivers/net/usb/rtl8150.c
 
-USB SERIAL BELKIN F5U103 DRIVER
-M:     William Greathouse <wgreathouse@smva.com>
-L:     linux-usb@vger.kernel.org
-S:     Maintained
-F:     drivers/usb/serial/belkin_sa.*
-
-USB SERIAL CYPRESS M8 DRIVER
-M:     Lonnie Mendez <dignome@gmail.com>
+USB SERIAL SUBSYSTEM
+M:     Johan Hovold <jhovold@gmail.com>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
-W:     http://geocities.com/i0xox0i
-W:     http://firstlight.net/cvs
-F:     drivers/usb/serial/cypress_m8.*
-
-USB SERIAL CYBERJACK DRIVER
-M:     Matthias Bruestle and Harald Welte <support@reiner-sct.com>
-W:     http://www.reiner-sct.de/support/treiber_cyberjack.php
-S:     Maintained
-F:     drivers/usb/serial/cyberjack.c
-
-USB SERIAL DIGI ACCELEPORT DRIVER
-M:     Peter Berger <pberger@brimson.com>
-M:     Al Borchers <alborchers@steinerpoint.com>
-L:     linux-usb@vger.kernel.org
-S:     Maintained
-F:     drivers/usb/serial/digi_acceleport.c
-
-USB SERIAL DRIVER
-M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-L:     linux-usb@vger.kernel.org
-S:     Supported
 F:     Documentation/usb/usb-serial.txt
-F:     drivers/usb/serial/generic.c
-F:     drivers/usb/serial/usb-serial.c
+F:     drivers/usb/serial/
 F:     include/linux/usb/serial.h
 
-USB SERIAL EMPEG EMPEG-CAR MARK I/II DRIVER
-M:     Gary Brubaker <xavyer@ix.netcom.com>
-L:     linux-usb@vger.kernel.org
-S:     Maintained
-F:     drivers/usb/serial/empeg.c
-
-USB SERIAL KEYSPAN DRIVER
-M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-L:     linux-usb@vger.kernel.org
-S:     Maintained
-F:     drivers/usb/serial/*keyspan*
-
-USB SERIAL WHITEHEAT DRIVER
-M:     Support Department <support@connecttech.com>
-L:     linux-usb@vger.kernel.org
-W:     http://www.connecttech.com
-S:     Supported
-F:     drivers/usb/serial/whiteheat*
-
 USB SMSC75XX ETHERNET DRIVER
 M:     Steve Glendinning <steve.glendinning@shawell.net>
 L:     netdev@vger.kernel.org
@@ -9380,6 +9432,7 @@ F:        arch/arm64/include/asm/xen/
 
 XEN NETWORK BACKEND DRIVER
 M:     Ian Campbell <ian.campbell@citrix.com>
+M:     Wei Liu <wei.liu2@citrix.com>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
 L:     netdev@vger.kernel.org
 S:     Supported
index 2ae108d..67077ad 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 12
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION =
 NAME = One Giant Leap for Frogkind
 
 # *DOCUMENTATION*
index f158197..b6a8c2d 100644 (file)
@@ -45,7 +45,14 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
 
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 {
-       lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+       unsigned int tmp = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+       __asm__ __volatile__(
+       "       ex  %0, [%1]            \n"
+       : "+r" (tmp)
+       : "r"(&(lock->slock))
+       : "memory");
+
        smp_mb();
 }
 
index 3242082..30c9baf 100644 (file)
@@ -43,7 +43,7 @@
  * Because it essentially checks if buffer end is within limit and @len is
  * non-ngeative, which implies that buffer start will be within limit too.
  *
- * The reason for rewriting being, for majorit yof cases, @len is generally
+ * The reason for rewriting being, for majoritof cases, @len is generally
  * compile time constant, causing first sub-expression to be compile time
  * subsumed.
  *
@@ -53,7 +53,7 @@
  *
  */
 #define __user_ok(addr, sz)    (((sz) <= TASK_SIZE) && \
-                                (((addr)+(sz)) <= get_fs()))
+                                ((addr) <= (get_fs() - (sz))))
 #define __access_ok(addr, sz)  (unlikely(__kernel_ok) || \
                                 likely(__user_ok((addr), (sz))))
 
index 3332385..5d76706 100644 (file)
@@ -102,7 +102,7 @@ static int genregs_set(struct task_struct *target,
        REG_IGNORE_ONE(pad2);
        REG_IN_CHUNK(callee, efa, cregs);       /* callee_regs[r25..r13] */
        REG_IGNORE_ONE(efa);                    /* efa update invalid */
-       REG_IN_ONE(stop_pc, &ptregs->ret);      /* stop_pc: PC update */
+       REG_IGNORE_ONE(stop_pc);                        /* PC updated via @ret */
 
        return ret;
 }
index ee6ef2f..7e95e1a 100644 (file)
@@ -101,7 +101,6 @@ SYSCALL_DEFINE0(rt_sigreturn)
 {
        struct rt_sigframe __user *sf;
        unsigned int magic;
-       int err;
        struct pt_regs *regs = current_pt_regs();
 
        /* Always make any pending restarted system calls return -EINTR */
@@ -119,15 +118,16 @@ SYSCALL_DEFINE0(rt_sigreturn)
        if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
                goto badframe;
 
-       err = restore_usr_regs(regs, sf);
-       err |= __get_user(magic, &sf->sigret_magic);
-       if (err)
+       if (__get_user(magic, &sf->sigret_magic))
                goto badframe;
 
        if (unlikely(is_do_ss_needed(magic)))
                if (restore_altstack(&sf->uc.uc_stack))
                        goto badframe;
 
+       if (restore_usr_regs(regs, sf))
+               goto badframe;
+
        /* Don't restart from sigreturn */
        syscall_wont_restart(regs);
 
@@ -190,6 +190,15 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info,
        if (!sf)
                return 1;
 
+       /*
+        * w/o SA_SIGINFO, struct ucontext is partially populated (only
+        * uc_mcontext/uc_sigmask) for kernel's normal user state preservation
+        * during signal handler execution. This works for SA_SIGINFO as well
+        * although the semantics are now overloaded (the same reg state can be
+        * inspected by userland: but are they allowed to fiddle with it ?
+        */
+       err |= stash_usr_regs(sf, regs, set);
+
        /*
         * SA_SIGINFO requires 3 args to signal handler:
         *  #1: sig-no (common to any handler)
@@ -213,14 +222,6 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info,
                magic = MAGIC_SIGALTSTK;
        }
 
-       /*
-        * w/o SA_SIGINFO, struct ucontext is partially populated (only
-        * uc_mcontext/uc_sigmask) for kernel's normal user state preservation
-        * during signal handler execution. This works for SA_SIGINFO as well
-        * although the semantics are now overloaded (the same reg state can be
-        * inspected by userland: but are they allowed to fiddle with it ?
-        */
-       err |= stash_usr_regs(sf, regs, set);
        err |= __put_user(magic, &sf->sigret_magic);
        if (err)
                return err;
index 0e51e69..3fde7de 100644 (file)
@@ -227,12 +227,9 @@ void __attribute__((weak)) arc_local_timer_setup(unsigned int cpu)
 {
        struct clock_event_device *clk = &per_cpu(arc_clockevent_device, cpu);
 
-       clockevents_calc_mult_shift(clk, arc_get_core_freq(), 5);
-
-       clk->max_delta_ns = clockevent_delta2ns(ARC_TIMER_MAX, clk);
        clk->cpumask = cpumask_of(cpu);
-
-       clockevents_register_device(clk);
+       clockevents_config_and_register(clk, arc_get_core_freq(),
+                                       0, ARC_TIMER_MAX);
 
        /*
         * setup the per-cpu timer IRQ handler - for all cpus
index 28d1700..7ff5b5c 100644 (file)
@@ -245,6 +245,12 @@ int misaligned_fixup(unsigned long address, struct pt_regs *regs,
                regs->status32 &= ~STATUS_DE_MASK;
        } else {
                regs->ret += state.instr_len;
+
+               /* handle zero-overhead-loop */
+               if ((regs->ret == regs->lp_end) && (regs->lp_count)) {
+                       regs->ret = regs->lp_start;
+                       regs->lp_count--;
+               }
        }
 
        return 0;
index d63f3de..0c14d8a 100644 (file)
@@ -17,7 +17,7 @@
 #include <asm/pgalloc.h>
 #include <asm/mmu.h>
 
-static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long address)
+static int handle_vmalloc_fault(unsigned long address)
 {
        /*
         * Synchronize this task's top level page-table
@@ -27,7 +27,7 @@ static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long address)
        pud_t *pud, *pud_k;
        pmd_t *pmd, *pmd_k;
 
-       pgd = pgd_offset_fast(mm, address);
+       pgd = pgd_offset_fast(current->active_mm, address);
        pgd_k = pgd_offset_k(address);
 
        if (!pgd_present(*pgd_k))
@@ -72,7 +72,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address)
         * nothing more.
         */
        if (address >= VMALLOC_START && address <= VMALLOC_END) {
-               ret = handle_vmalloc_fault(mm, address);
+               ret = handle_vmalloc_fault(address);
                if (unlikely(ret))
                        goto bad_area_nosemaphore;
                else
index a37a50f..db50b62 100644 (file)
@@ -296,10 +296,15 @@ archprepare:
 # Convert bzImage to zImage
 bzImage: zImage
 
-zImage Image xipImage bootpImage uImage: vmlinux
+BOOT_TARGETS   = zImage Image xipImage bootpImage uImage
+INSTALL_TARGETS        = zinstall uinstall install
+
+PHONY += bzImage $(BOOT_TARGETS) $(INSTALL_TARGETS)
+
+$(BOOT_TARGETS): vmlinux
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
 
-zinstall uinstall install: vmlinux
+$(INSTALL_TARGETS):
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
 
 %.dtb: | scripts
index 84aa2ca..ec2f806 100644 (file)
@@ -95,24 +95,24 @@ initrd:
        @test "$(INITRD)" != "" || \
        (echo You must specify INITRD; exit -1)
 
-install: $(obj)/Image
-       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+install:
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \
        $(obj)/Image System.map "$(INSTALL_PATH)"
 
-zinstall: $(obj)/zImage
-       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+zinstall:
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \
        $(obj)/zImage System.map "$(INSTALL_PATH)"
 
-uinstall: $(obj)/uImage
-       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+uinstall:
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \
        $(obj)/uImage System.map "$(INSTALL_PATH)"
 
 zi:
-       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \
        $(obj)/zImage System.map "$(INSTALL_PATH)"
 
 i:
-       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \
        $(obj)/Image System.map "$(INSTALL_PATH)"
 
 subdir-            := bootp compressed dts
index e95af3f..802720e 100644 (file)
@@ -41,6 +41,8 @@ dtb-$(CONFIG_ARCH_AT91)       += sama5d33ek.dtb
 dtb-$(CONFIG_ARCH_AT91)        += sama5d34ek.dtb
 dtb-$(CONFIG_ARCH_AT91)        += sama5d35ek.dtb
 
+dtb-$(CONFIG_ARCH_ATLAS6) += atlas6-evb.dtb
+
 dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb
 dtb-$(CONFIG_ARCH_BCM) += bcm11351-brt.dtb \
        bcm28155-ap.dtb
index 05e4485..8ac2ac1 100644 (file)
        };
 
        soc {
+               ranges = <MBUS_ID(0xf0, 0x01) 0 0xd0000000 0x100000
+                         MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+
+               pcie-controller {
+                       status = "okay";
+
+                       /* Connected to Marvell SATA controller */
+                       pcie@1,0 {
+                               /* Port 0, Lane 0 */
+                               status = "okay";
+                       };
+
+                       /* Connected to FL1009 USB 3.0 controller */
+                       pcie@2,0 {
+                               /* Port 1, Lane 0 */
+                               status = "okay";
+                       };
+               };
+
                internal-regs {
                        serial@12000 {
                                clock-frequency = <200000000>;
                                        marvell,pins = "mpp56";
                                        marvell,function = "gpio";
                                };
+
+                               poweroff: poweroff {
+                                       marvell,pins = "mpp8";
+                                       marvell,function = "gpio";
+                               };
                        };
 
                        mdio {
                                        pwm_polarity = <0>;
                                };
                        };
-
-                       pcie-controller {
-                               status = "okay";
-
-                               /* Connected to Marvell SATA controller */
-                               pcie@1,0 {
-                                       /* Port 0, Lane 0 */
-                                       status = "okay";
-                               };
-
-                               /* Connected to FL1009 USB 3.0 controller */
-                               pcie@2,0 {
-                                       /* Port 1, Lane 0 */
-                                       status = "okay";
-                               };
-                       };
                };
        };
 
                button@1 {
                        label = "Power Button";
                        linux,code = <116>;     /* KEY_POWER */
-                       gpios = <&gpio1 30 1>;
+                       gpios = <&gpio1 30 0>;
                };
 
                button@2 {
                };
        };
 
+       gpio_poweroff {
+               compatible = "gpio-poweroff";
+               pinctrl-0 = <&poweroff>;
+               pinctrl-names = "default";
+               gpios = <&gpio0 8 1>;
+       };
+
 };
index def125c..3058522 100644 (file)
@@ -70,6 +70,8 @@
 
                        timer@20300 {
                                compatible = "marvell,armada-xp-timer";
+                               clocks = <&coreclk 2>, <&refclk>;
+                               clock-names = "nbclk", "fixed";
                        };
 
                        coreclk: mvebu-sar@18230 {
                        };
                };
        };
+
+       clocks {
+               /* 25 MHz reference crystal */
+               refclk: oscillator {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <25000000>;
+               };
+       };
 };
index cf78ac0..e74dc15 100644 (file)
                                                         AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE>;  /* PA8 periph A */
                                        };
 
-                                       pinctrl_uart2_rts: uart2_rts-0 {
+                                       pinctrl_usart2_rts: usart2_rts-0 {
                                                atmel,pins =
                                                        <AT91_PIOB 0 AT91_PERIPH_B AT91_PINCTRL_NONE>;  /* PB0 periph B */
                                        };
 
-                                       pinctrl_uart2_cts: uart2_cts-0 {
+                                       pinctrl_usart2_cts: usart2_cts-0 {
                                                atmel,pins =
                                                        <AT91_PIOB 1 AT91_PERIPH_B AT91_PINCTRL_NONE>;  /* PB1 periph B */
                                        };
                                interrupts = <12 IRQ_TYPE_LEVEL_HIGH 0>;
                                dmas = <&dma0 1 AT91_DMA_CFG_PER_ID(0)>;
                                dma-names = "rxtx";
+                               pinctrl-names = "default";
                                #address-cells = <1>;
                                #size-cells = <0>;
                                status = "disabled";
                                interrupts = <26 IRQ_TYPE_LEVEL_HIGH 0>;
                                dmas = <&dma1 1 AT91_DMA_CFG_PER_ID(0)>;
                                dma-names = "rxtx";
+                               pinctrl-names = "default";
                                #address-cells = <1>;
                                #size-cells = <0>;
                                status = "disabled";
index 8678e0c..6db4f81 100644 (file)
                                interrupts = <17>;
                                fifosize = <128>;
                                clocks = <&clks 13>;
+                               sirf,uart-dma-rx-channel = <21>;
+                               sirf,uart-dma-tx-channel = <2>;
                        };
 
                        uart1: uart@b0060000 {
                                interrupts = <19>;
                                fifosize = <128>;
                                clocks = <&clks 15>;
+                               sirf,uart-dma-rx-channel = <6>;
+                               sirf,uart-dma-tx-channel = <7>;
                        };
 
                        usp0: usp@b0080000 {
                                compatible = "sirf,prima2-usp";
                                reg = <0xb0080000 0x10000>;
                                interrupts = <20>;
+                               fifosize = <128>;
                                clocks = <&clks 28>;
+                               sirf,usp-dma-rx-channel = <17>;
+                               sirf,usp-dma-tx-channel = <18>;
                        };
 
                        usp1: usp@b0090000 {
                                compatible = "sirf,prima2-usp";
                                reg = <0xb0090000 0x10000>;
                                interrupts = <21>;
+                               fifosize = <128>;
                                clocks = <&clks 29>;
+                               sirf,usp-dma-rx-channel = <14>;
+                               sirf,usp-dma-tx-channel = <15>;
                        };
 
                        dmac0: dma-controller@b00b0000 {
                                compatible = "sirf,prima2-vip";
                                reg = <0xb00C0000 0x10000>;
                                clocks = <&clks 31>;
+                               interrupts = <14>;
+                               sirf,vip-dma-rx-channel = <16>;
                        };
 
                        spi0: spi@b00d0000 {
index 7d7cc77..bbac42a 100644 (file)
                             <1 14 0xf08>,
                             <1 11 0xf08>,
                             <1 10 0xf08>;
+               /* Unfortunately we need this since some versions of U-Boot
+                * on Exynos don't set the CNTFRQ register, so we need the
+                * value from DT.
+                */
+               clock-frequency = <24000000>;
        };
 
        mct@101C0000 {
index ff1aea0..72693a6 100644 (file)
@@ -9,11 +9,6 @@
        model = "ARM Integrator/CP";
        compatible = "arm,integrator-cp";
 
-       aliases {
-               arm,timer-primary = &timer2;
-               arm,timer-secondary = &timer1;
-       };
-
        chosen {
                bootargs = "root=/dev/ram0 console=ttyAMA0,38400n8 earlyprintk";
        };
        };
 
        timer0: timer@13000000 {
+               /* TIMER0 runs @ 25MHz */
                compatible = "arm,integrator-cp-timer";
+               status = "disabled";
        };
 
        timer1: timer@13000100 {
+               /* TIMER1 runs @ 1MHz */
                compatible = "arm,integrator-cp-timer";
        };
 
        timer2: timer@13000200 {
+               /* TIMER2 runs @ 1MHz */
                compatible = "arm,integrator-cp-timer";
        };
 
index cf7aeaf..1335b2e 100644 (file)
@@ -13,6 +13,7 @@
                cpu@0 {
                        device_type = "cpu";
                        compatible = "marvell,feroceon";
+                       reg = <0>;
                        clocks = <&core_clk 1>, <&core_clk 3>, <&gate_clk 11>;
                        clock-names = "cpu_clk", "ddrclk", "powersave";
                };
                xor@60900 {
                        compatible = "marvell,orion-xor";
                        reg = <0x60900 0x100
-                              0xd0B00 0x100>;
+                              0x60B00 0x100>;
                        status = "okay";
                        clocks = <&gate_clk 16>;
 
index 0c514dc..2816bf6 100644 (file)
@@ -11,7 +11,7 @@
 
 / {
        model = "TI OMAP3 BeagleBoard xM";
-       compatible = "ti,omap3-beagle-xm", "ti,omap3-beagle", "ti,omap3";
+       compatible = "ti,omap3-beagle-xm", "ti,omap36xx", "ti,omap3";
 
        cpus {
                cpu@0 {
index 7d95cda..b41bd57 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <0>;
                        pinctrl-single,register-width = <16>;
-                       pinctrl-single,function-mask = <0x7f1f>;
+                       pinctrl-single,function-mask = <0xff1f>;
                };
 
                omap3_pmx_wkup: pinmux@0x48002a00 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        pinctrl-single,register-width = <16>;
-                       pinctrl-single,function-mask = <0x7f1f>;
+                       pinctrl-single,function-mask = <0xff1f>;
                };
 
                gpio1: gpio@48310000 {
index bbeb623..27ed9f5 100644 (file)
                        compatible = "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ranges = <0xb0000000 0xb0000000 0x180000>;
+                       ranges = <0xb0000000 0xb0000000 0x180000>,
+                              <0x56000000 0x56000000 0x1b00000>;
 
                        timer@b0020000 {
                                compatible = "sirf,prima2-tick";
                        uart0: uart@b0050000 {
                                cell-index = <0>;
                                compatible = "sirf,prima2-uart";
-                               reg = <0xb0050000 0x10000>;
+                               reg = <0xb0050000 0x1000>;
                                interrupts = <17>;
+                               fifosize = <128>;
                                clocks = <&clks 13>;
+                               sirf,uart-dma-rx-channel = <21>;
+                               sirf,uart-dma-tx-channel = <2>;
                        };
 
                        uart1: uart@b0060000 {
                                cell-index = <1>;
                                compatible = "sirf,prima2-uart";
-                               reg = <0xb0060000 0x10000>;
+                               reg = <0xb0060000 0x1000>;
                                interrupts = <18>;
+                               fifosize = <32>;
                                clocks = <&clks 14>;
                        };
 
                        uart2: uart@b0070000 {
                                cell-index = <2>;
                                compatible = "sirf,prima2-uart";
-                               reg = <0xb0070000 0x10000>;
+                               reg = <0xb0070000 0x1000>;
                                interrupts = <19>;
+                               fifosize = <128>;
                                clocks = <&clks 15>;
+                               sirf,uart-dma-rx-channel = <6>;
+                               sirf,uart-dma-tx-channel = <7>;
                        };
 
                        usp0: usp@b0080000 {
                                compatible = "sirf,prima2-usp";
                                reg = <0xb0080000 0x10000>;
                                interrupts = <20>;
+                               fifosize = <128>;
                                clocks = <&clks 28>;
+                               sirf,usp-dma-rx-channel = <17>;
+                               sirf,usp-dma-tx-channel = <18>;
                        };
 
                        usp1: usp@b0090000 {
                                compatible = "sirf,prima2-usp";
                                reg = <0xb0090000 0x10000>;
                                interrupts = <21>;
+                               fifosize = <128>;
                                clocks = <&clks 29>;
+                               sirf,usp-dma-rx-channel = <14>;
+                               sirf,usp-dma-tx-channel = <15>;
                        };
 
                        usp2: usp@b00a0000 {
                                compatible = "sirf,prima2-usp";
                                reg = <0xb00a0000 0x10000>;
                                interrupts = <22>;
+                               fifosize = <128>;
                                clocks = <&clks 30>;
+                               sirf,usp-dma-rx-channel = <10>;
+                               sirf,usp-dma-tx-channel = <11>;
                        };
 
                        dmac0: dma-controller@b00b0000 {
                                compatible = "sirf,prima2-vip";
                                reg = <0xb00C0000 0x10000>;
                                clocks = <&clks 31>;
+                               interrupts = <14>;
+                               sirf,vip-dma-rx-channel = <16>;
                        };
 
                        spi0: spi@b00d0000 {
index 6c26caa..658fcc5 100644 (file)
        };
 
        sdhi0: sdhi@ee100000 {
-               compatible = "renesas,r8a73a4-sdhi";
+               compatible = "renesas,sdhi-r8a73a4";
                reg = <0 0xee100000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 165 4>;
        };
 
        sdhi1: sdhi@ee120000 {
-               compatible = "renesas,r8a73a4-sdhi";
+               compatible = "renesas,sdhi-r8a73a4";
                reg = <0 0xee120000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 166 4>;
        };
 
        sdhi2: sdhi@ee140000 {
-               compatible = "renesas,r8a73a4-sdhi";
+               compatible = "renesas,sdhi-r8a73a4";
                reg = <0 0xee140000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 167 4>;
index 45ac404..3577aba 100644 (file)
@@ -96,6 +96,5 @@
        pfc: pfc@fffc0000 {
                compatible = "renesas,pfc-r8a7778";
                reg = <0xfffc000 0x118>;
-               #gpio-range-cells = <3>;
        };
 };
index 23a6244..ebbe507 100644 (file)
        pfc: pfc@fffc0000 {
                compatible = "renesas,pfc-r8a7779";
                reg = <0xfffc0000 0x23c>;
-               #gpio-range-cells = <3>;
        };
 
        thermal@ffc48000 {
index 3b879e7..413b4c2 100644 (file)
        pfc: pfc@e6060000 {
                compatible = "renesas,pfc-r8a7790";
                reg = <0 0xe6060000 0 0x250>;
-               #gpio-range-cells = <3>;
        };
 
        sdhi0: sdhi@ee100000 {
-               compatible = "renesas,r8a7790-sdhi";
+               compatible = "renesas,sdhi-r8a7790";
                reg = <0 0xee100000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 165 4>;
        };
 
        sdhi1: sdhi@ee120000 {
-               compatible = "renesas,r8a7790-sdhi";
+               compatible = "renesas,sdhi-r8a7790";
                reg = <0 0xee120000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 166 4>;
        };
 
        sdhi2: sdhi@ee140000 {
-               compatible = "renesas,r8a7790-sdhi";
+               compatible = "renesas,sdhi-r8a7790";
                reg = <0 0xee140000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 167 4>;
        };
 
        sdhi3: sdhi@ee160000 {
-               compatible = "renesas,r8a7790-sdhi";
+               compatible = "renesas,sdhi-r8a7790";
                reg = <0 0xee160000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 168 4>;
index ba59a58..3955c76 100644 (file)
        };
 
        sdhi0: sdhi@ee100000 {
-               compatible = "renesas,r8a7740-sdhi";
+               compatible = "renesas,sdhi-r8a7740";
                reg = <0xee100000 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 83 4
 
        /* SDHI1 and SDHI2 have no CD pins, no need for CD IRQ */
        sdhi1: sdhi@ee120000 {
-               compatible = "renesas,r8a7740-sdhi";
+               compatible = "renesas,sdhi-r8a7740";
                reg = <0xee120000 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 88 4
        };
 
        sdhi2: sdhi@ee140000 {
-               compatible = "renesas,r8a7740-sdhi";
+               compatible = "renesas,sdhi-r8a7740";
                reg = <0xee140000 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 104 4
index 06ea7d4..2a45092 100644 (file)
 #   $4 - default install path (blank if root directory)
 #
 
+verify () {
+       if [ ! -f "$1" ]; then
+               echo ""                                                   1>&2
+               echo " *** Missing file: $1"                              1>&2
+               echo ' *** You need to run "make" before "make install".' 1>&2
+               echo ""                                                   1>&2
+               exit 1
+       fi
+}
+
+# Make sure the files actually exist
+verify "$2"
+verify "$3"
+
 # User may have a custom install script
 if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi
 if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi
index 117f955..8e1a024 100644 (file)
@@ -269,6 +269,11 @@ static const struct edmacc_param dummy_paramset = {
        .ccnt = 1,
 };
 
+static const struct of_device_id edma_of_ids[] = {
+       { .compatible = "ti,edma3", },
+       {}
+};
+
 /*****************************************************************************/
 
 static void map_dmach_queue(unsigned ctlr, unsigned ch_no,
@@ -560,14 +565,38 @@ static int reserve_contiguous_slots(int ctlr, unsigned int id,
 static int prepare_unused_channel_list(struct device *dev, void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       int i, ctlr;
+       int i, count, ctlr;
+       struct of_phandle_args  dma_spec;
 
+       if (dev->of_node) {
+               count = of_property_count_strings(dev->of_node, "dma-names");
+               if (count < 0)
+                       return 0;
+               for (i = 0; i < count; i++) {
+                       if (of_parse_phandle_with_args(dev->of_node, "dmas",
+                                                      "#dma-cells", i,
+                                                      &dma_spec))
+                               continue;
+
+                       if (!of_match_node(edma_of_ids, dma_spec.np)) {
+                               of_node_put(dma_spec.np);
+                               continue;
+                       }
+
+                       clear_bit(EDMA_CHAN_SLOT(dma_spec.args[0]),
+                                 edma_cc[0]->edma_unused);
+                       of_node_put(dma_spec.np);
+               }
+               return 0;
+       }
+
+       /* For non-OF case */
        for (i = 0; i < pdev->num_resources; i++) {
                if ((pdev->resource[i].flags & IORESOURCE_DMA) &&
                                (int)pdev->resource[i].start >= 0) {
                        ctlr = EDMA_CTLR(pdev->resource[i].start);
                        clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start),
-                                       edma_cc[ctlr]->edma_unused);
+                                 edma_cc[ctlr]->edma_unused);
                }
        }
 
@@ -1762,11 +1791,6 @@ static int edma_probe(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id edma_of_ids[] = {
-       { .compatible = "ti,edma3", },
-       {}
-};
-
 static struct platform_driver edma_driver = {
        .driver = {
                .name   = "edma",
index 370236d..9902509 100644 (file)
@@ -51,7 +51,8 @@ void mcpm_cpu_power_down(void)
 {
        phys_reset_t phys_reset;
 
-       BUG_ON(!platform_ops);
+       if (WARN_ON_ONCE(!platform_ops || !platform_ops->power_down))
+               return;
        BUG_ON(!irqs_disabled());
 
        /*
@@ -93,7 +94,8 @@ void mcpm_cpu_suspend(u64 expected_residency)
 {
        phys_reset_t phys_reset;
 
-       BUG_ON(!platform_ops);
+       if (WARN_ON_ONCE(!platform_ops || !platform_ops->suspend))
+               return;
        BUG_ON(!irqs_disabled());
 
        /* Very similar to mcpm_cpu_power_down() */
index d56c932..025f6ce 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <asm/mach/sharpsl_param.h>
+#include <asm/memory.h>
 
 /*
  * Certain hardware parameters determined at the time of device manufacture,
  */
 #ifdef CONFIG_ARCH_SA1100
 #define PARAM_BASE     0xe8ffc000
+#define param_start(x) (void *)(x)
 #else
 #define PARAM_BASE     0xa0000a00
+#define param_start(x) __va(x)
 #endif
 #define MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 )  | ( b << 8 ) | a )
 
@@ -41,7 +44,7 @@ EXPORT_SYMBOL(sharpsl_param);
 
 void sharpsl_save_param(void)
 {
-       memcpy(&sharpsl_param, (void *)PARAM_BASE, sizeof(struct sharpsl_param_info));
+       memcpy(&sharpsl_param, param_start(PARAM_BASE), sizeof(struct sharpsl_param_info));
 
        if (sharpsl_param.comadj_keyword != COMADJ_MAGIC)
                sharpsl_param.comadj=-1;
index f3935b4..119fc37 100644 (file)
@@ -135,6 +135,7 @@ CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_ESDHC_IMX=y
 CONFIG_MMC_SDHCI_TEGRA=y
 CONFIG_MMC_SDHCI_SPEAR=y
 CONFIG_MMC_OMAP=y
index d3db398..59ceae8 100644 (file)
@@ -31,5 +31,4 @@ generic-y += termbits.h
 generic-y += termios.h
 generic-y += timex.h
 generic-y += trace_clock.h
-generic-y += types.h
 generic-y += unaligned.h
index bfc198c..863c892 100644 (file)
@@ -16,7 +16,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm goto("1:\n\t"
+       asm_volatile_goto("1:\n\t"
                 JUMP_LABEL_NOP "\n\t"
                 ".pushsection __jump_table,  \"aw\"\n\t"
                 ".word 1b, %l[l_yes], %c0\n\t"
index 0f7b762..fc82a88 100644 (file)
@@ -76,8 +76,11 @@ int mcpm_cpu_power_up(unsigned int cpu, unsigned int cluster);
  *
  * This must be called with interrupts disabled.
  *
- * This does not return.  Re-entry in the kernel is expected via
- * mcpm_entry_point.
+ * On success this does not return.  Re-entry in the kernel is expected
+ * via mcpm_entry_point.
+ *
+ * This will return if mcpm_platform_register() has not been called
+ * previously in which case the caller should take appropriate action.
  */
 void mcpm_cpu_power_down(void);
 
@@ -98,8 +101,11 @@ void mcpm_cpu_power_down(void);
  *
  * This must be called with interrupts disabled.
  *
- * This does not return.  Re-entry in the kernel is expected via
- * mcpm_entry_point.
+ * On success this does not return.  Re-entry in the kernel is expected
+ * via mcpm_entry_point.
+ *
+ * This will return if mcpm_platform_register() has not been called
+ * previously in which case the caller should take appropriate action.
  */
 void mcpm_cpu_suspend(u64 expected_residency);
 
index f1d96d4..73ddd72 100644 (file)
@@ -57,6 +57,9 @@ static inline void syscall_get_arguments(struct task_struct *task,
                                         unsigned int i, unsigned int n,
                                         unsigned long *args)
 {
+       if (n == 0)
+               return;
+
        if (i + n > SYSCALL_MAX_ARGS) {
                unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
                unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
@@ -81,6 +84,9 @@ static inline void syscall_set_arguments(struct task_struct *task,
                                         unsigned int i, unsigned int n,
                                         const unsigned long *args)
 {
+       if (n == 0)
+               return;
+
        if (i + n > SYSCALL_MAX_ARGS) {
                pr_warning("%s called with max args %d, handling only %d\n",
                           __func__, i + n, SYSCALL_MAX_ARGS);
index 2c7cc1e..476de57 100644 (file)
@@ -487,7 +487,26 @@ __fixup_smp:
        mrc     p15, 0, r0, c0, c0, 5   @ read MPIDR
        and     r0, r0, #0xc0000000     @ multiprocessing extensions and
        teq     r0, #0x80000000         @ not part of a uniprocessor system?
-       moveq   pc, lr                  @ yes, assume SMP
+       bne    __fixup_smp_on_up        @ no, assume UP
+
+       @ Core indicates it is SMP. Check for Aegis SOC where a single
+       @ Cortex-A9 CPU is present but SMP operations fault.
+       mov     r4, #0x41000000
+       orr     r4, r4, #0x0000c000
+       orr     r4, r4, #0x00000090
+       teq     r3, r4                  @ Check for ARM Cortex-A9
+       movne   pc, lr                  @ Not ARM Cortex-A9,
+
+       @ If a future SoC *does* use 0x0 as the PERIPH_BASE, then the
+       @ below address check will need to be #ifdef'd or equivalent
+       @ for the Aegis platform.
+       mrc     p15, 4, r0, c15, c0     @ get SCU base address
+       teq     r0, #0x0                @ '0' on actual UP A9 hardware
+       beq     __fixup_smp_on_up       @ So its an A9 UP
+       ldr     r0, [r0, #4]            @ read SCU Config
+       and     r0, r0, #0x3            @ number of CPUs
+       teq     r0, #0x0                @ is 1?
+       movne   pc, lr
 
 __fixup_smp_on_up:
        adr     r0, 1f
index 71e08ba..c02ba4a 100644 (file)
@@ -58,14 +58,14 @@ static const struct kvm_irq_level a15_vtimer_irq = {
  */
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 {
-       struct kvm_regs *cpu_reset;
+       struct kvm_regs *reset_regs;
        const struct kvm_irq_level *cpu_vtimer_irq;
 
        switch (vcpu->arch.target) {
        case KVM_ARM_TARGET_CORTEX_A15:
                if (vcpu->vcpu_id > a15_max_cpu_idx)
                        return -EINVAL;
-               cpu_reset = &a15_regs_reset;
+               reset_regs = &a15_regs_reset;
                vcpu->arch.midr = read_cpuid_id();
                cpu_vtimer_irq = &a15_vtimer_irq;
                break;
@@ -74,7 +74,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
        }
 
        /* Reset core registers */
-       memcpy(&vcpu->arch.regs, cpu_reset, sizeof(vcpu->arch.regs));
+       memcpy(&vcpu->arch.regs, reset_regs, sizeof(vcpu->arch.regs));
 
        /* Reset CP15 registers */
        kvm_reset_coprocs(vcpu);
index 180b302..f607deb 100644 (file)
@@ -93,7 +93,7 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction at91rm9200_timer_irq = {
        .name           = "at91_tick",
-       .flags          = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .flags          = IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
        .handler        = at91rm9200_timer_interrupt,
        .irq            = NR_IRQS_LEGACY + AT91_ID_SYS,
 };
index 3a4bc2e..bb39232 100644 (file)
@@ -171,7 +171,7 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
 
 static struct irqaction at91sam926x_pit_irq = {
        .name           = "at91_tick",
-       .flags          = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .flags          = IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
        .handler        = at91sam926x_pit_interrupt,
        .irq            = NR_IRQS_LEGACY + AT91_ID_SYS,
 };
index 721a1a3..c40c1e2 100644 (file)
 #include "at91_rstc.h"
                        .arm
 
+/*
+ * at91_ramc_base is an array void*
+ * init at NULL if only one DDR controler is present in or DT
+ */
                        .globl  at91sam9g45_restart
 
 at91sam9g45_restart:
                        ldr     r5, =at91_ramc_base             @ preload constants
                        ldr     r0, [r5]
+                       ldr     r5, [r5, #4]                    @ ddr1
+                       cmp     r5, #0
                        ldr     r4, =at91_rstc_base
                        ldr     r1, [r4]
 
@@ -30,6 +36,8 @@ at91sam9g45_restart:
 
                        .balign 32                              @ align to cache line
 
+                       strne   r2, [r5, #AT91_DDRSDRC_RTR]     @ disable DDR1 access
+                       strne   r3, [r5, #AT91_DDRSDRC_LPR]     @ power down DDR1
                        str     r2, [r0, #AT91_DDRSDRC_RTR]     @ disable DDR0 access
                        str     r3, [r0, #AT91_DDRSDRC_LPR]     @ power down DDR0
                        str     r4, [r1, #AT91_RSTC_CR]         @ reset processor
index 2919eba..c0e637a 100644 (file)
@@ -57,7 +57,7 @@ static irqreturn_t at91x40_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction at91x40_timer_irq = {
        .name           = "at91_tick",
-       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .flags          = IRQF_TIMER,
        .handler        = at91x40_timer_interrupt
 };
 
index 92b7f77..4078ba9 100644 (file)
@@ -176,7 +176,7 @@ static struct at24_platform_data eeprom_info = {
        .context        = (void *)0x7f00,
 };
 
-static struct snd_platform_data dm365_evm_snd_data = {
+static struct snd_platform_data dm365_evm_snd_data __maybe_unused = {
        .asp_chan_q = EVENTQ_3,
 };
 
index 52b8571..ce402cd 100644 (file)
@@ -15,8 +15,6 @@
 
 #include <mach/hardware.h>
 
-#include <linux/platform_device.h>
-
 #define DAVINCI_UART0_BASE     (IO_PHYS + 0x20000)
 #define DAVINCI_UART1_BASE     (IO_PHYS + 0x20400)
 #define DAVINCI_UART2_BASE     (IO_PHYS + 0x20800)
@@ -39,6 +37,8 @@
 #define UART_DM646X_SCR_TX_WATERMARK   0x08
 
 #ifndef __ASSEMBLY__
+#include <linux/platform_device.h>
+
 extern int davinci_serial_init(struct platform_device *);
 #endif
 
index 755fd29..06a9e2e 100644 (file)
@@ -1,2 +1,9 @@
 /* Simple oneliner include to the PCIv3 early init */
+#ifdef CONFIG_PCI
 extern int pci_v3_early_init(void);
+#else
+static inline int pci_v3_early_init(void)
+{
+       return 0;
+}
+#endif
index 4c24303..58adf2f 100644 (file)
@@ -140,6 +140,7 @@ int __init coherency_init(void)
                coherency_base = of_iomap(np, 0);
                coherency_cpu_base = of_iomap(np, 1);
                set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
+               of_node_put(np);
        }
 
        return 0;
@@ -147,9 +148,14 @@ int __init coherency_init(void)
 
 static int __init coherency_late_init(void)
 {
-       if (of_find_matching_node(NULL, of_coherency_table))
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, of_coherency_table);
+       if (np) {
                bus_register_notifier(&platform_bus_type,
                                      &mvebu_hwcc_platform_nb);
+               of_node_put(np);
+       }
        return 0;
 }
 
index 3cc4bef..27fc4f0 100644 (file)
@@ -67,6 +67,7 @@ int __init armada_370_xp_pmsu_init(void)
                pr_info("Initializing Power Management Service Unit\n");
                pmsu_mp_base = of_iomap(np, 0);
                pmsu_reset_base = of_iomap(np, 1);
+               of_node_put(np);
        }
 
        return 0;
index f875124..5175083 100644 (file)
@@ -98,6 +98,7 @@ static int __init mvebu_system_controller_init(void)
                BUG_ON(!match);
                system_controller_base = of_iomap(np, 0);
                mvebu_sc = (struct mvebu_system_controller *)match->data;
+               of_node_put(np);
        }
 
        return 0;
index 39c7838..87162e1 100644 (file)
@@ -129,6 +129,24 @@ DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
        .restart        = omap3xxx_restart,
 MACHINE_END
 
+static const char *omap36xx_boards_compat[] __initdata = {
+       "ti,omap36xx",
+       NULL,
+};
+
+DT_MACHINE_START(OMAP36XX_DT, "Generic OMAP36xx (Flattened Device Tree)")
+       .reserve        = omap_reserve,
+       .map_io         = omap3_map_io,
+       .init_early     = omap3630_init_early,
+       .init_irq       = omap_intc_of_init,
+       .handle_irq     = omap3_intc_handle_irq,
+       .init_machine   = omap_generic_init,
+       .init_late      = omap3_init_late,
+       .init_time      = omap3_sync32k_timer_init,
+       .dt_compat      = omap36xx_boards_compat,
+       .restart        = omap3xxx_restart,
+MACHINE_END
+
 static const char *omap3_gp_boards_compat[] __initdata = {
        "ti,omap3-beagle",
        "timll,omap3-devkit8000",
index c3270c0..f6fe388 100644 (file)
@@ -167,38 +167,47 @@ static struct lp55xx_led_config rx51_lp5523_led_config[] = {
                .name           = "lp5523:kb1",
                .chan_nr        = 0,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:kb2",
                .chan_nr        = 1,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:kb3",
                .chan_nr        = 2,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:kb4",
                .chan_nr        = 3,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:b",
                .chan_nr        = 4,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:g",
                .chan_nr        = 5,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:r",
                .chan_nr        = 6,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:kb5",
                .chan_nr        = 7,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:kb6",
                .chan_nr        = 8,
                .led_current    = 50,
+               .max_current    = 100,
        }
 };
 
index 64b5a83..8b6876c 100644 (file)
@@ -272,9 +272,19 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
        struct gpmc_timings t;
        int ret;
 
-       if (gpmc_onenand_data->of_node)
+       if (gpmc_onenand_data->of_node) {
                gpmc_read_settings_dt(gpmc_onenand_data->of_node,
                                      &onenand_async);
+               if (onenand_async.sync_read || onenand_async.sync_write) {
+                       if (onenand_async.sync_write)
+                               gpmc_onenand_data->flags |=
+                                       ONENAND_SYNC_READWRITE;
+                       else
+                               gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
+                       onenand_async.sync_read = false;
+                       onenand_async.sync_write = false;
+               }
+       }
 
        omap2_onenand_set_async_mode(onenand_base);
 
index 5d2080e..16f78a9 100644 (file)
@@ -28,7 +28,7 @@
 #define OMAP_PULL_UP                   (1 << 4)
 #define OMAP_ALTELECTRICALSEL          (1 << 5)
 
-/* 34xx specific mux bit defines */
+/* omap3/4/5 specific mux bit defines */
 #define OMAP_INPUT_EN                  (1 << 8)
 #define OMAP_OFF_EN                    (1 << 9)
 #define OMAP_OFFOUT_EN                 (1 << 10)
@@ -36,8 +36,6 @@
 #define OMAP_OFF_PULL_EN               (1 << 12)
 #define OMAP_OFF_PULL_UP               (1 << 13)
 #define OMAP_WAKEUP_EN                 (1 << 14)
-
-/* 44xx specific mux bit defines */
 #define OMAP_WAKEUP_EVENT              (1 << 15)
 
 /* Active pin states */
index fa74a06..ead48fa 100644 (file)
@@ -628,7 +628,7 @@ void __init omap4_local_timer_init(void)
 #endif /* CONFIG_HAVE_ARM_TWD */
 #endif /* CONFIG_ARCH_OMAP4 */
 
-#ifdef CONFIG_SOC_OMAP5
+#if defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX)
 void __init omap5_realtime_timer_init(void)
 {
        omap4_sync32k_timer_init();
@@ -636,7 +636,7 @@ void __init omap5_realtime_timer_init(void)
 
        clocksource_of_init();
 }
-#endif /* CONFIG_SOC_OMAP5 */
+#endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */
 
 /**
  * omap_timer_init - build and register timer device with an
index 5bd1479..7f8f607 100644 (file)
@@ -1108,9 +1108,9 @@ static const struct pinctrl_map eva_pinctrl_map[] = {
        PIN_MAP_MUX_GROUP_DEFAULT("asoc-simple-card.1", "pfc-r8a7740",
                                  "fsib_mclk_in", "fsib"),
        /* GETHER */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-eth", "pfc-r8a7740",
+       PIN_MAP_MUX_GROUP_DEFAULT("r8a7740-gether", "pfc-r8a7740",
                                  "gether_mii", "gether"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-eth", "pfc-r8a7740",
+       PIN_MAP_MUX_GROUP_DEFAULT("r8a7740-gether", "pfc-r8a7740",
                                  "gether_int", "gether"),
        /* HDMI */
        PIN_MAP_MUX_GROUP_DEFAULT("sh-mobile-hdmi", "pfc-r8a7740",
index ffb6f0a..5930af8 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/gpio-rcar.h>
 #include <linux/platform_device.h>
+#include <linux/phy.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/sh_eth.h>
@@ -155,6 +156,30 @@ static void __init lager_add_standard_devices(void)
                                          &ether_pdata, sizeof(ether_pdata));
 }
 
+/*
+ * Ether LEDs on the Lager board are named LINK and ACTIVE which corresponds
+ * to non-default 01 setting of the Micrel KSZ8041 PHY control register 1 bits
+ * 14-15. We have to set them back to 01 from the default 00 value each time
+ * the PHY is reset. It's also important because the PHY's LED0 signal is
+ * connected to SoC's ETH_LINK signal and in the PHY's default mode it will
+ * bounce on and off after each packet, which we apparently want to avoid.
+ */
+static int lager_ksz8041_fixup(struct phy_device *phydev)
+{
+       u16 phyctrl1 = phy_read(phydev, 0x1e);
+
+       phyctrl1 &= ~0xc000;
+       phyctrl1 |= 0x4000;
+       return phy_write(phydev, 0x1e, phyctrl1);
+}
+
+static void __init lager_init(void)
+{
+       lager_add_standard_devices();
+
+       phy_register_fixup_for_id("r8a7790-ether-ff:01", lager_ksz8041_fixup);
+}
+
 static const char *lager_boards_compat_dt[] __initdata = {
        "renesas,lager",
        NULL,
@@ -163,6 +188,6 @@ static const char *lager_boards_compat_dt[] __initdata = {
 DT_MACHINE_START(LAGER_DT, "lager")
        .init_early     = r8a7790_init_delay,
        .init_time      = r8a7790_timer_init,
-       .init_machine   = lager_add_standard_devices,
+       .init_machine   = lager_init,
        .dt_compat      = lager_boards_compat_dt,
 MACHINE_END
index 7aeb5d6..e6eb481 100644 (file)
@@ -131,6 +131,16 @@ static void tc2_pm_down(u64 residency)
        } else
                BUG();
 
+       /*
+        * If the CPU is committed to power down, make sure
+        * the power controller will be in charge of waking it
+        * up upon IRQ, ie IRQ lines are cut from GIC CPU IF
+        * to the CPU by disabling the GIC CPU IF to prevent wfi
+        * from completing execution behind power controller back
+        */
+       if (!skip_wfi)
+               gic_cpu_if_down();
+
        if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
                arch_spin_unlock(&tc2_pm_lock);
 
@@ -231,7 +241,6 @@ static void tc2_pm_suspend(u64 residency)
        cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
        cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
        ve_spc_set_resume_addr(cluster, cpu, virt_to_phys(mcpm_entry_point));
-       gic_cpu_if_down();
        tc2_pm_down(residency);
 }
 
index f5e1a84..1272ed2 100644 (file)
@@ -1232,7 +1232,8 @@ __iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
                                break;
 
                len = (j - i) << PAGE_SHIFT;
-               ret = iommu_map(mapping->domain, iova, phys, len, 0);
+               ret = iommu_map(mapping->domain, iova, phys, len,
+                               IOMMU_READ|IOMMU_WRITE);
                if (ret < 0)
                        goto fail;
                iova += len;
@@ -1431,6 +1432,27 @@ static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
                                         GFP_KERNEL);
 }
 
+static int __dma_direction_to_prot(enum dma_data_direction dir)
+{
+       int prot;
+
+       switch (dir) {
+       case DMA_BIDIRECTIONAL:
+               prot = IOMMU_READ | IOMMU_WRITE;
+               break;
+       case DMA_TO_DEVICE:
+               prot = IOMMU_READ;
+               break;
+       case DMA_FROM_DEVICE:
+               prot = IOMMU_WRITE;
+               break;
+       default:
+               prot = 0;
+       }
+
+       return prot;
+}
+
 /*
  * Map a part of the scatter-gather list into contiguous io address space
  */
@@ -1444,6 +1466,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
        int ret = 0;
        unsigned int count;
        struct scatterlist *s;
+       int prot;
 
        size = PAGE_ALIGN(size);
        *handle = DMA_ERROR_CODE;
@@ -1460,7 +1483,9 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
                        !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
                        __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
 
-               ret = iommu_map(mapping->domain, iova, phys, len, 0);
+               prot = __dma_direction_to_prot(dir);
+
+               ret = iommu_map(mapping->domain, iova, phys, len, prot);
                if (ret < 0)
                        goto fail;
                count += len >> PAGE_SHIFT;
@@ -1665,19 +1690,7 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
        if (dma_addr == DMA_ERROR_CODE)
                return dma_addr;
 
-       switch (dir) {
-       case DMA_BIDIRECTIONAL:
-               prot = IOMMU_READ | IOMMU_WRITE;
-               break;
-       case DMA_TO_DEVICE:
-               prot = IOMMU_READ;
-               break;
-       case DMA_FROM_DEVICE:
-               prot = IOMMU_WRITE;
-               break;
-       default:
-               prot = 0;
-       }
+       prot = __dma_direction_to_prot(dir);
 
        ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot);
        if (ret < 0)
index febaee7..18ec4c5 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/nodemask.h>
 #include <linux/initrd.h>
 #include <linux/of_fdt.h>
-#include <linux/of_reserved_mem.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
 #include <linux/memblock.h>
@@ -379,8 +378,6 @@ void __init arm_memblock_init(struct meminfo *mi,
        if (mdesc->reserve)
                mdesc->reserve();
 
-       early_init_dt_scan_reserved_mem();
-
        /*
         * reserve memory for DMA contigouos allocations,
         * must come from DMA area inside low memory
index f50d223..99b44e0 100644 (file)
@@ -930,4 +930,5 @@ void bpf_jit_free(struct sk_filter *fp)
 {
        if (fp->bpf_func != sk_run_filter)
                module_free(NULL, fp->bpf_func);
+       kfree(fp);
 }
index 1a6bfe9..835c559 100644 (file)
@@ -6,13 +6,6 @@ config FRAME_POINTER
        bool
        default y
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T output.
-
 config EARLY_PRINTK
        bool "Early printk support"
        default y
index 5b3e832..31c81e9 100644 (file)
@@ -42,7 +42,7 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
-# CONFIG_BLK_DEV is not set
+CONFIG_BLK_DEV=y
 CONFIG_SCSI=y
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
@@ -72,6 +72,7 @@ CONFIG_LOGO=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 # CONFIG_EXT3_FS_XATTR is not set
 CONFIG_FUSE_FS=y
@@ -90,3 +91,5 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_FTRACE is not set
 CONFIG_ATOMIC64_SELFTEST=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_BLK=y
index edb3d5c..7ecc2b2 100644 (file)
@@ -166,9 +166,10 @@ do {                                                                       \
 
 #define get_user(x, ptr)                                               \
 ({                                                                     \
+       __typeof__(*(ptr)) __user *__p = (ptr);                         \
        might_fault();                                                  \
-       access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) ?                 \
-               __get_user((x), (ptr)) :                                \
+       access_ok(VERIFY_READ, __p, sizeof(*__p)) ?                     \
+               __get_user((x), __p) :                                  \
                ((x) = 0, -EFAULT);                                     \
 })
 
@@ -227,9 +228,10 @@ do {                                                                       \
 
 #define put_user(x, ptr)                                               \
 ({                                                                     \
+       __typeof__(*(ptr)) __user *__p = (ptr);                         \
        might_fault();                                                  \
-       access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) ?                \
-               __put_user((x), (ptr)) :                                \
+       access_ok(VERIFY_WRITE, __p, sizeof(*__p)) ?                    \
+               __put_user((x), __p) :                                  \
                -EFAULT;                                                \
 })
 
index 1f2e4d5..bb785d2 100644 (file)
@@ -80,8 +80,10 @@ void fpsimd_thread_switch(struct task_struct *next)
 
 void fpsimd_flush_thread(void)
 {
+       preempt_disable();
        memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
        fpsimd_load_state(&current->thread.fpsimd_state);
+       preempt_enable();
 }
 
 #ifdef CONFIG_KERNEL_MODE_NEON
index 8ae80a1..19da91e 100644 (file)
@@ -35,7 +35,7 @@
  */
 ENTRY(__cpu_flush_user_tlb_range)
        vma_vm_mm x3, x2                        // get vma->vm_mm
-       mmid    x3, x3                          // get vm_mm->context.id
+       mmid    w3, x3                          // get vm_mm->context.id
        dsb     sy
        lsr     x0, x0, #12                     // align address
        lsr     x1, x1, #12
index d22af85..fd79807 100644 (file)
@@ -1,5 +1,19 @@
 
 generic-y      += clkdev.h
+generic-y       += cputime.h
+generic-y       += delay.h
+generic-y       += device.h
+generic-y       += div64.h
+generic-y       += emergency-restart.h
 generic-y      += exec.h
-generic-y      += trace_clock.h
+generic-y       += futex.h
+generic-y       += irq_regs.h
 generic-y      += param.h
+generic-y       += local.h
+generic-y       += local64.h
+generic-y       += percpu.h
+generic-y       += scatterlist.h
+generic-y       += sections.h
+generic-y       += topology.h
+generic-y      += trace_clock.h
+generic-y       += xor.h
diff --git a/arch/avr32/include/asm/cputime.h b/arch/avr32/include/asm/cputime.h
deleted file mode 100644 (file)
index e87e0f8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_CPUTIME_H
-#define __ASM_AVR32_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __ASM_AVR32_CPUTIME_H */
diff --git a/arch/avr32/include/asm/delay.h b/arch/avr32/include/asm/delay.h
deleted file mode 100644 (file)
index 9670e12..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/delay.h>
diff --git a/arch/avr32/include/asm/device.h b/arch/avr32/include/asm/device.h
deleted file mode 100644 (file)
index d8f9872..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Arch specific extensions to struct device
- *
- * This file is released under the GPLv2
- */
-#include <asm-generic/device.h>
-
diff --git a/arch/avr32/include/asm/div64.h b/arch/avr32/include/asm/div64.h
deleted file mode 100644 (file)
index d7ddd4f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_DIV64_H
-#define __ASM_AVR32_DIV64_H
-
-#include <asm-generic/div64.h>
-
-#endif /* __ASM_AVR32_DIV64_H */
diff --git a/arch/avr32/include/asm/emergency-restart.h b/arch/avr32/include/asm/emergency-restart.h
deleted file mode 100644 (file)
index 3e7e014..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_EMERGENCY_RESTART_H
-#define __ASM_AVR32_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* __ASM_AVR32_EMERGENCY_RESTART_H */
diff --git a/arch/avr32/include/asm/futex.h b/arch/avr32/include/asm/futex.h
deleted file mode 100644 (file)
index 10419f1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_FUTEX_H
-#define __ASM_AVR32_FUTEX_H
-
-#include <asm-generic/futex.h>
-
-#endif /* __ASM_AVR32_FUTEX_H */
diff --git a/arch/avr32/include/asm/irq_regs.h b/arch/avr32/include/asm/irq_regs.h
deleted file mode 100644 (file)
index 3dd9c0b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/irq_regs.h>
diff --git a/arch/avr32/include/asm/local.h b/arch/avr32/include/asm/local.h
deleted file mode 100644 (file)
index 1c16196..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_LOCAL_H
-#define __ASM_AVR32_LOCAL_H
-
-#include <asm-generic/local.h>
-
-#endif /* __ASM_AVR32_LOCAL_H */
diff --git a/arch/avr32/include/asm/local64.h b/arch/avr32/include/asm/local64.h
deleted file mode 100644 (file)
index 36c93b5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local64.h>
diff --git a/arch/avr32/include/asm/percpu.h b/arch/avr32/include/asm/percpu.h
deleted file mode 100644 (file)
index 69227b4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_PERCPU_H
-#define __ASM_AVR32_PERCPU_H
-
-#include <asm-generic/percpu.h>
-
-#endif /* __ASM_AVR32_PERCPU_H */
diff --git a/arch/avr32/include/asm/scatterlist.h b/arch/avr32/include/asm/scatterlist.h
deleted file mode 100644 (file)
index a5902d9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_SCATTERLIST_H
-#define __ASM_AVR32_SCATTERLIST_H
-
-#include <asm-generic/scatterlist.h>
-
-#endif /* __ASM_AVR32_SCATTERLIST_H */
diff --git a/arch/avr32/include/asm/sections.h b/arch/avr32/include/asm/sections.h
deleted file mode 100644 (file)
index aa14252..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_SECTIONS_H
-#define __ASM_AVR32_SECTIONS_H
-
-#include <asm-generic/sections.h>
-
-#endif /* __ASM_AVR32_SECTIONS_H */
diff --git a/arch/avr32/include/asm/topology.h b/arch/avr32/include/asm/topology.h
deleted file mode 100644 (file)
index 5b766cb..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_TOPOLOGY_H
-#define __ASM_AVR32_TOPOLOGY_H
-
-#include <asm-generic/topology.h>
-
-#endif /* __ASM_AVR32_TOPOLOGY_H */
diff --git a/arch/avr32/include/asm/xor.h b/arch/avr32/include/asm/xor.h
deleted file mode 100644 (file)
index 99c87aa..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_XOR_H
-#define _ASM_XOR_H
-
-#include <asm-generic/xor.h>
-
-#endif
index c273100..42a53e7 100644 (file)
@@ -289,7 +289,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                memset(childregs, 0, sizeof(struct pt_regs));
                p->thread.cpu_context.r0 = arg;
                p->thread.cpu_context.r1 = usp; /* fn */
-               p->thread.cpu_context.r2 = syscall_return;
+               p->thread.cpu_context.r2 = (unsigned long)syscall_return;
                p->thread.cpu_context.pc = (unsigned long)ret_from_kernel_thread;
                childregs->sr = MODE_SUPERVISOR;
        } else {
index 869a1c6..12f828a 100644 (file)
@@ -98,7 +98,14 @@ static void comparator_mode(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_SHUTDOWN:
                sysreg_write(COMPARE, 0);
                pr_debug("%s: stop\n", evdev->name);
-               cpu_idle_poll_ctrl(false);
+               if (evdev->mode == CLOCK_EVT_MODE_ONESHOT ||
+                   evdev->mode == CLOCK_EVT_MODE_RESUME) {
+                       /*
+                        * Only disable idle poll if we have forced that
+                        * in a previous call.
+                        */
+                       cpu_idle_poll_ctrl(false);
+               }
                break;
        default:
                BUG();
index 4a9baa9..9969dba 100644 (file)
@@ -276,7 +276,7 @@ static struct platform_device mtx1_pci_host = {
        .resource       = alchemy_pci_host_res,
 };
 
-static struct __initdata platform_device * mtx1_devs[] = {
+static struct platform_device *mtx1_devs[] __initdata = {
        &mtx1_pci_host,
        &mtx1_gpio_leds,
        &mtx1_wdt,
index 4d6d77e..e194f95 100644 (file)
@@ -22,7 +22,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm goto("1:\tnop\n\t"
+       asm_volatile_goto("1:\tnop\n\t"
                "nop\n\t"
                ".pushsection __jump_table,  \"aw\"\n\t"
                WORD_INSN " 1b, %l[l_yes], %0\n\t"
index 4204d76..029e002 100644 (file)
@@ -73,7 +73,7 @@
 3:
 
 #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
-       PTR_L   t8, __stack_chk_guard
+       PTR_LA  t8, __stack_chk_guard
        LONG_L  t9, TASK_STACK_CANARY(a1)
        LONG_S  t9, 0(t8)
 #endif
index 45f1ffc..24cdf64 100644 (file)
@@ -971,11 +971,11 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
 [C(LL)] = {
        [C(OP_READ)] = {
                [C(RESULT_ACCESS)]      = { 0x1c, CNTR_ODD, P },
-               [C(RESULT_MISS)]        = { 0x1d, CNTR_EVEN | CNTR_ODD, P },
+               [C(RESULT_MISS)]        = { 0x1d, CNTR_EVEN, P },
        },
        [C(OP_WRITE)] = {
                [C(RESULT_ACCESS)]      = { 0x1c, CNTR_ODD, P },
-               [C(RESULT_MISS)]        = { 0x1d, CNTR_EVEN | CNTR_ODD, P },
+               [C(RESULT_MISS)]        = { 0x1d, CNTR_EVEN, P },
        },
 },
 [C(ITLB)] = {
index 38af83f..20b7b04 100644 (file)
@@ -67,7 +67,7 @@ LEAF(resume)
 1:
 
 #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
-       PTR_L   t8, __stack_chk_guard
+       PTR_LA  t8, __stack_chk_guard
        LONG_L  t9, TASK_STACK_CANARY(a1)
        LONG_S  t9, 0(t8)
 #endif
index 921238a..078de5e 100644 (file)
@@ -69,7 +69,7 @@
 1:
 
 #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
-       PTR_L   t8, __stack_chk_guard
+       PTR_LA  t8, __stack_chk_guard
        LONG_L  t9, TASK_STACK_CANARY(a1)
        LONG_S  t9, 0(t8)
 #endif
index 627883b..bc6f96f 100644 (file)
@@ -609,6 +609,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
                        r4k_blast_scache();
                else
                        blast_scache_range(addr, addr + size);
+               preempt_enable();
                __sync();
                return;
        }
@@ -650,6 +651,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
                         */
                        blast_inv_scache_range(addr, addr + size);
                }
+               preempt_enable();
                __sync();
                return;
        }
index c69da37..5b28e81 100644 (file)
@@ -473,7 +473,7 @@ static void __init fill_ipi_map(void)
 {
        int cpu;
 
-       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+       for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
                fill_ipi_map1(gic_resched_int_base, cpu, GIC_CPU_INT1);
                fill_ipi_map1(gic_call_int_base, cpu, GIC_CPU_INT2);
        }
@@ -574,8 +574,9 @@ void __init arch_init_irq(void)
                /* FIXME */
                int i;
 #if defined(CONFIG_MIPS_MT_SMP)
-               gic_call_int_base = GIC_NUM_INTRS - NR_CPUS;
-               gic_resched_int_base = gic_call_int_base - NR_CPUS;
+               gic_call_int_base = GIC_NUM_INTRS -
+                       (NR_CPUS - nr_cpu_ids) * 2 - nr_cpu_ids;
+               gic_resched_int_base = gic_call_int_base - nr_cpu_ids;
                fill_ipi_map();
 #endif
                gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map,
@@ -599,7 +600,7 @@ void __init arch_init_irq(void)
                printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status());
                write_c0_status(0x1100dc00);
                printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status());
-               for (i = 0; i < NR_CPUS; i++) {
+               for (i = 0; i < nr_cpu_ids; i++) {
                        arch_init_ipiirq(MIPS_GIC_IRQ_BASE +
                                         GIC_RESCHED_INT(i), &irq_resched);
                        arch_init_ipiirq(MIPS_GIC_IRQ_BASE +
index e49241a..2027857 100644 (file)
@@ -126,7 +126,7 @@ static int rt_timer_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
-       rt->membase = devm_request_and_ioremap(&pdev->dev, res);
+       rt->membase = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(rt->membase))
                return PTR_ERR(rt->membase);
 
index 0f90569..9387cc2 100644 (file)
@@ -40,6 +40,8 @@ CONFIG_IP_NF_QUEUE=m
 CONFIG_LLC2=m
 CONFIG_NET_PKTGEN=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_PARPORT=y
index b647b18..9002532 100644 (file)
@@ -79,6 +79,8 @@ CONFIG_IP_DCCP=m
 CONFIG_LLC2=m
 CONFIG_NET_PKTGEN=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_BLK_DEV_UMEM=m
index e289f5b..f1a0c25 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODVERSIONS=y
@@ -27,6 +28,8 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
index 311ca36..ec1b014 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
@@ -39,6 +40,8 @@ CONFIG_NETFILTER_DEBUG=y
 CONFIG_IP_NF_QUEUE=m
 CONFIG_NET_PKTGEN=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_BLK_DEV_UMEM=m
index f110063..e1c8d20 100644 (file)
@@ -62,6 +62,8 @@ CONFIG_TIPC=m
 CONFIG_LLC2=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
index dfe88f6..ba61495 100644 (file)
@@ -49,6 +49,8 @@ CONFIG_INET6_ESP=y
 CONFIG_INET6_IPCOMP=y
 CONFIG_LLC2=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_PARPORT=y
index 1945f99..4736020 100644 (file)
@@ -6,7 +6,7 @@ struct pt_regs;
 
 /* traps.c */
 void parisc_terminate(char *msg, struct pt_regs *regs,
-               int code, unsigned long offset);
+               int code, unsigned long offset) __noreturn __cold;
 
 /* mm/fault.c */
 void do_page_fault(struct pt_regs *regs, unsigned long code,
index 37aabd7..d2d5825 100644 (file)
@@ -195,6 +195,8 @@ common_stext:
        ldw             MEM_PDC_HI(%r0),%r6
        depd            %r6, 31, 32, %r3        /* move to upper word */
 
+       mfctl           %cr30,%r6               /* PCX-W2 firmware bug */
+
        ldo             PDC_PSW(%r0),%arg0              /* 21 */
        ldo             PDC_PSW_SET_DEFAULTS(%r0),%arg1 /* 2 */
        ldo             PDC_PSW_WIDE_BIT(%r0),%arg2     /* 2 */
@@ -203,6 +205,8 @@ common_stext:
        copy            %r0,%arg3
 
 stext_pdc_ret:
+       mtctl           %r6,%cr30               /* restore task thread info */
+
        /* restore rfi target address*/
        ldd             TI_TASK-THREAD_SZ_ALGN(%sp), %r10
        tophys_r1       %r10
index 8a252f2..2b96602 100644 (file)
@@ -72,7 +72,6 @@ enum ipi_message_type {
        IPI_NOP=0,
        IPI_RESCHEDULE=1,
        IPI_CALL_FUNC,
-       IPI_CALL_FUNC_SINGLE,
        IPI_CPU_START,
        IPI_CPU_STOP,
        IPI_CPU_TEST
@@ -164,11 +163,6 @@ ipi_interrupt(int irq, void *dev_id)
                                generic_smp_call_function_interrupt();
                                break;
 
-                       case IPI_CALL_FUNC_SINGLE:
-                               smp_debug(100, KERN_DEBUG "CPU%d IPI_CALL_FUNC_SINGLE\n", this_cpu);
-                               generic_smp_call_function_single_interrupt();
-                               break;
-
                        case IPI_CPU_START:
                                smp_debug(100, KERN_DEBUG "CPU%d IPI_CPU_START\n", this_cpu);
                                break;
@@ -260,7 +254,7 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 
 void arch_send_call_function_single_ipi(int cpu)
 {
-       send_IPI_single(cpu, IPI_CALL_FUNC_SINGLE);
+       send_IPI_single(cpu, IPI_CALL_FUNC);
 }
 
 /*
index 04e47c6..1cd1d0c 100644 (file)
@@ -291,11 +291,6 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
        do_exit(SIGSEGV);
 }
 
-int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs)
-{
-       return syscall(regs);
-}
-
 /* gdb uses break 4,8 */
 #define GDB_BREAK_INSN 0x10004
 static void handle_gdb_break(struct pt_regs *regs, int wot)
@@ -805,14 +800,14 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
        else {
 
            /*
-            * The kernel should never fault on its own address space.
+            * The kernel should never fault on its own address space,
+            * unless pagefault_disable() was called before.
             */
 
-           if (fault_space == 0
+           if (fault_space == 0 && !in_atomic())
            {
                pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
                parisc_terminate("Kernel Fault", regs, code, fault_address);
-       
            }
        }
 
index ac4370b..b5507ec 100644 (file)
@@ -56,7 +56,7 @@
 #ifdef __KERNEL__
 #include <linux/module.h>
 #include <linux/compiler.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #define s_space "%%sr1"
 #define d_space "%%sr2"
 #else
@@ -524,4 +524,17 @@ EXPORT_SYMBOL(copy_to_user);
 EXPORT_SYMBOL(copy_from_user);
 EXPORT_SYMBOL(copy_in_user);
 EXPORT_SYMBOL(memcpy);
+
+long probe_kernel_read(void *dst, const void *src, size_t size)
+{
+       unsigned long addr = (unsigned long)src;
+
+       if (size < 0 || addr < PAGE_SIZE)
+               return -EFAULT;
+
+       /* check for I/O space F_EXTEND(0xfff00000) access as well? */
+
+       return __probe_kernel_read(dst, src, size);
+}
+
 #endif
index d10d27a..0293588 100644 (file)
@@ -171,17 +171,25 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
                              unsigned long address)
 {
        struct vm_area_struct *vma, *prev_vma;
-       struct task_struct *tsk = current;
-       struct mm_struct *mm = tsk->mm;
+       struct task_struct *tsk;
+       struct mm_struct *mm;
        unsigned long acc_type;
        int fault;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+       unsigned int flags;
 
-       if (in_atomic() || !mm)
+       if (in_atomic())
                goto no_context;
 
+       tsk = current;
+       mm = tsk->mm;
+       if (!mm)
+               goto no_context;
+
+       flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
        if (user_mode(regs))
                flags |= FAULT_FLAG_USER;
+
+       acc_type = parisc_acctyp(code, regs->iir);
        if (acc_type & VM_WRITE)
                flags |= FAULT_FLAG_WRITE;
 retry:
@@ -196,8 +204,6 @@ retry:
 
 good_area:
 
-       acc_type = parisc_acctyp(code,regs->iir);
-
        if ((vma->vm_flags & acc_type) != acc_type)
                goto bad_area;
 
index ae098c4..f016bb6 100644 (file)
@@ -19,7 +19,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm goto("1:\n\t"
+       asm_volatile_goto("1:\n\t"
                 "nop\n\t"
                 ".pushsection __jump_table,  \"aw\"\n\t"
                 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
index 0adab06..572bb5b 100644 (file)
@@ -661,7 +661,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
        /* number of bytes needed for the bitmap */
        sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long);
 
-       page = alloc_pages_node(nid, GFP_ATOMIC, get_order(sz));
+       page = alloc_pages_node(nid, GFP_KERNEL, get_order(sz));
        if (!page)
                panic("iommu_init_table: Can't allocate %ld bytes\n", sz);
        tbl->it_map = page_address(page);
index 57d286a..c7cb8c2 100644 (file)
@@ -495,14 +495,15 @@ void __do_irq(struct pt_regs *regs)
 void do_IRQ(struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
-       struct thread_info *curtp, *irqtp;
+       struct thread_info *curtp, *irqtp, *sirqtp;
 
        /* Switch to the irq stack to handle this */
        curtp = current_thread_info();
        irqtp = hardirq_ctx[raw_smp_processor_id()];
+       sirqtp = softirq_ctx[raw_smp_processor_id()];
 
        /* Already there ? */
-       if (unlikely(curtp == irqtp)) {
+       if (unlikely(curtp == irqtp || curtp == sirqtp)) {
                __do_irq(regs);
                set_irq_regs(old_regs);
                return;
index 27a90b9..b4e6676 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/machdep.h>
 #include <asm/smp.h>
 #include <asm/pmc.h>
+#include <asm/firmware.h>
 
 #include "cacheinfo.h"
 
@@ -179,15 +180,25 @@ SYSFS_PMCSETUP(spurr, SPRN_SPURR);
 SYSFS_PMCSETUP(dscr, SPRN_DSCR);
 SYSFS_PMCSETUP(pir, SPRN_PIR);
 
+/*
+  Lets only enable read for phyp resources and
+  enable write when needed with a separate function.
+  Lets be conservative and default to pseries.
+*/
 static DEVICE_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
 static DEVICE_ATTR(spurr, 0400, show_spurr, NULL);
 static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr);
-static DEVICE_ATTR(purr, 0600, show_purr, store_purr);
+static DEVICE_ATTR(purr, 0400, show_purr, store_purr);
 static DEVICE_ATTR(pir, 0400, show_pir, NULL);
 
 unsigned long dscr_default = 0;
 EXPORT_SYMBOL(dscr_default);
 
+static void add_write_permission_dev_attr(struct device_attribute *attr)
+{
+       attr->attr.mode |= 0200;
+}
+
 static ssize_t show_dscr_default(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -394,8 +405,11 @@ static void register_cpu_online(unsigned int cpu)
        if (cpu_has_feature(CPU_FTR_MMCRA))
                device_create_file(s, &dev_attr_mmcra);
 
-       if (cpu_has_feature(CPU_FTR_PURR))
+       if (cpu_has_feature(CPU_FTR_PURR)) {
+               if (!firmware_has_feature(FW_FEATURE_LPAR))
+                       add_write_permission_dev_attr(&dev_attr_purr);
                device_create_file(s, &dev_attr_purr);
+       }
 
        if (cpu_has_feature(CPU_FTR_SPURR))
                device_create_file(s, &dev_attr_spurr);
index 7b60b98..cd809ea 100644 (file)
@@ -79,6 +79,11 @@ _GLOBAL(tm_abort)
        TABORT(R3)
        blr
 
+       .section        ".toc","aw"
+DSCR_DEFAULT:
+       .tc dscr_default[TC],dscr_default
+
+       .section        ".text"
 
 /* void tm_reclaim(struct thread_struct *thread,
  *                 unsigned long orig_msr,
@@ -123,6 +128,7 @@ _GLOBAL(tm_reclaim)
        mr      r15, r14
        ori     r15, r15, MSR_FP
        li      r16, MSR_RI
+       ori     r16, r16, MSR_EE /* IRQs hard off */
        andc    r15, r15, r16
        oris    r15, r15, MSR_VEC@h
 #ifdef CONFIG_VSX
@@ -187,11 +193,18 @@ dont_backup_fp:
        std     r1, PACATMSCRATCH(r13)
        ld      r1, PACAR1(r13)
 
+       /* Store the PPR in r11 and reset to decent value */
+       std     r11, GPR11(r1)                  /* Temporary stash */
+       mfspr   r11, SPRN_PPR
+       HMT_MEDIUM
+
        /* Now get some more GPRS free */
        std     r7, GPR7(r1)                    /* Temporary stash */
        std     r12, GPR12(r1)                  /* ''   ''    ''   */
        ld      r12, STACK_PARAM(0)(r1)         /* Param 0, thread_struct * */
 
+       std     r11, THREAD_TM_PPR(r12)         /* Store PPR and free r11 */
+
        addi    r7, r12, PT_CKPT_REGS           /* Thread's ckpt_regs */
 
        /* Make r7 look like an exception frame so that we
@@ -203,15 +216,19 @@ dont_backup_fp:
        SAVE_GPR(0, r7)                         /* user r0 */
        SAVE_GPR(2, r7)                 /* user r2 */
        SAVE_4GPRS(3, r7)                       /* user r3-r6 */
-       SAVE_4GPRS(8, r7)                       /* user r8-r11 */
+       SAVE_GPR(8, r7)                         /* user r8 */
+       SAVE_GPR(9, r7)                         /* user r9 */
+       SAVE_GPR(10, r7)                        /* user r10 */
        ld      r3, PACATMSCRATCH(r13)          /* user r1 */
        ld      r4, GPR7(r1)                    /* user r7 */
-       ld      r5, GPR12(r1)                   /* user r12 */
-       GET_SCRATCH0(6)                         /* user r13 */
+       ld      r5, GPR11(r1)                   /* user r11 */
+       ld      r6, GPR12(r1)                   /* user r12 */
+       GET_SCRATCH0(8)                         /* user r13 */
        std     r3, GPR1(r7)
        std     r4, GPR7(r7)
-       std     r5, GPR12(r7)
-       std     r6, GPR13(r7)
+       std     r5, GPR11(r7)
+       std     r6, GPR12(r7)
+       std     r8, GPR13(r7)
 
        SAVE_NVGPRS(r7)                         /* user r14-r31 */
 
@@ -234,14 +251,12 @@ dont_backup_fp:
        std     r6, _XER(r7)
 
 
-       /* ******************** TAR, PPR, DSCR ********** */
+       /* ******************** TAR, DSCR ********** */
        mfspr   r3, SPRN_TAR
-       mfspr   r4, SPRN_PPR
-       mfspr   r5, SPRN_DSCR
+       mfspr   r4, SPRN_DSCR
 
        std     r3, THREAD_TM_TAR(r12)
-       std     r4, THREAD_TM_PPR(r12)
-       std     r5, THREAD_TM_DSCR(r12)
+       std     r4, THREAD_TM_DSCR(r12)
 
        /* MSR and flags:  We don't change CRs, and we don't need to alter
         * MSR.
@@ -258,7 +273,7 @@ dont_backup_fp:
        std     r3, THREAD_TM_TFHAR(r12)
        std     r4, THREAD_TM_TFIAR(r12)
 
-       /* AMR and PPR are checkpointed too, but are unsupported by Linux. */
+       /* AMR is checkpointed too, but is unsupported by Linux. */
 
        /* Restore original MSR/IRQ state & clear TM mode */
        ld      r14, TM_FRAME_L0(r1)            /* Orig MSR */
@@ -274,6 +289,12 @@ dont_backup_fp:
        mtcr    r4
        mtlr    r0
        ld      r2, 40(r1)
+
+       /* Load system default DSCR */
+       ld      r4, DSCR_DEFAULT@toc(r2)
+       ld      r0, 0(r4)
+       mtspr   SPRN_DSCR, r0
+
        blr
 
 
@@ -358,25 +379,24 @@ dont_restore_fp:
 
 restore_gprs:
 
-       /* ******************** TAR, PPR, DSCR ********** */
-       ld      r4, THREAD_TM_TAR(r3)
-       ld      r5, THREAD_TM_PPR(r3)
-       ld      r6, THREAD_TM_DSCR(r3)
+       /* ******************** CR,LR,CCR,MSR ********** */
+       ld      r4, _CTR(r7)
+       ld      r5, _LINK(r7)
+       ld      r6, _CCR(r7)
+       ld      r8, _XER(r7)
 
-       mtspr   SPRN_TAR,       r4
-       mtspr   SPRN_PPR,       r5
-       mtspr   SPRN_DSCR,      r6
+       mtctr   r4
+       mtlr    r5
+       mtcr    r6
+       mtxer   r8
 
-       /* ******************** CR,LR,CCR,MSR ********** */
-       ld      r3, _CTR(r7)
-       ld      r4, _LINK(r7)
-       ld      r5, _CCR(r7)
-       ld      r6, _XER(r7)
+       /* ******************** TAR ******************** */
+       ld      r4, THREAD_TM_TAR(r3)
+       mtspr   SPRN_TAR,       r4
 
-       mtctr   r3
-       mtlr    r4
-       mtcr    r5
-       mtxer   r6
+       /* Load up the PPR and DSCR in GPRs only at this stage */
+       ld      r5, THREAD_TM_DSCR(r3)
+       ld      r6, THREAD_TM_PPR(r3)
 
        /* Clear the MSR RI since we are about to change R1.  EE is already off
         */
@@ -384,19 +404,26 @@ restore_gprs:
        mtmsrd  r4, 1
 
        REST_4GPRS(0, r7)                       /* GPR0-3 */
-       REST_GPR(4, r7)                         /* GPR4-6 */
-       REST_GPR(5, r7)
-       REST_GPR(6, r7)
+       REST_GPR(4, r7)                         /* GPR4 */
        REST_4GPRS(8, r7)                       /* GPR8-11 */
        REST_2GPRS(12, r7)                      /* GPR12-13 */
 
        REST_NVGPRS(r7)                         /* GPR14-31 */
 
-       ld      r7, GPR7(r7)                    /* GPR7 */
+       /* Load up PPR and DSCR here so we don't run with user values for long
+        */
+       mtspr   SPRN_DSCR, r5
+       mtspr   SPRN_PPR, r6
+
+       REST_GPR(5, r7)                         /* GPR5-7 */
+       REST_GPR(6, r7)
+       ld      r7, GPR7(r7)
 
        /* Commit register state as checkpointed state: */
        TRECHKPT
 
+       HMT_MEDIUM
+
        /* Our transactional state has now changed.
         *
         * Now just get out of here.  Transactional (current) state will be
@@ -419,6 +446,12 @@ restore_gprs:
        mtcr    r4
        mtlr    r0
        ld      r2, 40(r1)
+
+       /* Load system default DSCR */
+       ld      r4, DSCR_DEFAULT@toc(r2)
+       ld      r0, 0(r4)
+       mtspr   SPRN_DSCR, r0
+
        blr
 
        /* ****************************************************************** */
index 78a3506..d38cc08 100644 (file)
@@ -1530,11 +1530,15 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
        const char *cp;
 
        dn = dev->of_node;
-       if (!dn)
-               return -ENODEV;
+       if (!dn) {
+               strcat(buf, "\n");
+               return strlen(buf);
+       }
        cp = of_get_property(dn, "compatible", NULL);
-       if (!cp)
-               return -ENODEV;
+       if (!cp) {
+               strcat(buf, "\n");
+               return strlen(buf);
+       }
 
        return sprintf(buf, "vio:T%sS%s\n", vio_dev->type, cp);
 }
index 294b7af..c71103b 100644 (file)
@@ -1066,7 +1066,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 BEGIN_FTR_SECTION
        mfspr   r8, SPRN_DSCR
        ld      r7, HSTATE_DSCR(r13)
-       std     r8, VCPU_DSCR(r7)
+       std     r8, VCPU_DSCR(r9)
        mtspr   SPRN_DSCR, r7
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 
index 1c6a9d7..c65593a 100644 (file)
@@ -332,6 +332,13 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
        unsigned long hva;
        int pfnmap = 0;
        int tsize = BOOK3E_PAGESZ_4K;
+       int ret = 0;
+       unsigned long mmu_seq;
+       struct kvm *kvm = vcpu_e500->vcpu.kvm;
+
+       /* used to check for invalidations in progress */
+       mmu_seq = kvm->mmu_notifier_seq;
+       smp_rmb();
 
        /*
         * Translate guest physical to true physical, acquiring
@@ -449,6 +456,12 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
        }
 
+       spin_lock(&kvm->mmu_lock);
+       if (mmu_notifier_retry(kvm, mmu_seq)) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
        kvmppc_e500_ref_setup(ref, gtlbe, pfn);
 
        kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
@@ -457,10 +470,13 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
        /* Clear i-cache for new pages */
        kvmppc_mmu_flush_icache(pfn);
 
+out:
+       spin_unlock(&kvm->mmu_lock);
+
        /* Drop refcount on page, so that mmu notifiers can clear it */
        kvm_release_pfn_clean(pfn);
 
-       return 0;
+       return ret;
 }
 
 /* XXX only map the one-one case, for now use TLB0 */
index 167f725..57a0720 100644 (file)
@@ -226,19 +226,35 @@ _GLOBAL(csum_partial)
        blr
 
 
-       .macro source
+       .macro srcnr
 100:
        .section __ex_table,"a"
        .align 3
-       .llong 100b,.Lsrc_error
+       .llong 100b,.Lsrc_error_nr
        .previous
        .endm
 
-       .macro dest
+       .macro source
+150:
+       .section __ex_table,"a"
+       .align 3
+       .llong 150b,.Lsrc_error
+       .previous
+       .endm
+
+       .macro dstnr
 200:
        .section __ex_table,"a"
        .align 3
-       .llong 200b,.Ldest_error
+       .llong 200b,.Ldest_error_nr
+       .previous
+       .endm
+
+       .macro dest
+250:
+       .section __ex_table,"a"
+       .align 3
+       .llong 250b,.Ldest_error
        .previous
        .endm
 
@@ -269,16 +285,16 @@ _GLOBAL(csum_partial_copy_generic)
        rldicl. r6,r3,64-1,64-2         /* r6 = (r3 & 0x3) >> 1 */
        beq     .Lcopy_aligned
 
-       li      r7,4
-       sub     r6,r7,r6
+       li      r9,4
+       sub     r6,r9,r6
        mtctr   r6
 
 1:
-source;        lhz     r6,0(r3)                /* align to doubleword */
+srcnr; lhz     r6,0(r3)                /* align to doubleword */
        subi    r5,r5,2
        addi    r3,r3,2
        adde    r0,r0,r6
-dest;  sth     r6,0(r4)
+dstnr; sth     r6,0(r4)
        addi    r4,r4,2
        bdnz    1b
 
@@ -392,10 +408,10 @@ dest;     std     r16,56(r4)
 
        mtctr   r6
 3:
-source;        ld      r6,0(r3)
+srcnr; ld      r6,0(r3)
        addi    r3,r3,8
        adde    r0,r0,r6
-dest;  std     r6,0(r4)
+dstnr; std     r6,0(r4)
        addi    r4,r4,8
        bdnz    3b
 
@@ -405,10 +421,10 @@ dest;     std     r6,0(r4)
        srdi.   r6,r5,2
        beq     .Lcopy_tail_halfword
 
-source;        lwz     r6,0(r3)
+srcnr; lwz     r6,0(r3)
        addi    r3,r3,4
        adde    r0,r0,r6
-dest;  stw     r6,0(r4)
+dstnr; stw     r6,0(r4)
        addi    r4,r4,4
        subi    r5,r5,4
 
@@ -416,10 +432,10 @@ dest;     stw     r6,0(r4)
        srdi.   r6,r5,1
        beq     .Lcopy_tail_byte
 
-source;        lhz     r6,0(r3)
+srcnr; lhz     r6,0(r3)
        addi    r3,r3,2
        adde    r0,r0,r6
-dest;  sth     r6,0(r4)
+dstnr; sth     r6,0(r4)
        addi    r4,r4,2
        subi    r5,r5,2
 
@@ -427,10 +443,10 @@ dest;     sth     r6,0(r4)
        andi.   r6,r5,1
        beq     .Lcopy_finish
 
-source;        lbz     r6,0(r3)
+srcnr; lbz     r6,0(r3)
        sldi    r9,r6,8                 /* Pad the byte out to 16 bits */
        adde    r0,r0,r9
-dest;  stb     r6,0(r4)
+dstnr; stb     r6,0(r4)
 
 .Lcopy_finish:
        addze   r0,r0                   /* add in final carry */
@@ -440,6 +456,11 @@ dest;      stb     r6,0(r4)
        blr
 
 .Lsrc_error:
+       ld      r14,STK_REG(R14)(r1)
+       ld      r15,STK_REG(R15)(r1)
+       ld      r16,STK_REG(R16)(r1)
+       addi    r1,r1,STACKFRAMESIZE
+.Lsrc_error_nr:
        cmpdi   0,r7,0
        beqlr
        li      r6,-EFAULT
@@ -447,6 +468,11 @@ dest;      stb     r6,0(r4)
        blr
 
 .Ldest_error:
+       ld      r14,STK_REG(R14)(r1)
+       ld      r15,STK_REG(R15)(r1)
+       ld      r16,STK_REG(R16)(r1)
+       addi    r1,r1,STACKFRAMESIZE
+.Ldest_error_nr:
        cmpdi   0,r8,0
        beqlr
        li      r6,-EFAULT
index d0cd9e4..8ed035d 100644 (file)
@@ -300,5 +300,9 @@ void vmemmap_free(unsigned long start, unsigned long end)
 {
 }
 
+void register_page_bootmem_memmap(unsigned long section_nr,
+                                 struct page *start_page, unsigned long size)
+{
+}
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
index 1cf9c5b..3fa93dc 100644 (file)
@@ -297,12 +297,21 @@ void __init paging_init(void)
 }
 #endif /* ! CONFIG_NEED_MULTIPLE_NODES */
 
+static void __init register_page_bootmem_info(void)
+{
+       int i;
+
+       for_each_online_node(i)
+               register_page_bootmem_info_node(NODE_DATA(i));
+}
+
 void __init mem_init(void)
 {
 #ifdef CONFIG_SWIOTLB
        swiotlb_init(0);
 #endif
 
+       register_page_bootmem_info();
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
        set_max_mapnr(max_pfn);
        free_all_bootmem();
index bf56e33..2345bdb 100644 (file)
@@ -691,4 +691,5 @@ void bpf_jit_free(struct sk_filter *fp)
 {
        if (fp->bpf_func != sk_run_filter)
                module_free(NULL, fp->bpf_func);
+       kfree(fp);
 }
index 2ee4a70..a3f7abd 100644 (file)
 #define MMCR1_UNIT_SHIFT(pmc)          (60 - (4 * ((pmc) - 1)))
 #define MMCR1_COMBINE_SHIFT(pmc)       (35 - ((pmc) - 1))
 #define MMCR1_PMCSEL_SHIFT(pmc)                (24 - (((pmc) - 1)) * 8)
+#define MMCR1_FAB_SHIFT                        36
 #define MMCR1_DC_QUAL_SHIFT            47
 #define MMCR1_IC_QUAL_SHIFT            46
 
@@ -388,8 +389,8 @@ static int power8_compute_mmcr(u64 event[], int n_ev,
                 * the threshold bits are used for the match value.
                 */
                if (event_is_fab_match(event[i])) {
-                       mmcr1 |= (event[i] >> EVENT_THR_CTL_SHIFT) &
-                                 EVENT_THR_CTL_MASK;
+                       mmcr1 |= ((event[i] >> EVENT_THR_CTL_SHIFT) &
+                                 EVENT_THR_CTL_MASK) << MMCR1_FAB_SHIFT;
                } else {
                        val = (event[i] >> EVENT_THR_CTL_SHIFT) & EVENT_THR_CTL_MASK;
                        mmcra |= val << MMCRA_THR_CTL_SHIFT;
index 6c32190..346b1c8 100644 (file)
@@ -15,7 +15,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm goto("0:    brcl 0,0\n"
+       asm_volatile_goto("0:   brcl 0,0\n"
                ".pushsection __jump_table, \"aw\"\n"
                ASM_ALIGN "\n"
                ASM_PTR " 0b, %l[label], %0\n"
index 9b60a36..2204400 100644 (file)
@@ -748,7 +748,9 @@ static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry)
 
 static inline void pgste_set_pte(pte_t *ptep, pte_t entry)
 {
-       if (!MACHINE_HAS_ESOP && (pte_val(entry) & _PAGE_WRITE)) {
+       if (!MACHINE_HAS_ESOP &&
+           (pte_val(entry) & _PAGE_PRESENT) &&
+           (pte_val(entry) & _PAGE_WRITE)) {
                /*
                 * Without enhanced suppression-on-protection force
                 * the dirty bit on for all writable ptes.
index 8ad8af9..819b94d 100644 (file)
@@ -71,30 +71,30 @@ static inline void local_tick_enable(unsigned long long comp)
 
 typedef unsigned long long cycles_t;
 
-static inline unsigned long long get_tod_clock(void)
-{
-       unsigned long long clk;
-
-#ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES
-       asm volatile(".insn s,0xb27c0000,%0" : "=Q" (clk) : : "cc");
-#else
-       asm volatile("stck %0" : "=Q" (clk) : : "cc");
-#endif
-       return clk;
-}
-
 static inline void get_tod_clock_ext(char *clk)
 {
        asm volatile("stcke %0" : "=Q" (*clk) : : "cc");
 }
 
-static inline unsigned long long get_tod_clock_xt(void)
+static inline unsigned long long get_tod_clock(void)
 {
        unsigned char clk[16];
        get_tod_clock_ext(clk);
        return *((unsigned long long *)&clk[1]);
 }
 
+static inline unsigned long long get_tod_clock_fast(void)
+{
+#ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES
+       unsigned long long clk;
+
+       asm volatile("stckf %0" : "=Q" (clk) : : "cc");
+       return clk;
+#else
+       return get_tod_clock();
+#endif
+}
+
 static inline cycles_t get_cycles(void)
 {
        return (cycles_t) get_tod_clock() >> 2;
@@ -125,7 +125,7 @@ extern u64 sched_clock_base_cc;
  */
 static inline unsigned long long get_tod_clock_monotonic(void)
 {
-       return get_tod_clock_xt() - sched_clock_base_cc;
+       return get_tod_clock() - sched_clock_base_cc;
 }
 
 /**
index 1389b63..adaa9e9 100644 (file)
@@ -99,7 +99,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
                        break;
                }
        }
-       return err;
+       return err ? -EFAULT : 0;
 }
 
 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
@@ -148,7 +148,7 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
                        break;
                }
        }
-       return err;
+       return err ? -EFAULT : 0;
 }
 
 static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
index c84f33d..7dd2172 100644 (file)
@@ -40,28 +40,26 @@ static inline void *load_real_addr(void *addr)
 }
 
 /*
- * Copy up to one page to vmalloc or real memory
+ * Copy real to virtual or real memory
  */
-static ssize_t copy_page_real(void *buf, void *src, size_t csize)
+static int copy_from_realmem(void *dest, void *src, size_t count)
 {
-       size_t size;
+       unsigned long size;
+       int rc;
 
-       if (is_vmalloc_addr(buf)) {
-               BUG_ON(csize >= PAGE_SIZE);
-               /* If buf is not page aligned, copy first part */
-               size = min(roundup(__pa(buf), PAGE_SIZE) - __pa(buf), csize);
-               if (size) {
-                       if (memcpy_real(load_real_addr(buf), src, size))
-                               return -EFAULT;
-                       buf += size;
-                       src += size;
-               }
-               /* Copy second part */
-               size = csize - size;
-               return (size) ? memcpy_real(load_real_addr(buf), src, size) : 0;
-       } else {
-               return memcpy_real(buf, src, csize);
-       }
+       if (!count)
+               return 0;
+       if (!is_vmalloc_or_module_addr(dest))
+               return memcpy_real(dest, src, count);
+       do {
+               size = min(count, PAGE_SIZE - (__pa(dest) & ~PAGE_MASK));
+               if (memcpy_real(load_real_addr(dest), src, size))
+                       return -EFAULT;
+               count -= size;
+               dest += size;
+               src += size;
+       } while (count);
+       return 0;
 }
 
 /*
@@ -114,7 +112,7 @@ static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize,
                rc = copy_to_user_real((void __force __user *) buf,
                                       (void *) src, csize);
        else
-               rc = copy_page_real(buf, (void *) src, csize);
+               rc = copy_from_realmem(buf, (void *) src, csize);
        return (rc == 0) ? rc : csize;
 }
 
@@ -210,7 +208,7 @@ int copy_from_oldmem(void *dest, void *src, size_t count)
        if (OLDMEM_BASE) {
                if ((unsigned long) src < OLDMEM_SIZE) {
                        copied = min(count, OLDMEM_SIZE - (unsigned long) src);
-                       rc = memcpy_real(dest, src + OLDMEM_BASE, copied);
+                       rc = copy_from_realmem(dest, src + OLDMEM_BASE, copied);
                        if (rc)
                                return rc;
                }
@@ -223,7 +221,7 @@ int copy_from_oldmem(void *dest, void *src, size_t count)
                                return rc;
                }
        }
-       return memcpy_real(dest + copied, src + copied, count - copied);
+       return copy_from_realmem(dest + copied, src + copied, count - copied);
 }
 
 /*
index f1279dc..17d62fe 100644 (file)
@@ -867,7 +867,7 @@ static inline void
 debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
                        int exception)
 {
-       active->id.stck = get_tod_clock();
+       active->id.stck = get_tod_clock_fast();
        active->id.fields.cpuid = smp_processor_id();
        active->caller = __builtin_return_address(0);
        active->id.fields.exception = exception;
index cc30d1f..0dc2b6d 100644 (file)
@@ -266,6 +266,7 @@ sysc_sigpending:
        tm      __TI_flags+3(%r12),_TIF_SYSCALL
        jno     sysc_return
        lm      %r2,%r7,__PT_R2(%r11)   # load svc arguments
+       l       %r10,__TI_sysc_table(%r12)      # 31 bit system call table
        xr      %r8,%r8                 # svc 0 returns -ENOSYS
        clc     __PT_INT_CODE+2(2,%r11),BASED(.Lnr_syscalls+2)
        jnl     sysc_nr_ok              # invalid svc number -> do svc 0
index 2b2188b..e5b43c9 100644 (file)
@@ -297,6 +297,7 @@ sysc_sigpending:
        tm      __TI_flags+7(%r12),_TIF_SYSCALL
        jno     sysc_return
        lmg     %r2,%r7,__PT_R2(%r11)   # load svc arguments
+       lg      %r10,__TI_sysc_table(%r12)      # address of system call table
        lghi    %r8,0                   # svc 0 returns -ENOSYS
        llgh    %r1,__PT_INT_CODE+2(%r11)       # load new svc number
        cghi    %r1,NR_syscalls
index 0ce9fb2..d86e64e 100644 (file)
@@ -67,6 +67,11 @@ static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn)
        case 0xac:      /* stnsm */
        case 0xad:      /* stosm */
                return -EINVAL;
+       case 0xc6:
+               switch (insn[0] & 0x0f) {
+               case 0x00: /* exrl   */
+                       return -EINVAL;
+               }
        }
        switch (insn[0]) {
        case 0x0101:    /* pr    */
@@ -180,7 +185,6 @@ static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn)
                break;
        case 0xc6:
                switch (insn[0] & 0x0f) {
-               case 0x00: /* exrl   */
                case 0x02: /* pfdrl  */
                case 0x04: /* cghrl  */
                case 0x05: /* chrl   */
index 7f35cb3..7f1f7ac 100644 (file)
@@ -385,7 +385,7 @@ static int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
        }
 
        if ((!rc) && (vcpu->arch.sie_block->ckc <
-               get_tod_clock() + vcpu->arch.sie_block->epoch)) {
+               get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) {
                if ((!psw_extint_disabled(vcpu)) &&
                        (vcpu->arch.sie_block->gcr[0] & 0x800ul))
                        rc = 1;
@@ -425,7 +425,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
                goto no_timer;
        }
 
-       now = get_tod_clock() + vcpu->arch.sie_block->epoch;
+       now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch;
        if (vcpu->arch.sie_block->ckc < now) {
                __unset_cpu_idle(vcpu);
                return 0;
@@ -515,7 +515,7 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
        }
 
        if ((vcpu->arch.sie_block->ckc <
-               get_tod_clock() + vcpu->arch.sie_block->epoch))
+               get_tod_clock_fast() + vcpu->arch.sie_block->epoch))
                __try_deliver_ckc_interrupt(vcpu);
 
        if (atomic_read(&fi->active)) {
index 57c87d7..a9f3d00 100644 (file)
@@ -44,7 +44,7 @@ static void __udelay_disabled(unsigned long long usecs)
        do {
                set_clock_comparator(end);
                vtime_stop_cpu();
-       } while (get_tod_clock() < end);
+       } while (get_tod_clock_fast() < end);
        lockdep_on();
        __ctl_load(cr0, 0, 0);
        __ctl_load(cr6, 6, 6);
@@ -55,7 +55,7 @@ static void __udelay_enabled(unsigned long long usecs)
 {
        u64 clock_saved, end;
 
-       end = get_tod_clock() + (usecs << 12);
+       end = get_tod_clock_fast() + (usecs << 12);
        do {
                clock_saved = 0;
                if (end < S390_lowcore.clock_comparator) {
@@ -65,7 +65,7 @@ static void __udelay_enabled(unsigned long long usecs)
                vtime_stop_cpu();
                if (clock_saved)
                        local_tick_enable(clock_saved);
-       } while (get_tod_clock() < end);
+       } while (get_tod_clock_fast() < end);
 }
 
 /*
@@ -109,8 +109,8 @@ void udelay_simple(unsigned long long usecs)
 {
        u64 end;
 
-       end = get_tod_clock() + (usecs << 12);
-       while (get_tod_clock() < end)
+       end = get_tod_clock_fast() + (usecs << 12);
+       while (get_tod_clock_fast() < end)
                cpu_relax();
 }
 
@@ -120,10 +120,10 @@ void __ndelay(unsigned long long nsecs)
 
        nsecs <<= 9;
        do_div(nsecs, 125);
-       end = get_tod_clock() + nsecs;
+       end = get_tod_clock_fast() + nsecs;
        if (nsecs & ~0xfffUL)
                __udelay(nsecs >> 12);
-       while (get_tod_clock() < end)
+       while (get_tod_clock_fast() < end)
                barrier();
 }
 EXPORT_SYMBOL(__ndelay);
index 7092392..a5df511 100644 (file)
@@ -881,7 +881,9 @@ void bpf_jit_free(struct sk_filter *fp)
        struct bpf_binary_header *header = (void *)addr;
 
        if (fp->bpf_func == sk_run_filter)
-               return;
+               goto free_filter;
        set_memory_rw(addr, header->pages);
        module_free(NULL, header);
+free_filter:
+       kfree(fp);
 }
index a1be70d..305f7ee 100644 (file)
@@ -2,6 +2,7 @@ menu "Machine selection"
 
 config SCORE
        def_bool y
+       select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
        select GENERIC_IOMAP
        select GENERIC_ATOMIC64
@@ -110,3 +111,6 @@ source "security/Kconfig"
 source "crypto/Kconfig"
 
 source "lib/Kconfig"
+
+config NO_IOMEM
+       def_bool y
index 974aefe..9e3e060 100644 (file)
@@ -20,8 +20,8 @@ cflags-y += -G0 -pipe -mel -mnhwloop -D__SCOREEL__ \
 #
 KBUILD_AFLAGS += $(cflags-y)
 KBUILD_CFLAGS += $(cflags-y)
-KBUILD_AFLAGS_MODULE += -mlong-calls
-KBUILD_CFLAGS_MODULE += -mlong-calls
+KBUILD_AFLAGS_MODULE +=
+KBUILD_CFLAGS_MODULE +=
 LDFLAGS += --oformat elf32-littlescore
 LDFLAGS_vmlinux        += -G0 -static -nostdlib
 
index f909ac3..961bd64 100644 (file)
@@ -184,48 +184,57 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
                                __wsum sum)
 {
        __asm__ __volatile__(
-               ".set\tnoreorder\t\t\t# csum_ipv6_magic\n\t"
-               ".set\tnoat\n\t"
-               "addu\t%0, %5\t\t\t# proto (long in network byte order)\n\t"
-               "sltu\t$1, %0, %5\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %6\t\t\t# csum\n\t"
-               "sltu\t$1, %0, %6\n\t"
-               "lw\t%1, 0(%2)\t\t\t# four words source address\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 4(%2)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 8(%2)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 12(%2)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 0(%3)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 4(%3)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 8(%3)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 12(%3)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "addu\t%0, $1\t\t\t# Add final carry\n\t"
-               ".set\tnoat\n\t"
-               ".set\tnoreorder"
+               ".set\tvolatile\t\t\t# csum_ipv6_magic\n\t"
+               "add\t%0, %0, %5\t\t\t# proto (long in network byte order)\n\t"
+               "cmp.c\t%5, %0\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %6\t\t\t# csum\n\t"
+               "cmp.c\t%6, %0\n\t"
+               "lw\t%1, [%2, 0]\t\t\t# four words source address\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "1:lw\t%1, [%2, 4]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%2,8]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%2, 12]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0,%1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%3, 0]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%3, 4]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%3, 8]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%3, 12]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:\n\t"
+               ".set\toptimize"
                : "=r" (sum), "=r" (proto)
                : "r" (saddr), "r" (daddr),
                  "0" (htonl(len)), "1" (htonl(proto)), "r" (sum));
index fbbfd71..574c882 100644 (file)
@@ -5,5 +5,4 @@
 
 #define virt_to_bus    virt_to_phys
 #define bus_to_virt    phys_to_virt
-
 #endif /* _ASM_SCORE_IO_H */
index 059a61b..716b3fd 100644 (file)
@@ -2,7 +2,7 @@
 #define _ASM_SCORE_PGALLOC_H
 
 #include <linux/mm.h>
-
+#include <linux/highmem.h>
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
        pte_t *pte)
 {
index 7234ed0..befb87d 100644 (file)
@@ -264,7 +264,7 @@ resume_kernel:
        disable_irq
        lw      r8, [r28, TI_PRE_COUNT]
        cmpz.c  r8
-       bne     r8, restore_all
+       bne     restore_all
 need_resched:
        lw      r8, [r28, TI_FLAGS]
        andri.c r9, r8, _TIF_NEED_RESCHED
@@ -415,7 +415,7 @@ ENTRY(handle_sys)
        sw      r9, [r0, PT_EPC]
 
        cmpi.c  r27, __NR_syscalls      # check syscall number
-       bgeu    illegal_syscall
+       bcs     illegal_syscall
 
        slli    r8, r27, 2              # get syscall routine
        la      r11, sys_call_table
index f4c6d02..a1519ad 100644 (file)
@@ -78,8 +78,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        p->thread.reg0 = (unsigned long) childregs;
        if (unlikely(p->flags & PF_KTHREAD)) {
                memset(childregs, 0, sizeof(struct pt_regs));
-               p->thread->reg12 = usp;
-               p->thread->reg13 = arg;
+               p->thread.reg12 = usp;
+               p->thread.reg13 = arg;
                p->thread.reg3 = (unsigned long) ret_from_kernel_thread;
        } else {
                *childregs = *current_pt_regs();
index 2137ad6..78c4fdb 100644 (file)
@@ -506,12 +506,17 @@ config SUN_OPENPROMFS
          Only choose N if you know in advance that you will not need to modify
          OpenPROM settings on the running system.
 
-# Makefile helper
+# Makefile helpers
 config SPARC64_PCI
        bool
        default y
        depends on SPARC64 && PCI
 
+config SPARC64_PCI_MSI
+       bool
+       default y
+       depends on SPARC64_PCI && PCI_MSI
+
 endmenu
 
 menu "Executable file formats"
index e204f90..7c90c50 100644 (file)
@@ -254,7 +254,7 @@ static int sun_fd_request_irq(void)
                once = 1;
 
                error = request_irq(FLOPPY_IRQ, sparc_floppy_irq,
-                                   IRQF_DISABLED, "floppy", NULL);
+                                   0, "floppy", NULL);
 
                return ((error == 0) ? 0 : -1);
        }
index 5080d16..ec2e2e2 100644 (file)
@@ -9,7 +9,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-               asm goto("1:\n\t"
+               asm_volatile_goto("1:\n\t"
                         "nop\n\t"
                         "nop\n\t"
                         ".pushsection __jump_table,  \"aw\"\n\t"
index d432fb2..d15cc17 100644 (file)
@@ -1,3 +1,4 @@
+
 #
 # Makefile for the linux kernel.
 #
@@ -99,7 +100,7 @@ obj-$(CONFIG_STACKTRACE)     += stacktrace.o
 obj-$(CONFIG_SPARC64_PCI)    += pci.o pci_common.o psycho_common.o
 obj-$(CONFIG_SPARC64_PCI)    += pci_psycho.o pci_sabre.o pci_schizo.o
 obj-$(CONFIG_SPARC64_PCI)    += pci_sun4v.o pci_sun4v_asm.o pci_fire.o
-obj-$(CONFIG_PCI_MSI)        += pci_msi.o
+obj-$(CONFIG_SPARC64_PCI_MSI) += pci_msi.o
 
 obj-$(CONFIG_COMPAT)         += sys32.o sys_sparc32.o signal32.o
 
index 62d6b15..dff60ab 100644 (file)
@@ -849,9 +849,8 @@ void ldom_reboot(const char *boot_command)
        if (boot_command && strlen(boot_command)) {
                unsigned long len;
 
-               strcpy(full_boot_str, "boot ");
-               strlcpy(full_boot_str + strlen("boot "), boot_command,
-                       sizeof(full_boot_str + strlen("boot ")));
+               snprintf(full_boot_str, sizeof(full_boot_str), "boot %s",
+                        boot_command);
                len = strlen(full_boot_str);
 
                if (reboot_data_supported) {
index 54df554..e01d75d 100644 (file)
@@ -1249,12 +1249,12 @@ int ldc_bind(struct ldc_channel *lp, const char *name)
        snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name);
        snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name);
 
-       err = request_irq(lp->cfg.rx_irq, ldc_rx, IRQF_DISABLED,
+       err = request_irq(lp->cfg.rx_irq, ldc_rx, 0,
                          lp->rx_irq_name, lp);
        if (err)
                return err;
 
-       err = request_irq(lp->cfg.tx_irq, ldc_tx, IRQF_DISABLED,
+       err = request_irq(lp->cfg.tx_irq, ldc_tx, 0,
                          lp->tx_irq_name, lp);
        if (err) {
                free_irq(lp->cfg.rx_irq, lp);
index 9c7be59..218b6b2 100644 (file)
@@ -808,4 +808,5 @@ void bpf_jit_free(struct sk_filter *fp)
 {
        if (fp->bpf_func != sk_run_filter)
                module_free(NULL, fp->bpf_func);
+       kfree(fp);
 }
index d385eaa..7097984 100644 (file)
@@ -166,7 +166,7 @@ static inline int atomic_cmpxchg(atomic_t *v, int o, int n)
  *
  * Atomically sets @v to @i and returns old @v
  */
-static inline u64 atomic64_xchg(atomic64_t *v, u64 n)
+static inline long long atomic64_xchg(atomic64_t *v, long long n)
 {
        return xchg64(&v->counter, n);
 }
@@ -180,7 +180,8 @@ static inline u64 atomic64_xchg(atomic64_t *v, u64 n)
  * Atomically checks if @v holds @o and replaces it with @n if so.
  * Returns the old value at @v.
  */
-static inline u64 atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n)
+static inline long long atomic64_cmpxchg(atomic64_t *v, long long o,
+                                       long long n)
 {
        return cmpxchg64(&v->counter, o, n);
 }
index 0d0395b..1ad4a1f 100644 (file)
@@ -80,7 +80,7 @@ static inline void atomic_set(atomic_t *v, int n)
 /* A 64bit atomic type */
 
 typedef struct {
-       u64 __aligned(8) counter;
+       long long counter;
 } atomic64_t;
 
 #define ATOMIC64_INIT(val) { (val) }
@@ -91,14 +91,14 @@ typedef struct {
  *
  * Atomically reads the value of @v.
  */
-static inline u64 atomic64_read(const atomic64_t *v)
+static inline long long atomic64_read(const atomic64_t *v)
 {
        /*
         * Requires an atomic op to read both 32-bit parts consistently.
         * Casting away const is safe since the atomic support routines
         * do not write to memory if the value has not been modified.
         */
-       return _atomic64_xchg_add((u64 *)&v->counter, 0);
+       return _atomic64_xchg_add((long long *)&v->counter, 0);
 }
 
 /**
@@ -108,7 +108,7 @@ static inline u64 atomic64_read(const atomic64_t *v)
  *
  * Atomically adds @i to @v.
  */
-static inline void atomic64_add(u64 i, atomic64_t *v)
+static inline void atomic64_add(long long i, atomic64_t *v)
 {
        _atomic64_xchg_add(&v->counter, i);
 }
@@ -120,7 +120,7 @@ static inline void atomic64_add(u64 i, atomic64_t *v)
  *
  * Atomically adds @i to @v and returns @i + @v
  */
-static inline u64 atomic64_add_return(u64 i, atomic64_t *v)
+static inline long long atomic64_add_return(long long i, atomic64_t *v)
 {
        smp_mb();  /* barrier for proper semantics */
        return _atomic64_xchg_add(&v->counter, i) + i;
@@ -135,7 +135,8 @@ static inline u64 atomic64_add_return(u64 i, atomic64_t *v)
  * Atomically adds @a to @v, so long as @v was not already @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-static inline u64 atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
+static inline long long atomic64_add_unless(atomic64_t *v, long long a,
+                                       long long u)
 {
        smp_mb();  /* barrier for proper semantics */
        return _atomic64_xchg_add_unless(&v->counter, a, u) != u;
@@ -151,7 +152,7 @@ static inline u64 atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
  * atomic64_set() can't be just a raw store, since it would be lost if it
  * fell between the load and store of one of the other atomic ops.
  */
-static inline void atomic64_set(atomic64_t *v, u64 n)
+static inline void atomic64_set(atomic64_t *v, long long n)
 {
        _atomic64_xchg(&v->counter, n);
 }
@@ -236,11 +237,13 @@ extern struct __get_user __atomic_xchg_add_unless(volatile int *p,
 extern struct __get_user __atomic_or(volatile int *p, int *lock, int n);
 extern struct __get_user __atomic_andn(volatile int *p, int *lock, int n);
 extern struct __get_user __atomic_xor(volatile int *p, int *lock, int n);
-extern u64 __atomic64_cmpxchg(volatile u64 *p, int *lock, u64 o, u64 n);
-extern u64 __atomic64_xchg(volatile u64 *p, int *lock, u64 n);
-extern u64 __atomic64_xchg_add(volatile u64 *p, int *lock, u64 n);
-extern u64 __atomic64_xchg_add_unless(volatile u64 *p,
-                                     int *lock, u64 o, u64 n);
+extern long long __atomic64_cmpxchg(volatile long long *p, int *lock,
+                                       long long o, long long n);
+extern long long __atomic64_xchg(volatile long long *p, int *lock, long long n);
+extern long long __atomic64_xchg_add(volatile long long *p, int *lock,
+                                       long long n);
+extern long long __atomic64_xchg_add_unless(volatile long long *p,
+                                       int *lock, long long o, long long n);
 
 /* Return failure from the atomic wrappers. */
 struct __get_user __atomic_bad_address(int __user *addr);
index 4001d5e..0ccda3c 100644 (file)
@@ -35,10 +35,10 @@ int _atomic_xchg(int *ptr, int n);
 int _atomic_xchg_add(int *v, int i);
 int _atomic_xchg_add_unless(int *v, int a, int u);
 int _atomic_cmpxchg(int *ptr, int o, int n);
-u64 _atomic64_xchg(u64 *v, u64 n);
-u64 _atomic64_xchg_add(u64 *v, u64 i);
-u64 _atomic64_xchg_add_unless(u64 *v, u64 a, u64 u);
-u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
+long long _atomic64_xchg(long long *v, long long n);
+long long _atomic64_xchg_add(long long *v, long long i);
+long long _atomic64_xchg_add_unless(long long *v, long long a, long long u);
+long long _atomic64_cmpxchg(long long *v, long long o, long long n);
 
 #define xchg(ptr, n)                                                   \
        ({                                                              \
@@ -53,7 +53,8 @@ u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
                if (sizeof(*(ptr)) != 4)                                \
                        __cmpxchg_called_with_bad_pointer();            \
                smp_mb();                                               \
-               (typeof(*(ptr)))_atomic_cmpxchg((int *)ptr, (int)o, (int)n); \
+               (typeof(*(ptr)))_atomic_cmpxchg((int *)ptr, (int)o,     \
+                                               (int)n);                \
        })
 
 #define xchg64(ptr, n)                                                 \
@@ -61,7 +62,8 @@ u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
                if (sizeof(*(ptr)) != 8)                                \
                        __xchg_called_with_bad_pointer();               \
                smp_mb();                                               \
-               (typeof(*(ptr)))_atomic64_xchg((u64 *)(ptr), (u64)(n)); \
+               (typeof(*(ptr)))_atomic64_xchg((long long *)(ptr),      \
+                                               (long long)(n));        \
        })
 
 #define cmpxchg64(ptr, o, n)                                           \
@@ -69,7 +71,8 @@ u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
                if (sizeof(*(ptr)) != 8)                                \
                        __cmpxchg_called_with_bad_pointer();            \
                smp_mb();                                               \
-               (typeof(*(ptr)))_atomic64_cmpxchg((u64 *)ptr, (u64)o, (u64)n); \
+               (typeof(*(ptr)))_atomic64_cmpxchg((long long *)ptr,     \
+                                       (long long)o, (long long)n);    \
        })
 
 #else
@@ -81,10 +84,11 @@ u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
                switch (sizeof(*(ptr))) {                               \
                case 4:                                                 \
                        __x = (typeof(__x))(unsigned long)              \
-                               __insn_exch4((ptr), (u32)(unsigned long)(n)); \
+                               __insn_exch4((ptr),                     \
+                                       (u32)(unsigned long)(n));       \
                        break;                                          \
                case 8:                                                 \
-                       __x = (typeof(__x))                     \
+                       __x = (typeof(__x))                             \
                                __insn_exch((ptr), (unsigned long)(n)); \
                        break;                                          \
                default:                                                \
@@ -103,10 +107,12 @@ u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
                switch (sizeof(*(ptr))) {                               \
                case 4:                                                 \
                        __x = (typeof(__x))(unsigned long)              \
-                               __insn_cmpexch4((ptr), (u32)(unsigned long)(n)); \
+                               __insn_cmpexch4((ptr),                  \
+                                       (u32)(unsigned long)(n));       \
                        break;                                          \
                case 8:                                                 \
-                       __x = (typeof(__x))__insn_cmpexch((ptr), (u64)(n)); \
+                       __x = (typeof(__x))__insn_cmpexch((ptr),        \
+                                               (long long)(n));        \
                        break;                                          \
                default:                                                \
                        __cmpxchg_called_with_bad_pointer();            \
index 63294f5..4f7ae39 100644 (file)
 #ifndef _ASM_TILE_PERCPU_H
 #define _ASM_TILE_PERCPU_H
 
-register unsigned long __my_cpu_offset __asm__("tp");
-#define __my_cpu_offset __my_cpu_offset
-#define set_my_cpu_offset(tp) (__my_cpu_offset = (tp))
+register unsigned long my_cpu_offset_reg asm("tp");
+
+#ifdef CONFIG_PREEMPT
+/*
+ * For full preemption, we can't just use the register variable
+ * directly, since we need barrier() to hazard against it, causing the
+ * compiler to reload anything computed from a previous "tp" value.
+ * But we also don't want to use volatile asm, since we'd like the
+ * compiler to be able to cache the value across multiple percpu reads.
+ * So we use a fake stack read as a hazard against barrier().
+ * The 'U' constraint is like 'm' but disallows postincrement.
+ */
+static inline unsigned long __my_cpu_offset(void)
+{
+       unsigned long tp;
+       register unsigned long *sp asm("sp");
+       asm("move %0, tp" : "=r" (tp) : "U" (*sp));
+       return tp;
+}
+#define __my_cpu_offset __my_cpu_offset()
+#else
+/*
+ * We don't need to hazard against barrier() since "tp" doesn't ever
+ * change with PREEMPT_NONE, and with PREEMPT_VOLUNTARY it only
+ * changes at function call points, at which we are already re-reading
+ * the value of "tp" due to "my_cpu_offset_reg" being a global variable.
+ */
+#define __my_cpu_offset my_cpu_offset_reg
+#endif
+
+#define set_my_cpu_offset(tp) (my_cpu_offset_reg = (tp))
 
 #include <asm-generic/percpu.h>
 
index df27a1f..531f4c3 100644 (file)
@@ -66,7 +66,7 @@ static struct hardwall_type hardwall_types[] = {
                0,
                "udn",
                LIST_HEAD_INIT(hardwall_types[HARDWALL_UDN].list),
-               __SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_UDN].lock),
+               __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_UDN].lock),
                NULL
        },
 #ifndef __tilepro__
@@ -77,7 +77,7 @@ static struct hardwall_type hardwall_types[] = {
                1,  /* disabled pending hypervisor support */
                "idn",
                LIST_HEAD_INIT(hardwall_types[HARDWALL_IDN].list),
-               __SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_IDN].lock),
+               __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_IDN].lock),
                NULL
        },
        {  /* access to user-space IPI */
@@ -87,7 +87,7 @@ static struct hardwall_type hardwall_types[] = {
                0,
                "ipi",
                LIST_HEAD_INIT(hardwall_types[HARDWALL_IPI].list),
-               __SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_IPI].lock),
+               __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_IPI].lock),
                NULL
        },
 #endif
index 088d5c1..2cbe6d5 100644 (file)
@@ -815,6 +815,9 @@ STD_ENTRY(interrupt_return)
        }
        bzt     r28, 1f
        bnz     r29, 1f
+       /* Disable interrupts explicitly for preemption. */
+       IRQ_DISABLE(r20,r21)
+       TRACE_IRQS_OFF
        jal     preempt_schedule_irq
        FEEDBACK_REENTER(interrupt_return)
 1:
index ec755d3..b8fc497 100644 (file)
@@ -841,6 +841,9 @@ STD_ENTRY(interrupt_return)
        }
        beqzt   r28, 1f
        bnez    r29, 1f
+       /* Disable interrupts explicitly for preemption. */
+       IRQ_DISABLE(r20,r21)
+       TRACE_IRQS_OFF
        jal     preempt_schedule_irq
        FEEDBACK_REENTER(interrupt_return)
 1:
index 362284a..c93977a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mmzone.h>
 #include <linux/dcache.h>
 #include <linux/fs.h>
+#include <linux/string.h>
 #include <asm/backtrace.h>
 #include <asm/page.h>
 #include <asm/ucontext.h>
@@ -332,21 +333,18 @@ static void describe_addr(struct KBacktraceIterator *kbt,
        }
 
        if (vma->vm_file) {
-               char *s;
                p = d_path(&vma->vm_file->f_path, buf, bufsize);
                if (IS_ERR(p))
                        p = "?";
-               s = strrchr(p, '/');
-               if (s)
-                       p = s+1;
+               name = kbasename(p);
        } else {
-               p = "anon";
+               name = "anon";
        }
 
        /* Generate a string description of the vma info. */
-       namelen = strlen(p);
+       namelen = strlen(name);
        remaining = (bufsize - 1) - namelen;
-       memmove(buf, p, namelen);
+       memmove(buf, name, namelen);
        snprintf(buf + namelen, remaining, "[%lx+%lx] ",
                 vma->vm_start, vma->vm_end - vma->vm_start);
 }
index 759efa3..c89b211 100644 (file)
@@ -107,19 +107,19 @@ unsigned long _atomic_xor(volatile unsigned long *p, unsigned long mask)
 EXPORT_SYMBOL(_atomic_xor);
 
 
-u64 _atomic64_xchg(u64 *v, u64 n)
+long long _atomic64_xchg(long long *v, long long n)
 {
        return __atomic64_xchg(v, __atomic_setup(v), n);
 }
 EXPORT_SYMBOL(_atomic64_xchg);
 
-u64 _atomic64_xchg_add(u64 *v, u64 i)
+long long _atomic64_xchg_add(long long *v, long long i)
 {
        return __atomic64_xchg_add(v, __atomic_setup(v), i);
 }
 EXPORT_SYMBOL(_atomic64_xchg_add);
 
-u64 _atomic64_xchg_add_unless(u64 *v, u64 a, u64 u)
+long long _atomic64_xchg_add_unless(long long *v, long long a, long long u)
 {
        /*
         * Note: argument order is switched here since it is easier
@@ -130,7 +130,7 @@ u64 _atomic64_xchg_add_unless(u64 *v, u64 a, u64 u)
 }
 EXPORT_SYMBOL(_atomic64_xchg_add_unless);
 
-u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n)
+long long _atomic64_cmpxchg(long long *v, long long o, long long n)
 {
        return __atomic64_cmpxchg(v, __atomic_setup(v), o, n);
 }
index 829df49..41ebbfe 100644 (file)
@@ -40,9 +40,11 @@ static ssize_t exitcode_proc_write(struct file *file,
                const char __user *buffer, size_t count, loff_t *pos)
 {
        char *end, buf[sizeof("nnnnn\0")];
+       size_t size;
        int tmp;
 
-       if (copy_from_user(buf, buffer, count))
+       size = min(count, sizeof(buf));
+       if (copy_from_user(buf, buffer, size))
                return -EFAULT;
 
        tmp = simple_strtol(buf, &end, 0);
index ee2fb9d..f67e839 100644 (file)
@@ -860,7 +860,7 @@ source "kernel/Kconfig.preempt"
 
 config X86_UP_APIC
        bool "Local APIC support on uniprocessors"
-       depends on X86_32 && !SMP && !X86_32_NON_STANDARD
+       depends on X86_32 && !SMP && !X86_32_NON_STANDARD && !PCI_MSI
        ---help---
          A local APIC (Advanced Programmable Interrupt Controller) is an
          integrated interrupt controller in the CPU. If you have a single-CPU
@@ -885,11 +885,11 @@ config X86_UP_IOAPIC
 
 config X86_LOCAL_APIC
        def_bool y
-       depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC
+       depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
 
 config X86_IO_APIC
        def_bool y
-       depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC
+       depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC || PCI_MSI
 
 config X86_VISWS_APIC
        def_bool y
@@ -1033,6 +1033,7 @@ config X86_REBOOTFIXUPS
 
 config MICROCODE
        tristate "CPU microcode loading support"
+       depends on CPU_SUP_AMD || CPU_SUP_INTEL
        select FW_LOADER
        ---help---
 
index d3f5c63..89270b4 100644 (file)
@@ -374,7 +374,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
                 * Catch too early usage of this before alternatives
                 * have run.
                 */
-               asm goto("1: jmp %l[t_warn]\n"
+               asm_volatile_goto("1: jmp %l[t_warn]\n"
                         "2:\n"
                         ".section .altinstructions,\"a\"\n"
                         " .long 1b - .\n"
@@ -388,7 +388,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
 
 #endif
 
-               asm goto("1: jmp %l[t_no]\n"
+               asm_volatile_goto("1: jmp %l[t_no]\n"
                         "2:\n"
                         ".section .altinstructions,\"a\"\n"
                         " .long 1b - .\n"
@@ -453,7 +453,7 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
  * have. Thus, we force the jump to the widest, 4-byte, signed relative
  * offset even though the last would often fit in less bytes.
  */
-               asm goto("1: .byte 0xe9\n .long %l[t_dynamic] - 2f\n"
+               asm_volatile_goto("1: .byte 0xe9\n .long %l[t_dynamic] - 2f\n"
                         "2:\n"
                         ".section .altinstructions,\"a\"\n"
                         " .long 1b - .\n"              /* src offset */
index 64507f3..6a2cefb 100644 (file)
@@ -18,7 +18,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm goto("1:"
+       asm_volatile_goto("1:"
                ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t"
                ".pushsection __jump_table,  \"aw\" \n\t"
                _ASM_ALIGN "\n\t"
index e7e6751..07537a4 100644 (file)
@@ -20,7 +20,7 @@
 static inline void __mutex_fastpath_lock(atomic_t *v,
                                         void (*fail_fn)(atomic_t *))
 {
-       asm volatile goto(LOCK_PREFIX "   decl %0\n"
+       asm_volatile_goto(LOCK_PREFIX "   decl %0\n"
                          "   jns %l[exit]\n"
                          : : "m" (v->counter)
                          : "memory", "cc"
@@ -75,7 +75,7 @@ static inline int __mutex_fastpath_lock_retval(atomic_t *count)
 static inline void __mutex_fastpath_unlock(atomic_t *v,
                                           void (*fail_fn)(atomic_t *))
 {
-       asm volatile goto(LOCK_PREFIX "   incl %0\n"
+       asm_volatile_goto(LOCK_PREFIX "   incl %0\n"
                          "   jg %l[exit]\n"
                          : : "m" (v->counter)
                          : "memory", "cc"
index 0da5200..b3e18f8 100644 (file)
@@ -128,7 +128,8 @@ do {                                                        \
 do {                                                                   \
        typedef typeof(var) pao_T__;                                    \
        const int pao_ID__ = (__builtin_constant_p(val) &&              \
-                             ((val) == 1 || (val) == -1)) ? (val) : 0; \
+                             ((val) == 1 || (val) == -1)) ?            \
+                               (int)(val) : 0;                         \
        if (0) {                                                        \
                pao_T__ pao_tmp__;                                      \
                pao_tmp__ = (val);                                      \
index 1191ac1..a419814 100644 (file)
@@ -113,7 +113,7 @@ static int __init early_get_pnodeid(void)
                break;
        case UV3_HUB_PART_NUMBER:
        case UV3_HUB_PART_NUMBER_X:
-               uv_min_hub_revision_id += UV3_HUB_REVISION_BASE - 1;
+               uv_min_hub_revision_id += UV3_HUB_REVISION_BASE;
                break;
        }
 
index 897783b..8a87a32 100644 (file)
@@ -1276,16 +1276,16 @@ void perf_events_lapic_init(void)
 static int __kprobes
 perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs)
 {
-       int ret;
        u64 start_clock;
        u64 finish_clock;
+       int ret;
 
        if (!atomic_read(&active_events))
                return NMI_DONE;
 
-       start_clock = local_clock();
+       start_clock = sched_clock();
        ret = x86_pmu.handle_irq(regs);
-       finish_clock = local_clock();
+       finish_clock = sched_clock();
 
        perf_sample_event_took(finish_clock - start_clock);
 
@@ -1888,10 +1888,7 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
        userpg->cap_user_rdpmc = x86_pmu.attr_rdpmc;
        userpg->pmc_width = x86_pmu.cntval_bits;
 
-       if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
-               return;
-
-       if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+       if (!sched_clock_stable)
                return;
 
        userpg->cap_user_time = 1;
@@ -1899,10 +1896,8 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
        userpg->time_shift = CYC2NS_SCALE_FACTOR;
        userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;
 
-       if (sched_clock_stable && !check_tsc_disabled()) {
-               userpg->cap_user_time_zero = 1;
-               userpg->time_zero = this_cpu_read(cyc2ns_offset);
-       }
+       userpg->cap_user_time_zero = 1;
+       userpg->time_zero = this_cpu_read(cyc2ns_offset);
 }
 
 /*
index b3cd3eb..96f958d 100644 (file)
@@ -313,6 +313,16 @@ static size_t __init gen6_stolen_size(int num, int slot, int func)
        return gmch_ctrl << 25; /* 32 MB units */
 }
 
+static inline size_t gen8_stolen_size(int num, int slot, int func)
+{
+       u16 gmch_ctrl;
+
+       gmch_ctrl = read_pci_config_16(num, slot, func, SNB_GMCH_CTRL);
+       gmch_ctrl >>= BDW_GMCH_GMS_SHIFT;
+       gmch_ctrl &= BDW_GMCH_GMS_MASK;
+       return gmch_ctrl << 25; /* 32 MB units */
+}
+
 typedef size_t (*stolen_size_fn)(int num, int slot, int func);
 
 static struct pci_device_id intel_stolen_ids[] __initdata = {
@@ -336,6 +346,8 @@ static struct pci_device_id intel_stolen_ids[] __initdata = {
        INTEL_IVB_D_IDS(gen6_stolen_size),
        INTEL_HSW_D_IDS(gen6_stolen_size),
        INTEL_HSW_M_IDS(gen6_stolen_size),
+       INTEL_BDW_M_IDS(gen8_stolen_size),
+       INTEL_BDW_D_IDS(gen8_stolen_size)
 };
 
 static void __init intel_graphics_stolen(int num, int slot, int func)
index 697b93a..b2046e4 100644 (file)
@@ -609,7 +609,7 @@ static struct dentry *d_kvm_debug;
 
 struct dentry *kvm_init_debugfs(void)
 {
-       d_kvm_debug = debugfs_create_dir("kvm", NULL);
+       d_kvm_debug = debugfs_create_dir("kvm-guest", NULL);
        if (!d_kvm_debug)
                printk(KERN_WARNING "Could not create 'kvm' debugfs directory\n");
 
@@ -775,11 +775,22 @@ void __init kvm_spinlock_init(void)
        if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT))
                return;
 
-       printk(KERN_INFO "KVM setup paravirtual spinlock\n");
+       pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(kvm_lock_spinning);
+       pv_lock_ops.unlock_kick = kvm_unlock_kick;
+}
+
+static __init int kvm_spinlock_init_jump(void)
+{
+       if (!kvm_para_available())
+               return 0;
+       if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT))
+               return 0;
 
        static_key_slow_inc(&paravirt_ticketlocks_enabled);
+       printk(KERN_INFO "KVM setup paravirtual spinlock\n");
 
-       pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(kvm_lock_spinning);
-       pv_lock_ops.unlock_kick = kvm_unlock_kick;
+       return 0;
 }
+early_initcall(kvm_spinlock_init_jump);
+
 #endif /* CONFIG_PARAVIRT_SPINLOCKS */
index ba77ebc..6fcb49c 100644 (file)
@@ -113,10 +113,10 @@ static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2
                u64 before, delta, whole_msecs;
                int remainder_ns, decimal_msecs, thishandled;
 
-               before = local_clock();
+               before = sched_clock();
                thishandled = a->handler(type, regs);
                handled += thishandled;
-               delta = local_clock() - before;
+               delta = sched_clock() - before;
                trace_nmi_handler(a->handler, (int)delta, thishandled);
 
                if (delta < nmi_longest_ns)
index e643e74..7e920bf 100644 (file)
@@ -326,6 +326,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"),
                },
        },
+       {       /* Handle problems with rebooting on the Latitude E5410. */
+               .callback = set_pci_reboot,
+               .ident = "Dell Latitude E5410",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5410"),
+               },
+       },
        {       /* Handle problems with rebooting on the Latitude E5420. */
                .callback = set_pci_reboot,
                .ident = "Dell Latitude E5420",
index 22513e9..86179d4 100644 (file)
@@ -72,14 +72,14 @@ __init int create_simplefb(const struct screen_info *si,
         * the part that is occupied by the framebuffer */
        len = mode->height * mode->stride;
        len = PAGE_ALIGN(len);
-       if (len > si->lfb_size << 16) {
+       if (len > (u64)si->lfb_size << 16) {
                printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
                return -EINVAL;
        }
 
        /* setup IORESOURCE_MEM as framebuffer memory */
        memset(&res, 0, sizeof(res));
-       res.flags = IORESOURCE_MEM;
+       res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
        res.name = simplefb_resname;
        res.start = si->lfb_base;
        res.end = si->lfb_base + len - 1;
index a1216de..2b2fce1 100644 (file)
@@ -3255,25 +3255,29 @@ static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
 
 static void ept_load_pdptrs(struct kvm_vcpu *vcpu)
 {
+       struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
+
        if (!test_bit(VCPU_EXREG_PDPTR,
                      (unsigned long *)&vcpu->arch.regs_dirty))
                return;
 
        if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
-               vmcs_write64(GUEST_PDPTR0, vcpu->arch.mmu.pdptrs[0]);
-               vmcs_write64(GUEST_PDPTR1, vcpu->arch.mmu.pdptrs[1]);
-               vmcs_write64(GUEST_PDPTR2, vcpu->arch.mmu.pdptrs[2]);
-               vmcs_write64(GUEST_PDPTR3, vcpu->arch.mmu.pdptrs[3]);
+               vmcs_write64(GUEST_PDPTR0, mmu->pdptrs[0]);
+               vmcs_write64(GUEST_PDPTR1, mmu->pdptrs[1]);
+               vmcs_write64(GUEST_PDPTR2, mmu->pdptrs[2]);
+               vmcs_write64(GUEST_PDPTR3, mmu->pdptrs[3]);
        }
 }
 
 static void ept_save_pdptrs(struct kvm_vcpu *vcpu)
 {
+       struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
+
        if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
-               vcpu->arch.mmu.pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
-               vcpu->arch.mmu.pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
-               vcpu->arch.mmu.pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
-               vcpu->arch.mmu.pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
+               mmu->pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
+               mmu->pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
+               mmu->pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
+               mmu->pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
        }
 
        __set_bit(VCPU_EXREG_PDPTR,
@@ -5345,7 +5349,9 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu)
         * There are errata that may cause this bit to not be set:
         * AAK134, BY25.
         */
-       if (exit_qualification & INTR_INFO_UNBLOCK_NMI)
+       if (!(to_vmx(vcpu)->idt_vectoring_info & VECTORING_INFO_VALID_MASK) &&
+                       cpu_has_virtual_nmis() &&
+                       (exit_qualification & INTR_INFO_UNBLOCK_NMI))
                vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, GUEST_INTR_STATE_NMI);
 
        gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
@@ -7775,10 +7781,6 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
                vmcs_write64(GUEST_PDPTR1, vmcs12->guest_pdptr1);
                vmcs_write64(GUEST_PDPTR2, vmcs12->guest_pdptr2);
                vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3);
-               __clear_bit(VCPU_EXREG_PDPTR,
-                               (unsigned long *)&vcpu->arch.regs_avail);
-               __clear_bit(VCPU_EXREG_PDPTR,
-                               (unsigned long *)&vcpu->arch.regs_dirty);
        }
 
        kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->guest_rsp);
index 79c216a..516593e 100644 (file)
@@ -772,13 +772,21 @@ out:
        return;
 }
 
+static void bpf_jit_free_deferred(struct work_struct *work)
+{
+       struct sk_filter *fp = container_of(work, struct sk_filter, work);
+       unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
+       struct bpf_binary_header *header = (void *)addr;
+
+       set_memory_rw(addr, header->pages);
+       module_free(NULL, header);
+       kfree(fp);
+}
+
 void bpf_jit_free(struct sk_filter *fp)
 {
        if (fp->bpf_func != sk_run_filter) {
-               unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
-               struct bpf_binary_header *header = (void *)addr;
-
-               set_memory_rw(addr, header->pages);
-               module_free(NULL, header);
+               INIT_WORK(&fp->work, bpf_jit_free_deferred);
+               schedule_work(&fp->work);
        }
 }
index 5596c7b..082e881 100644 (file)
@@ -700,7 +700,7 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
        if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
                return -ENODEV;
 
-       if (start > end || !addr)
+       if (start > end)
                return -EINVAL;
 
        mutex_lock(&pci_mmcfg_lock);
@@ -716,6 +716,11 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
                return -EEXIST;
        }
 
+       if (!addr) {
+               mutex_unlock(&pci_mmcfg_lock);
+               return -EINVAL;
+       }
+
        rc = -EBUSY;
        cfg = pci_mmconfig_alloc(seg, start, end, addr);
        if (cfg == NULL) {
index d1e4777..31d0475 100644 (file)
@@ -278,6 +278,15 @@ static void __init xen_smp_prepare_boot_cpu(void)
                   old memory can be recycled */
                make_lowmem_page_readwrite(xen_initial_gdt);
 
+#ifdef CONFIG_X86_32
+               /*
+                * Xen starts us with XEN_FLAT_RING1_DS, but linux code
+                * expects __USER_DS
+                */
+               loadsegment(ds, __USER_DS);
+               loadsegment(es, __USER_DS);
+#endif
+
                xen_filter_cpu_maps();
                xen_setup_vcpu_info_placement();
        }
index de1dfa1..21dbe6b 100644 (file)
@@ -1122,7 +1122,7 @@ ENDPROC(fast_syscall_spill_registers)
  * a3: exctable, original value in excsave1
  */
 
-fast_syscall_spill_registers_fixup:
+ENTRY(fast_syscall_spill_registers_fixup)
 
        rsr     a2, windowbase  # get current windowbase (a2 is saved)
        xsr     a0, depc        # restore depc and a0
@@ -1134,22 +1134,26 @@ fast_syscall_spill_registers_fixup:
         */
 
        xsr     a3, excsave1    # get spill-mask
-       slli    a2, a3, 1       # shift left by one
+       slli    a3, a3, 1       # shift left by one
 
-       slli    a3, a2, 32-WSBITS
-       src     a2, a2, a3      # a1 = xxwww1yyxxxwww1yy......
+       slli    a2, a3, 32-WSBITS
+       src     a2, a3, a2      # a2 = xxwww1yyxxxwww1yy......
        wsr     a2, windowstart # set corrected windowstart
 
-       rsr     a3, excsave1
-       l32i    a2, a3, EXC_TABLE_DOUBLE_SAVE   # restore a2
-       l32i    a3, a3, EXC_TABLE_PARAM # original WB (in user task)
+       srli    a3, a3, 1
+       rsr     a2, excsave1
+       l32i    a2, a2, EXC_TABLE_DOUBLE_SAVE   # restore a2
+       xsr     a2, excsave1
+       s32i    a3, a2, EXC_TABLE_DOUBLE_SAVE   # save a3
+       l32i    a3, a2, EXC_TABLE_PARAM # original WB (in user task)
+       xsr     a2, excsave1
 
        /* Return to the original (user task) WINDOWBASE.
         * We leave the following frame behind:
         * a0, a1, a2   same
-        * a3:          trashed (saved in excsave_1)
+        * a3:          trashed (saved in EXC_TABLE_DOUBLE_SAVE)
         * depc:        depc (we have to return to that address)
-        * excsave_1:   a3
+        * excsave_1:   exctable
         */
 
        wsr     a3, windowbase
@@ -1159,9 +1163,9 @@ fast_syscall_spill_registers_fixup:
         *  a0: return address
         *  a1: used, stack pointer
         *  a2: kernel stack pointer
-        *  a3: available, saved in EXCSAVE_1
+        *  a3: available
         *  depc: exception address
-        *  excsave: a3
+        *  excsave: exctable
         * Note: This frame might be the same as above.
         */
 
@@ -1181,9 +1185,12 @@ fast_syscall_spill_registers_fixup:
        rsr     a0, exccause
        addx4   a0, a0, a3                      # find entry in table
        l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
+       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
        jx      a0
 
-fast_syscall_spill_registers_fixup_return:
+ENDPROC(fast_syscall_spill_registers_fixup)
+
+ENTRY(fast_syscall_spill_registers_fixup_return)
 
        /* When we return here, all registers have been restored (a2: DEPC) */
 
@@ -1191,13 +1198,13 @@ fast_syscall_spill_registers_fixup_return:
 
        /* Restore fixup handler. */
 
-       xsr     a3, excsave1
-       movi    a2, fast_syscall_spill_registers_fixup
-       s32i    a2, a3, EXC_TABLE_FIXUP
-       s32i    a0, a3, EXC_TABLE_DOUBLE_SAVE
-       rsr     a2, windowbase
-       s32i    a2, a3, EXC_TABLE_PARAM
-       l32i    a2, a3, EXC_TABLE_KSTK
+       rsr     a2, excsave1
+       s32i    a3, a2, EXC_TABLE_DOUBLE_SAVE
+       movi    a3, fast_syscall_spill_registers_fixup
+       s32i    a3, a2, EXC_TABLE_FIXUP
+       rsr     a3, windowbase
+       s32i    a3, a2, EXC_TABLE_PARAM
+       l32i    a2, a2, EXC_TABLE_KSTK
 
        /* Load WB at the time the exception occurred. */
 
@@ -1206,8 +1213,12 @@ fast_syscall_spill_registers_fixup_return:
        wsr     a3, windowbase
        rsync
 
+       rsr     a3, excsave1
+       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
+
        rfde
 
+ENDPROC(fast_syscall_spill_registers_fixup_return)
 
 /*
  * spill all registers.
index 718eca1..98b67d5 100644 (file)
@@ -341,7 +341,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 
        sp = regs->areg[1];
 
-       if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) {
+       if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && sas_ss_flags(sp) == 0) {
                sp = current->sas_ss_sp + current->sas_ss_size;
        }
 
index 56f88b7..e9e1aad 100644 (file)
@@ -737,7 +737,8 @@ static int __init iss_net_setup(char *str)
                return 1;
        }
 
-       if ((new = alloc_bootmem(sizeof new)) == NULL) {
+       new = alloc_bootmem(sizeof(*new));
+       if (new == NULL) {
                printk("Alloc_bootmem failed\n");
                return 1;
        }
index 7f38e40..2429515 100644 (file)
@@ -99,11 +99,16 @@ config BLK_DEV_THROTTLING
 
        See Documentation/cgroups/blkio-controller.txt for more information.
 
-config CMDLINE_PARSER
+config BLK_CMDLINE_PARSER
        bool "Block device command line partition parser"
        default n
        ---help---
-       Parsing command line, get the partitions information.
+       Enabling this option allows you to specify the partition layout from
+       the kernel boot args.  This is typically of use for embedded devices
+       which don't otherwise have any standardized method for listing the
+       partitions on a block device.
+
+       See Documentation/block/cmdline-partition.txt for more information.
 
 menu "Partition Types"
 
index 4fa4be5..671a83d 100644 (file)
@@ -18,4 +18,4 @@ obj-$(CONFIG_IOSCHED_CFQ)     += cfq-iosched.o
 
 obj-$(CONFIG_BLOCK_COMPAT)     += compat_ioctl.o
 obj-$(CONFIG_BLK_DEV_INTEGRITY)        += blk-integrity.o
-obj-$(CONFIG_CMDLINE_PARSER)   += cmdline-parser.o
+obj-$(CONFIG_BLK_CMDLINE_PARSER)       += cmdline-parser.o
index 87a3208..9b29a99 100644 (file)
@@ -263,7 +263,7 @@ config SYSV68_PARTITION
 
 config CMDLINE_PARTITION
        bool "Command line partition support" if PARTITION_ADVANCED
-       select CMDLINE_PARSER
+       select BLK_CMDLINE_PARSER
        help
-         Say Y here if you would read the partitions table from bootargs.
+         Say Y here if you want to read the partition table from bootargs.
          The format for the command line is just like mtdparts.
index 56cf4ff..5141b56 100644 (file)
@@ -2,15 +2,15 @@
  * Copyright (C) 2013 HUAWEI
  * Author: Cai Zhiyong <caizhiyong@huawei.com>
  *
- * Read block device partition table from command line.
- * The partition used for fixed block device (eMMC) embedded device.
- * It is no MBR, save storage space. Bootloader can be easily accessed
+ * Read block device partition table from the command line.
+ * Typically used for fixed block (eMMC) embedded devices.
+ * It has no MBR, so saves storage space. Bootloader can be easily accessed
  * by absolute address of data on the block device.
  * Users can easily change the partition.
  *
  * The format for the command line is just like mtdparts.
  *
- * Verbose config please reference "Documentation/block/cmdline-partition.txt"
+ * For further information, see "Documentation/block/cmdline-partition.txt"
  *
  */
 
index 1eb09ee..a8287b4 100644 (file)
@@ -222,11 +222,16 @@ check_hybrid:
         * the disk size.
         *
         * Hybrid MBRs do not necessarily comply with this.
+        *
+        * Consider a bad value here to be a warning to support dd'ing
+        * an image from a smaller disk to a larger disk.
         */
        if (ret == GPT_MBR_PROTECTIVE) {
                sz = le32_to_cpu(mbr->partition_record[part].size_in_lba);
                if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF)
-                       ret = 0;
+                       pr_debug("GPT: mbr size in lba (%u) different than whole disk (%u).\n",
+                                sz, min_t(uint32_t,
+                                          total_sectors - 1, 0xFFFFFFFF));
        }
 done:
        return ret;
index 22327e6..6efe2ac 100644 (file)
@@ -24,7 +24,7 @@ menuconfig ACPI
          are configured, ACPI is used.
 
          The project home page for the Linux ACPI subsystem is here:
-         <http://www.lesswatts.org/projects/acpi/>
+         <https://01.org/linux-acpi>
 
          Linux support for ACPI is based on Intel Corporation's ACPI
          Component Architecture (ACPI CA).  For more information on the
@@ -123,9 +123,9 @@ config ACPI_BUTTON
        default y
        help
          This driver handles events on the power, sleep, and lid buttons.
-         A daemon reads /proc/acpi/event and perform user-defined actions
-         such as shutting down the system.  This is necessary for
-         software-controlled poweroff.
+         A daemon reads events from input devices or via netlink and
+         performs user-defined actions such as shutting down the system.
+         This is necessary for software-controlled poweroff.
 
          To compile this driver as a module, choose M here:
          the module will be called button.
index 59d3202..a94383d 100644 (file)
@@ -1025,60 +1025,4 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off)
        }
 }
 EXPORT_SYMBOL_GPL(acpi_dev_pm_detach);
-
-/**
- * acpi_dev_pm_add_dependent - Add physical device depending for PM.
- * @handle: Handle of ACPI device node.
- * @depdev: Device depending on that node for PM.
- */
-void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev)
-{
-       struct acpi_device_physical_node *dep;
-       struct acpi_device *adev;
-
-       if (!depdev || acpi_bus_get_device(handle, &adev))
-               return;
-
-       mutex_lock(&adev->physical_node_lock);
-
-       list_for_each_entry(dep, &adev->power_dependent, node)
-               if (dep->dev == depdev)
-                       goto out;
-
-       dep = kzalloc(sizeof(*dep), GFP_KERNEL);
-       if (dep) {
-               dep->dev = depdev;
-               list_add_tail(&dep->node, &adev->power_dependent);
-       }
-
- out:
-       mutex_unlock(&adev->physical_node_lock);
-}
-EXPORT_SYMBOL_GPL(acpi_dev_pm_add_dependent);
-
-/**
- * acpi_dev_pm_remove_dependent - Remove physical device depending for PM.
- * @handle: Handle of ACPI device node.
- * @depdev: Device depending on that node for PM.
- */
-void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev)
-{
-       struct acpi_device_physical_node *dep;
-       struct acpi_device *adev;
-
-       if (!depdev || acpi_bus_get_device(handle, &adev))
-               return;
-
-       mutex_lock(&adev->physical_node_lock);
-
-       list_for_each_entry(dep, &adev->power_dependent, node)
-               if (dep->dev == depdev) {
-                       list_del(&dep->node);
-                       kfree(dep);
-                       break;
-               }
-
-       mutex_unlock(&adev->physical_node_lock);
-}
-EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent);
 #endif /* CONFIG_PM */
index 0dbe5cd..c2ad391 100644 (file)
@@ -59,16 +59,9 @@ ACPI_MODULE_NAME("power");
 #define ACPI_POWER_RESOURCE_STATE_ON   0x01
 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
 
-struct acpi_power_dependent_device {
-       struct list_head node;
-       struct acpi_device *adev;
-       struct work_struct work;
-};
-
 struct acpi_power_resource {
        struct acpi_device device;
        struct list_head list_node;
-       struct list_head dependent;
        char *name;
        u32 system_level;
        u32 order;
@@ -233,32 +226,6 @@ static int acpi_power_get_list_state(struct list_head *list, int *state)
        return 0;
 }
 
-static void acpi_power_resume_dependent(struct work_struct *work)
-{
-       struct acpi_power_dependent_device *dep;
-       struct acpi_device_physical_node *pn;
-       struct acpi_device *adev;
-       int state;
-
-       dep = container_of(work, struct acpi_power_dependent_device, work);
-       adev = dep->adev;
-       if (acpi_power_get_inferred_state(adev, &state))
-               return;
-
-       if (state > ACPI_STATE_D0)
-               return;
-
-       mutex_lock(&adev->physical_node_lock);
-
-       list_for_each_entry(pn, &adev->physical_node_list, node)
-               pm_request_resume(pn->dev);
-
-       list_for_each_entry(pn, &adev->power_dependent, node)
-               pm_request_resume(pn->dev);
-
-       mutex_unlock(&adev->physical_node_lock);
-}
-
 static int __acpi_power_on(struct acpi_power_resource *resource)
 {
        acpi_status status = AE_OK;
@@ -283,14 +250,8 @@ static int acpi_power_on_unlocked(struct acpi_power_resource *resource)
                                  resource->name));
        } else {
                result = __acpi_power_on(resource);
-               if (result) {
+               if (result)
                        resource->ref_count--;
-               } else {
-                       struct acpi_power_dependent_device *dep;
-
-                       list_for_each_entry(dep, &resource->dependent, node)
-                               schedule_work(&dep->work);
-               }
        }
        return result;
 }
@@ -390,52 +351,6 @@ static int acpi_power_on_list(struct list_head *list)
        return result;
 }
 
-static void acpi_power_add_dependent(struct acpi_power_resource *resource,
-                                    struct acpi_device *adev)
-{
-       struct acpi_power_dependent_device *dep;
-
-       mutex_lock(&resource->resource_lock);
-
-       list_for_each_entry(dep, &resource->dependent, node)
-               if (dep->adev == adev)
-                       goto out;
-
-       dep = kzalloc(sizeof(*dep), GFP_KERNEL);
-       if (!dep)
-               goto out;
-
-       dep->adev = adev;
-       INIT_WORK(&dep->work, acpi_power_resume_dependent);
-       list_add_tail(&dep->node, &resource->dependent);
-
- out:
-       mutex_unlock(&resource->resource_lock);
-}
-
-static void acpi_power_remove_dependent(struct acpi_power_resource *resource,
-                                       struct acpi_device *adev)
-{
-       struct acpi_power_dependent_device *dep;
-       struct work_struct *work = NULL;
-
-       mutex_lock(&resource->resource_lock);
-
-       list_for_each_entry(dep, &resource->dependent, node)
-               if (dep->adev == adev) {
-                       list_del(&dep->node);
-                       work = &dep->work;
-                       break;
-               }
-
-       mutex_unlock(&resource->resource_lock);
-
-       if (work) {
-               cancel_work_sync(work);
-               kfree(dep);
-       }
-}
-
 static struct attribute *attrs[] = {
        NULL,
 };
@@ -524,8 +439,6 @@ static void acpi_power_expose_hide(struct acpi_device *adev,
 
 void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
 {
-       struct acpi_device_power_state *ps;
-       struct acpi_power_resource_entry *entry;
        int state;
 
        if (adev->wakeup.flags.valid)
@@ -535,16 +448,6 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
        if (!adev->power.flags.power_resources)
                return;
 
-       ps = &adev->power.states[ACPI_STATE_D0];
-       list_for_each_entry(entry, &ps->resources, node) {
-               struct acpi_power_resource *resource = entry->resource;
-
-               if (add)
-                       acpi_power_add_dependent(resource, adev);
-               else
-                       acpi_power_remove_dependent(resource, adev);
-       }
-
        for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++)
                acpi_power_expose_hide(adev,
                                       &adev->power.states[state].resources,
@@ -882,7 +785,6 @@ int acpi_add_power_resource(acpi_handle handle)
        acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER,
                                ACPI_STA_DEFAULT);
        mutex_init(&resource->resource_lock);
-       INIT_LIST_HEAD(&resource->dependent);
        INIT_LIST_HEAD(&resource->list_node);
        resource->name = device->pnp.bus_id;
        strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
@@ -936,8 +838,10 @@ void acpi_resume_power_resources(void)
                mutex_lock(&resource->resource_lock);
 
                result = acpi_power_get_state(resource->device.handle, &state);
-               if (result)
+               if (result) {
+                       mutex_unlock(&resource->resource_lock);
                        continue;
+               }
 
                if (state == ACPI_POWER_RESOURCE_STATE_OFF
                    && resource->ref_count) {
index 611ce90..fee8a29 100644 (file)
@@ -968,7 +968,7 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(acpi_bus_get_device);
+EXPORT_SYMBOL(acpi_bus_get_device);
 
 int acpi_device_add(struct acpi_device *device,
                    void (*release)(struct device *))
@@ -999,7 +999,6 @@ int acpi_device_add(struct acpi_device *device,
        INIT_LIST_HEAD(&device->wakeup_list);
        INIT_LIST_HEAD(&device->physical_node_list);
        mutex_init(&device->physical_node_lock);
-       INIT_LIST_HEAD(&device->power_dependent);
 
        new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
        if (!new_bus_id) {
index 9d715ae..8e28f92 100644 (file)
@@ -1343,7 +1343,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
                host->flags |= ATA_HOST_PARALLEL_SCAN;
        else
-               printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
+               dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n");
 
        if (pi.flags & ATA_FLAG_EM)
                ahci_reset_em(host);
index 2daaee0..7d3b853 100644 (file)
@@ -184,7 +184,7 @@ static int ahci_probe(struct platform_device *pdev)
        if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
                host->flags |= ATA_HOST_PARALLEL_SCAN;
        else
-               printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
+               dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
 
        if (pi.flags & ATA_FLAG_EM)
                ahci_reset_em(host);
index acfd0f7..aaac4fb 100644 (file)
@@ -778,8 +778,16 @@ static void ahci_start_port(struct ata_port *ap)
                                rc = ap->ops->transmit_led_message(ap,
                                                               emp->led_state,
                                                               4);
+                               /*
+                                * If busy, give a breather but do not
+                                * release EH ownership by using msleep()
+                                * instead of ata_msleep().  EM Transmit
+                                * bit is busy for the whole host and
+                                * releasing ownership will cause other
+                                * ports to fail the same way.
+                                */
                                if (rc == -EBUSY)
-                                       ata_msleep(ap, 1);
+                                       msleep(1);
                                else
                                        break;
                        }
index 4ba8b04..ab714d2 100644 (file)
@@ -1035,17 +1035,3 @@ void ata_acpi_on_disable(struct ata_device *dev)
 {
        ata_acpi_clear_gtf(dev);
 }
-
-void ata_scsi_acpi_bind(struct ata_device *dev)
-{
-       acpi_handle handle = ata_dev_acpi_handle(dev);
-       if (handle)
-               acpi_dev_pm_add_dependent(handle, &dev->sdev->sdev_gendev);
-}
-
-void ata_scsi_acpi_unbind(struct ata_device *dev)
-{
-       acpi_handle handle = ata_dev_acpi_handle(dev);
-       if (handle)
-               acpi_dev_pm_remove_dependent(handle, &dev->sdev->sdev_gendev);
-}
index c69fcce..370462f 100644 (file)
@@ -1322,14 +1322,14 @@ void ata_eh_qc_complete(struct ata_queued_cmd *qc)
  *     should be retried.  To be used from EH.
  *
  *     SCSI midlayer limits the number of retries to scmd->allowed.
- *     scmd->retries is decremented for commands which get retried
+ *     scmd->allowed is incremented for commands which get retried
  *     due to unrelated failures (qc->err_mask is zero).
  */
 void ata_eh_qc_retry(struct ata_queued_cmd *qc)
 {
        struct scsi_cmnd *scmd = qc->scsicmd;
-       if (!qc->err_mask && scmd->retries)
-               scmd->retries--;
+       if (!qc->err_mask)
+               scmd->allowed++;
        __ata_eh_qc_complete(qc);
 }
 
index 97a0cef..db6dfcf 100644 (file)
@@ -3679,7 +3679,6 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
                        if (!IS_ERR(sdev)) {
                                dev->sdev = sdev;
                                scsi_device_put(sdev);
-                               ata_scsi_acpi_bind(dev);
                        } else {
                                dev->sdev = NULL;
                        }
@@ -3767,8 +3766,6 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
        struct scsi_device *sdev;
        unsigned long flags;
 
-       ata_scsi_acpi_unbind(dev);
-
        /* Alas, we need to grab scan_mutex to ensure SCSI device
         * state doesn't change underneath us and thus
         * scsi_device_get() always succeeds.  The mutex locking can
index eeeb778..45b5ab3 100644 (file)
@@ -121,8 +121,6 @@ extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);
 extern void ata_acpi_bind_port(struct ata_port *ap);
 extern void ata_acpi_bind_dev(struct ata_device *dev);
 extern acpi_handle ata_dev_acpi_handle(struct ata_device *dev);
-extern void ata_scsi_acpi_bind(struct ata_device *dev);
-extern void ata_scsi_acpi_unbind(struct ata_device *dev);
 #else
 static inline void ata_acpi_dissociate(struct ata_host *host) { }
 static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
@@ -133,8 +131,6 @@ static inline void ata_acpi_set_state(struct ata_port *ap,
                                      pm_message_t state) { }
 static inline void ata_acpi_bind_port(struct ata_port *ap) {}
 static inline void ata_acpi_bind_dev(struct ata_device *dev) {}
-static inline void ata_scsi_acpi_bind(struct ata_device *dev) {}
-static inline void ata_scsi_acpi_unbind(struct ata_device *dev) {}
 #endif
 
 /* libata-scsi.c */
index 4bceb88..b33d1f9 100644 (file)
@@ -78,7 +78,7 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
 
        ap->ioaddr.cmd_addr = cmd_addr;
 
-       if (pnp_port_valid(idev, 1) == 0) {
+       if (pnp_port_valid(idev, 1)) {
                ctl_addr = devm_ioport_map(&idev->dev,
                                           pnp_port_start(idev, 1), 1);
                ap->ioaddr.altstatus_addr = ctl_addr;
index 9e59f65..bece691 100644 (file)
@@ -333,8 +333,10 @@ store_mem_state(struct device *dev,
                online_type = ONLINE_KEEP;
        else if (!strncmp(buf, "offline", min_t(int, count, 7)))
                online_type = -1;
-       else
-               return -EINVAL;
+       else {
+               ret = -EINVAL;
+               goto err;
+       }
 
        switch (online_type) {
        case ONLINE_KERNEL:
@@ -357,6 +359,7 @@ store_mem_state(struct device *dev,
                ret = -EINVAL; /* should never happen */
        }
 
+err:
        unlock_device_hotplug();
 
        if (ret)
index c9fd694..50329d1 100644 (file)
@@ -210,25 +210,6 @@ static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
        }
 }
 
-static void bcma_core_pci_power_save(struct bcma_drv_pci *pc, bool up)
-{
-       u16 data;
-
-       if (pc->core->id.rev >= 15 && pc->core->id.rev <= 20) {
-               data = up ? 0x74 : 0x7C;
-               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
-                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7F64);
-               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
-                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
-       } else if (pc->core->id.rev >= 21 && pc->core->id.rev <= 22) {
-               data = up ? 0x75 : 0x7D;
-               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
-                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7E65);
-               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
-                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
-       }
-}
-
 /**************************************************
  * Init.
  **************************************************/
@@ -255,6 +236,32 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc)
                bcma_core_pci_clientmode_init(pc);
 }
 
+void bcma_core_pci_power_save(struct bcma_bus *bus, bool up)
+{
+       struct bcma_drv_pci *pc;
+       u16 data;
+
+       if (bus->hosttype != BCMA_HOSTTYPE_PCI)
+               return;
+
+       pc = &bus->drv_pci[0];
+
+       if (pc->core->id.rev >= 15 && pc->core->id.rev <= 20) {
+               data = up ? 0x74 : 0x7C;
+               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
+                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7F64);
+               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
+                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
+       } else if (pc->core->id.rev >= 21 && pc->core->id.rev <= 22) {
+               data = up ? 0x75 : 0x7D;
+               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
+                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7E65);
+               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
+                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
+       }
+}
+EXPORT_SYMBOL_GPL(bcma_core_pci_power_save);
+
 int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
                          bool enable)
 {
@@ -310,8 +317,6 @@ void bcma_core_pci_up(struct bcma_bus *bus)
 
        pc = &bus->drv_pci[0];
 
-       bcma_core_pci_power_save(pc, true);
-
        bcma_core_pci_extend_L1timer(pc, true);
 }
 EXPORT_SYMBOL_GPL(bcma_core_pci_up);
@@ -326,7 +331,5 @@ void bcma_core_pci_down(struct bcma_bus *bus)
        pc = &bus->drv_pci[0];
 
        bcma_core_pci_extend_L1timer(pc, false);
-
-       bcma_core_pci_power_save(pc, false);
 }
 EXPORT_SYMBOL_GPL(bcma_core_pci_down);
index a12b923..0a327f4 100644 (file)
@@ -85,6 +85,7 @@ static struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x04CA, 0x3008) },
        { USB_DEVICE(0x13d3, 0x3362) },
        { USB_DEVICE(0x0CF3, 0xE004) },
+       { USB_DEVICE(0x0CF3, 0xE005) },
        { USB_DEVICE(0x0930, 0x0219) },
        { USB_DEVICE(0x0489, 0xe057) },
        { USB_DEVICE(0x13d3, 0x3393) },
@@ -126,6 +127,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
index 8e16f0a..f3dfc0a 100644 (file)
@@ -102,6 +102,7 @@ static struct usb_device_id btusb_table[] = {
 
        /* Broadcom BCM20702A0 */
        { USB_DEVICE(0x0b05, 0x17b5) },
+       { USB_DEVICE(0x0b05, 0x17cb) },
        { USB_DEVICE(0x04ca, 0x2003) },
        { USB_DEVICE(0x0489, 0xe042) },
        { USB_DEVICE(0x413c, 0x8197) },
@@ -112,6 +113,9 @@ static struct usb_device_id btusb_table[] = {
        /*Broadcom devices with vendor specific id */
        { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
 
+       /* Belkin F8065bf - Broadcom based */
+       { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
+
        { }     /* Terminating entry */
 };
 
@@ -148,6 +152,7 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
index 19ab6ff..2394e97 100644 (file)
@@ -700,6 +700,7 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
                                         phys_addr_t sdramwins_phys_base,
                                         size_t sdramwins_size)
 {
+       struct device_node *np;
        int win;
 
        mbus->mbuswins_base = ioremap(mbuswins_phys_base, mbuswins_size);
@@ -712,8 +713,11 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
                return -ENOMEM;
        }
 
-       if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"))
+       np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
+       if (np) {
                mbus->hw_io_coherency = 1;
+               of_node_put(np);
+       }
 
        for (win = 0; win < mbus->soc->num_wins; win++)
                mvebu_mbus_disable_window(mbus, win);
@@ -861,11 +865,13 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
        int ret;
 
        /*
-        * These are optional, so we clear them and they'll
-        * be zero if they are missing from the DT.
+        * These are optional, so we make sure that resource_size(x) will
+        * return 0.
         */
        memset(mem, 0, sizeof(struct resource));
+       mem->end = -1;
        memset(io, 0, sizeof(struct resource));
+       io->end = -1;
 
        ret = of_property_read_u32_array(np, "pcie-mem-aperture", reg, ARRAY_SIZE(reg));
        if (!ret) {
index 7737b5b..7a744d3 100644 (file)
@@ -640,7 +640,7 @@ struct timer_rand_state {
  */
 void add_device_randomness(const void *buf, unsigned int size)
 {
-       unsigned long time = get_cycles() ^ jiffies;
+       unsigned long time = random_get_entropy() ^ jiffies;
 
        mix_pool_bytes(&input_pool, buf, size, NULL);
        mix_pool_bytes(&input_pool, &time, sizeof(time), NULL);
@@ -677,7 +677,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
                goto out;
 
        sample.jiffies = jiffies;
-       sample.cycles = get_cycles();
+       sample.cycles = random_get_entropy();
        sample.num = num;
        mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL);
 
@@ -744,7 +744,7 @@ void add_interrupt_randomness(int irq, int irq_flags)
        struct fast_pool        *fast_pool = &__get_cpu_var(irq_randomness);
        struct pt_regs          *regs = get_irq_regs();
        unsigned long           now = jiffies;
-       __u32                   input[4], cycles = get_cycles();
+       __u32                   input[4], cycles = random_get_entropy();
 
        input[0] = cycles ^ jiffies;
        input[1] = irq;
@@ -1459,12 +1459,11 @@ struct ctl_table random_table[] = {
 
 static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
 
-static int __init random_int_secret_init(void)
+int random_int_secret_init(void)
 {
        get_random_bytes(random_int_secret, sizeof(random_int_secret));
        return 0;
 }
-late_initcall(random_int_secret_init);
 
 /*
  * Get a random word for internal kernel use only. Similar to urandom but
@@ -1483,7 +1482,7 @@ unsigned int get_random_int(void)
 
        hash = get_cpu_var(get_random_int_hash);
 
-       hash[0] += current->pid + jiffies + get_cycles();
+       hash[0] += current->pid + jiffies + random_get_entropy();
        md5_transform(hash, random_int_secret);
        ret = hash[0];
        put_cpu_var(get_random_int_hash);
index 06189e5..94c280d 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
+#include <xen/xen.h>
 #include <xen/events.h>
 #include <xen/interface/io/tpmif.h>
 #include <xen/grant_table.h>
index 51410c2..4d978a3 100644 (file)
  */
 
 #define SRC_CR                 0x00U
+#define SRC_CR_T0_ENSEL                BIT(15)
+#define SRC_CR_T1_ENSEL                BIT(17)
+#define SRC_CR_T2_ENSEL                BIT(19)
+#define SRC_CR_T3_ENSEL                BIT(21)
+#define SRC_CR_T4_ENSEL                BIT(23)
+#define SRC_CR_T5_ENSEL                BIT(25)
+#define SRC_CR_T6_ENSEL                BIT(27)
+#define SRC_CR_T7_ENSEL                BIT(29)
 #define SRC_XTALCR             0x0CU
 #define SRC_XTALCR_XTALTIMEN   BIT(20)
 #define SRC_XTALCR_SXTALDIS    BIT(19)
@@ -543,6 +551,19 @@ void __init nomadik_clk_init(void)
                       __func__, np->name);
                return;
        }
+
+       /* Set all timers to use the 2.4 MHz TIMCLK */
+       val = readl(src_base + SRC_CR);
+       val |= SRC_CR_T0_ENSEL;
+       val |= SRC_CR_T1_ENSEL;
+       val |= SRC_CR_T2_ENSEL;
+       val |= SRC_CR_T3_ENSEL;
+       val |= SRC_CR_T4_ENSEL;
+       val |= SRC_CR_T5_ENSEL;
+       val |= SRC_CR_T6_ENSEL;
+       val |= SRC_CR_T7_ENSEL;
+       writel(val, src_base + SRC_CR);
+
        val = readl(src_base + SRC_XTALCR);
        pr_info("SXTALO is %s\n",
                (val & SRC_XTALCR_SXTALDIS) ? "disabled" : "enabled");
index fc777bd..81a202d 100644 (file)
@@ -39,8 +39,8 @@ static const struct coreclk_ratio a370_coreclk_ratios[] __initconst = {
 };
 
 static const u32 a370_tclk_freqs[] __initconst = {
-       16600000,
-       20000000,
+       166000000,
+       200000000,
 };
 
 static u32 __init a370_get_tclk_freq(void __iomem *sar)
index 5bb848c..81dd31a 100644 (file)
@@ -49,7 +49,7 @@
 #define SOCFPGA_L4_SP_CLK              "l4_sp_clk"
 #define SOCFPGA_NAND_CLK               "nand_clk"
 #define SOCFPGA_NAND_X_CLK             "nand_x_clk"
-#define SOCFPGA_MMC_CLK                        "mmc_clk"
+#define SOCFPGA_MMC_CLK                        "sdmmc_clk"
 #define SOCFPGA_DB_CLK                 "gpio_db_clk"
 
 #define div_mask(width)        ((1 << (width)) - 1)
index 67ccf4a..f5e4c21 100644 (file)
@@ -107,7 +107,7 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
 
        vco = icst_hz_to_vco(icst->params, rate);
        icst->rate = icst_hz(icst->params, vco);
-       vco_set(icst->vcoreg, icst->lockreg, vco);
+       vco_set(icst->lockreg, icst->vcoreg, vco);
        return 0;
 }
 
index 08ae128..c73fc2b 100644 (file)
@@ -65,6 +65,7 @@ void proc_fork_connector(struct task_struct *task)
 
        msg = (struct cn_msg *)buffer;
        ev = (struct proc_event *)msg->data;
+       memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
        put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
@@ -80,6 +81,7 @@ void proc_fork_connector(struct task_struct *task)
        memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
+       msg->flags = 0; /* not used */
        /*  If cn_netlink_send() failed, the data is not sent */
        cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
 }
@@ -96,6 +98,7 @@ void proc_exec_connector(struct task_struct *task)
 
        msg = (struct cn_msg *)buffer;
        ev = (struct proc_event *)msg->data;
+       memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
        put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
@@ -106,6 +109,7 @@ void proc_exec_connector(struct task_struct *task)
        memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
+       msg->flags = 0; /* not used */
        cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
 }
 
@@ -122,6 +126,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
 
        msg = (struct cn_msg *)buffer;
        ev = (struct proc_event *)msg->data;
+       memset(&ev->event_data, 0, sizeof(ev->event_data));
        ev->what = which_id;
        ev->event_data.id.process_pid = task->pid;
        ev->event_data.id.process_tgid = task->tgid;
@@ -145,6 +150,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
        memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
+       msg->flags = 0; /* not used */
        cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
 }
 
@@ -160,6 +166,7 @@ void proc_sid_connector(struct task_struct *task)
 
        msg = (struct cn_msg *)buffer;
        ev = (struct proc_event *)msg->data;
+       memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
        put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
@@ -170,6 +177,7 @@ void proc_sid_connector(struct task_struct *task)
        memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
+       msg->flags = 0; /* not used */
        cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
 }
 
@@ -185,6 +193,7 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
 
        msg = (struct cn_msg *)buffer;
        ev = (struct proc_event *)msg->data;
+       memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
        put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
@@ -203,6 +212,7 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
        memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
+       msg->flags = 0; /* not used */
        cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
 }
 
@@ -218,6 +228,7 @@ void proc_comm_connector(struct task_struct *task)
 
        msg = (struct cn_msg *)buffer;
        ev = (struct proc_event *)msg->data;
+       memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
        put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
@@ -229,6 +240,7 @@ void proc_comm_connector(struct task_struct *task)
        memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
+       msg->flags = 0; /* not used */
        cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
 }
 
@@ -244,6 +256,7 @@ void proc_coredump_connector(struct task_struct *task)
 
        msg = (struct cn_msg *)buffer;
        ev = (struct proc_event *)msg->data;
+       memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
        put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
@@ -254,6 +267,7 @@ void proc_coredump_connector(struct task_struct *task)
        memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
+       msg->flags = 0; /* not used */
        cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
 }
 
@@ -269,6 +283,7 @@ void proc_exit_connector(struct task_struct *task)
 
        msg = (struct cn_msg *)buffer;
        ev = (struct proc_event *)msg->data;
+       memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
        put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
@@ -281,6 +296,7 @@ void proc_exit_connector(struct task_struct *task)
        memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
+       msg->flags = 0; /* not used */
        cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
 }
 
@@ -304,6 +320,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
 
        msg = (struct cn_msg *)buffer;
        ev = (struct proc_event *)msg->data;
+       memset(&ev->event_data, 0, sizeof(ev->event_data));
        msg->seq = rcvd_seq;
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
        put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
@@ -313,6 +330,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
        memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
        msg->ack = rcvd_ack + 1;
        msg->len = sizeof(*ev);
+       msg->flags = 0; /* not used */
        cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
 }
 
index 6ecfa75..a36749f 100644 (file)
@@ -109,7 +109,7 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
 
        data = nlmsg_data(nlh);
 
-       memcpy(data, msg, sizeof(*data) + msg->len);
+       memcpy(data, msg, size);
 
        NETLINK_CB(skb).dst_group = group;
 
@@ -157,17 +157,18 @@ static int cn_call_callback(struct sk_buff *skb)
 static void cn_rx_skb(struct sk_buff *__skb)
 {
        struct nlmsghdr *nlh;
-       int err;
        struct sk_buff *skb;
+       int len, err;
 
        skb = skb_get(__skb);
 
        if (skb->len >= NLMSG_HDRLEN) {
                nlh = nlmsg_hdr(skb);
+               len = nlmsg_len(nlh);
 
-               if (nlh->nlmsg_len < sizeof(struct cn_msg) ||
+               if (len < (int)sizeof(struct cn_msg) ||
                    skb->len < nlh->nlmsg_len ||
-                   nlh->nlmsg_len > CONNECTOR_MAX_MSG_SIZE) {
+                   len > CONNECTOR_MAX_MSG_SIZE) {
                        kfree_skb(skb);
                        return;
                }
index d2c3253..506fd23 100644 (file)
@@ -986,12 +986,12 @@ static int __init acpi_cpufreq_init(void)
 {
        int ret;
 
+       if (acpi_disabled)
+               return -ENODEV;
+
        /* don't keep reloading if cpufreq_driver exists */
        if (cpufreq_get_current_driver())
-               return 0;
-
-       if (acpi_disabled)
-               return 0;
+               return -EEXIST;
 
        pr_debug("acpi_cpufreq_init\n");
 
index 78c49d8..c522a95 100644 (file)
@@ -229,7 +229,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
        if (of_property_read_u32(np, "clock-latency", &transition_latency))
                transition_latency = CPUFREQ_ETERNAL;
 
-       if (cpu_reg) {
+       if (!IS_ERR(cpu_reg)) {
                struct opp *opp;
                unsigned long min_uV, max_uV;
                int i;
index 9733f29..eb3fdc7 100644 (file)
@@ -48,7 +48,7 @@ static inline int32_t div_fp(int32_t x, int32_t y)
 }
 
 struct sample {
-       int core_pct_busy;
+       int32_t core_pct_busy;
        u64 aperf;
        u64 mperf;
        int freq;
@@ -68,7 +68,7 @@ struct _pid {
        int32_t i_gain;
        int32_t d_gain;
        int deadband;
-       int last_err;
+       int32_t last_err;
 };
 
 struct cpudata {
@@ -153,16 +153,15 @@ static inline void pid_d_gain_set(struct _pid *pid, int percent)
        pid->d_gain = div_fp(int_tofp(percent), int_tofp(100));
 }
 
-static signed int pid_calc(struct _pid *pid, int busy)
+static signed int pid_calc(struct _pid *pid, int32_t busy)
 {
-       signed int err, result;
+       signed int result;
        int32_t pterm, dterm, fp_error;
        int32_t integral_limit;
 
-       err = pid->setpoint - busy;
-       fp_error = int_tofp(err);
+       fp_error = int_tofp(pid->setpoint) - busy;
 
-       if (abs(err) <= pid->deadband)
+       if (abs(fp_error) <= int_tofp(pid->deadband))
                return 0;
 
        pterm = mul_fp(pid->p_gain, fp_error);
@@ -176,8 +175,8 @@ static signed int pid_calc(struct _pid *pid, int busy)
        if (pid->integral < -integral_limit)
                pid->integral = -integral_limit;
 
-       dterm = mul_fp(pid->d_gain, (err - pid->last_err));
-       pid->last_err = err;
+       dterm = mul_fp(pid->d_gain, fp_error - pid->last_err);
+       pid->last_err = fp_error;
 
        result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm;
 
@@ -367,12 +366,13 @@ static int intel_pstate_turbo_pstate(void)
 static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
 {
        int max_perf = cpu->pstate.turbo_pstate;
+       int max_perf_adj;
        int min_perf;
        if (limits.no_turbo)
                max_perf = cpu->pstate.max_pstate;
 
-       max_perf = fp_toint(mul_fp(int_tofp(max_perf), limits.max_perf));
-       *max = clamp_t(int, max_perf,
+       max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf), limits.max_perf));
+       *max = clamp_t(int, max_perf_adj,
                        cpu->pstate.min_pstate, cpu->pstate.turbo_pstate);
 
        min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits.min_perf));
@@ -383,6 +383,7 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
 static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
 {
        int max_perf, min_perf;
+       u64 val;
 
        intel_pstate_get_min_max(cpu, &min_perf, &max_perf);
 
@@ -394,8 +395,11 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
        trace_cpu_frequency(pstate * 100000, cpu->cpu);
 
        cpu->pstate.current_pstate = pstate;
-       wrmsrl(MSR_IA32_PERF_CTL, pstate << 8);
+       val = pstate << 8;
+       if (limits.no_turbo)
+               val |= (u64)1 << 32;
 
+       wrmsrl(MSR_IA32_PERF_CTL, val);
 }
 
 static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps)
@@ -432,8 +436,9 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu,
                                        struct sample *sample)
 {
        u64 core_pct;
-       core_pct = div64_u64(sample->aperf * 100, sample->mperf);
-       sample->freq = cpu->pstate.max_pstate * core_pct * 1000;
+       core_pct = div64_u64(int_tofp(sample->aperf * 100),
+                            sample->mperf);
+       sample->freq = fp_toint(cpu->pstate.max_pstate * core_pct * 1000);
 
        sample->core_pct_busy = core_pct;
 }
@@ -465,22 +470,19 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
        mod_timer_pinned(&cpu->timer, jiffies + delay);
 }
 
-static inline int intel_pstate_get_scaled_busy(struct cpudata *cpu)
+static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
 {
-       int32_t busy_scaled;
        int32_t core_busy, max_pstate, current_pstate;
 
-       core_busy = int_tofp(cpu->samples[cpu->sample_ptr].core_pct_busy);
+       core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy;
        max_pstate = int_tofp(cpu->pstate.max_pstate);
        current_pstate = int_tofp(cpu->pstate.current_pstate);
-       busy_scaled = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
-
-       return fp_toint(busy_scaled);
+       return mul_fp(core_busy, div_fp(max_pstate, current_pstate));
 }
 
 static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
 {
-       int busy_scaled;
+       int32_t busy_scaled;
        struct _pid *pid;
        signed int ctl = 0;
        int steps;
@@ -634,8 +636,8 @@ static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
 
 static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
 {
-       int rc, min_pstate, max_pstate;
        struct cpudata *cpu;
+       int rc;
 
        rc = intel_pstate_init_cpu(policy->cpu);
        if (rc)
@@ -649,9 +651,8 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
        else
                policy->policy = CPUFREQ_POLICY_POWERSAVE;
 
-       intel_pstate_get_min_max(cpu, &min_pstate, &max_pstate);
-       policy->min = min_pstate * 100000;
-       policy->max = max_pstate * 100000;
+       policy->min = cpu->pstate.min_pstate * 100000;
+       policy->max = cpu->pstate.turbo_pstate * 100000;
 
        /* cpuinfo and default policy values */
        policy->cpuinfo.min_freq = cpu->pstate.min_pstate * 100000;
index 8a72b0c..15631f9 100644 (file)
@@ -166,7 +166,7 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
                if (freq->frequency == CPUFREQ_ENTRY_INVALID)
                        continue;
 
-               dvfs = &s3c64xx_dvfs_table[freq->index];
+               dvfs = &s3c64xx_dvfs_table[freq->driver_data];
                found = 0;
 
                for (i = 0; i < count; i++) {
index 19e364f..3f41816 100644 (file)
@@ -113,7 +113,7 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
                unsigned int target_freq, unsigned int relation)
 {
        struct cpufreq_freqs freqs;
-       unsigned long newfreq;
+       long newfreq;
        struct clk *srcclk;
        int index, ret, mult = 1;
 
index 526ec77..f238cfd 100644 (file)
@@ -198,6 +198,7 @@ config TI_EDMA
        depends on ARCH_DAVINCI || ARCH_OMAP
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
+       select TI_PRIV_EDMA
        default n
        help
          Enable support for the TI EDMA controller. This DMA
index ff50ff4..10b577f 100644 (file)
@@ -305,7 +305,9 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
                                edma_alloc_slot(EDMA_CTLR(echan->ch_num),
                                                EDMA_SLOT_ANY);
                        if (echan->slot[i] < 0) {
+                               kfree(edesc);
                                dev_err(dev, "Failed to allocate slot\n");
+                               kfree(edesc);
                                return NULL;
                        }
                }
@@ -345,6 +347,7 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
                        ccnt = sg_dma_len(sg) / (acnt * bcnt);
                        if (ccnt > (SZ_64K - 1)) {
                                dev_err(dev, "Exceeded max SG segment size\n");
+                               kfree(edesc);
                                return NULL;
                        }
                        cidx = acnt * bcnt;
@@ -749,6 +752,6 @@ static void __exit edma_exit(void)
 }
 module_exit(edma_exit);
 
-MODULE_AUTHOR("Matt Porter <mporter@ti.com>");
+MODULE_AUTHOR("Matt Porter <matt.porter@linaro.org>");
 MODULE_DESCRIPTION("TI EDMA DMA engine driver");
 MODULE_LICENSE("GPL v2");
index 78f8ca5..55852c0 100644 (file)
@@ -437,17 +437,18 @@ static void dma_irq_handle_channel(struct imxdma_channel *imxdmac)
        struct imxdma_engine *imxdma = imxdmac->imxdma;
        int chno = imxdmac->channel;
        struct imxdma_desc *desc;
+       unsigned long flags;
 
-       spin_lock(&imxdma->lock);
+       spin_lock_irqsave(&imxdma->lock, flags);
        if (list_empty(&imxdmac->ld_active)) {
-               spin_unlock(&imxdma->lock);
+               spin_unlock_irqrestore(&imxdma->lock, flags);
                goto out;
        }
 
        desc = list_first_entry(&imxdmac->ld_active,
                                struct imxdma_desc,
                                node);
-       spin_unlock(&imxdma->lock);
+       spin_unlock_irqrestore(&imxdma->lock, flags);
 
        if (desc->sg) {
                u32 tmp;
@@ -519,7 +520,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
 {
        struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
        struct imxdma_engine *imxdma = imxdmac->imxdma;
-       unsigned long flags;
        int slot = -1;
        int i;
 
@@ -527,7 +527,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
        switch (d->type) {
        case IMXDMA_DESC_INTERLEAVED:
                /* Try to get a free 2D slot */
-               spin_lock_irqsave(&imxdma->lock, flags);
                for (i = 0; i < IMX_DMA_2D_SLOTS; i++) {
                        if ((imxdma->slots_2d[i].count > 0) &&
                        ((imxdma->slots_2d[i].xsr != d->x) ||
@@ -537,10 +536,8 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
                        slot = i;
                        break;
                }
-               if (slot < 0) {
-                       spin_unlock_irqrestore(&imxdma->lock, flags);
+               if (slot < 0)
                        return -EBUSY;
-               }
 
                imxdma->slots_2d[slot].xsr = d->x;
                imxdma->slots_2d[slot].ysr = d->y;
@@ -549,7 +546,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
 
                imxdmac->slot_2d = slot;
                imxdmac->enabled_2d = true;
-               spin_unlock_irqrestore(&imxdma->lock, flags);
 
                if (slot == IMX_DMA_2D_SLOT_A) {
                        d->config_mem &= ~CCR_MSEL_B;
@@ -625,18 +621,17 @@ static void imxdma_tasklet(unsigned long data)
        struct imxdma_channel *imxdmac = (void *)data;
        struct imxdma_engine *imxdma = imxdmac->imxdma;
        struct imxdma_desc *desc;
+       unsigned long flags;
 
-       spin_lock(&imxdma->lock);
+       spin_lock_irqsave(&imxdma->lock, flags);
 
        if (list_empty(&imxdmac->ld_active)) {
                /* Someone might have called terminate all */
-               goto out;
+               spin_unlock_irqrestore(&imxdma->lock, flags);
+               return;
        }
        desc = list_first_entry(&imxdmac->ld_active, struct imxdma_desc, node);
 
-       if (desc->desc.callback)
-               desc->desc.callback(desc->desc.callback_param);
-
        /* If we are dealing with a cyclic descriptor, keep it on ld_active
         * and dont mark the descriptor as complete.
         * Only in non-cyclic cases it would be marked as complete
@@ -663,7 +658,11 @@ static void imxdma_tasklet(unsigned long data)
                                 __func__, imxdmac->channel);
        }
 out:
-       spin_unlock(&imxdma->lock);
+       spin_unlock_irqrestore(&imxdma->lock, flags);
+
+       if (desc->desc.callback)
+               desc->desc.callback(desc->desc.callback_param);
+
 }
 
 static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -883,7 +882,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
        kfree(imxdmac->sg_list);
 
        imxdmac->sg_list = kcalloc(periods + 1,
-                       sizeof(struct scatterlist), GFP_KERNEL);
+                       sizeof(struct scatterlist), GFP_ATOMIC);
        if (!imxdmac->sg_list)
                return NULL;
 
index 45a5202..ebad845 100644 (file)
@@ -93,6 +93,7 @@ struct hpb_dmae_chan {
        void __iomem *base;
        const struct hpb_dmae_slave_config *cfg;
        char dev_id[16];                /* unique name per DMAC of channel */
+       dma_addr_t slave_addr;
 };
 
 struct hpb_dmae_device {
@@ -432,7 +433,6 @@ hpb_dmae_alloc_chan_resources(struct hpb_dmae_chan *hpb_chan,
                hpb_chan->xfer_mode = XFER_DOUBLE;
        } else {
                dev_err(hpb_chan->shdma_chan.dev, "DCR setting error");
-               shdma_free_irq(&hpb_chan->shdma_chan);
                return -EINVAL;
        }
 
@@ -446,7 +446,8 @@ hpb_dmae_alloc_chan_resources(struct hpb_dmae_chan *hpb_chan,
        return 0;
 }
 
-static int hpb_dmae_set_slave(struct shdma_chan *schan, int slave_id, bool try)
+static int hpb_dmae_set_slave(struct shdma_chan *schan, int slave_id,
+                             dma_addr_t slave_addr, bool try)
 {
        struct hpb_dmae_chan *chan = to_chan(schan);
        const struct hpb_dmae_slave_config *sc =
@@ -457,6 +458,7 @@ static int hpb_dmae_set_slave(struct shdma_chan *schan, int slave_id, bool try)
        if (try)
                return 0;
        chan->cfg = sc;
+       chan->slave_addr = slave_addr ? : sc->addr;
        return hpb_dmae_alloc_chan_resources(chan, sc);
 }
 
@@ -468,7 +470,7 @@ static dma_addr_t hpb_dmae_slave_addr(struct shdma_chan *schan)
 {
        struct hpb_dmae_chan *chan = to_chan(schan);
 
-       return chan->cfg->addr;
+       return chan->slave_addr;
 }
 
 static struct shdma_desc *hpb_dmae_embedded_desc(void *buf, int i)
@@ -614,7 +616,6 @@ static void hpb_dmae_chan_remove(struct hpb_dmae_device *hpbdev)
        shdma_for_each_chan(schan, &hpbdev->shdma_dev, i) {
                BUG_ON(!schan);
 
-               shdma_free_irq(schan);
                shdma_chan_remove(schan);
        }
        dma_dev->chancnt = 0;
index 2d9ca60..41b5913 100644 (file)
@@ -248,14 +248,15 @@ static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
        struct lp_gpio *lg = irq_data_get_irq_handler_data(data);
        struct irq_chip *chip = irq_data_get_irq_chip(data);
        u32 base, pin, mask;
-       unsigned long reg, pending;
+       unsigned long reg, ena, pending;
        unsigned virq;
 
        /* check from GPIO controller which pin triggered the interrupt */
        for (base = 0; base < lg->chip.ngpio; base += 32) {
                reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
+               ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
 
-               while ((pending = inl(reg))) {
+               while ((pending = (inl(reg) & inl(ena)))) {
                        pin = __ffs(pending);
                        mask = BIT(pin);
                        /* Clear before handling so we don't lose an edge */
index 0ff4355..89675f8 100644 (file)
@@ -63,6 +63,7 @@ struct gpio_bank {
        struct gpio_chip chip;
        struct clk *dbck;
        u32 mod_usage;
+       u32 irq_usage;
        u32 dbck_enable_mask;
        bool dbck_enabled;
        struct device *dev;
@@ -86,6 +87,9 @@ struct gpio_bank {
 #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
 #define GPIO_MOD_CTRL_BIT      BIT(0)
 
+#define BANK_USED(bank) (bank->mod_usage || bank->irq_usage)
+#define LINE_USED(line, offset) (line & (1 << offset))
+
 static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
 {
        return bank->chip.base + gpio_irq;
@@ -420,15 +424,69 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
        return 0;
 }
 
+static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset)
+{
+       if (bank->regs->pinctrl) {
+               void __iomem *reg = bank->base + bank->regs->pinctrl;
+
+               /* Claim the pin for MPU */
+               __raw_writel(__raw_readl(reg) | (1 << offset), reg);
+       }
+
+       if (bank->regs->ctrl && !BANK_USED(bank)) {
+               void __iomem *reg = bank->base + bank->regs->ctrl;
+               u32 ctrl;
+
+               ctrl = __raw_readl(reg);
+               /* Module is enabled, clocks are not gated */
+               ctrl &= ~GPIO_MOD_CTRL_BIT;
+               __raw_writel(ctrl, reg);
+               bank->context.ctrl = ctrl;
+       }
+}
+
+static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset)
+{
+       void __iomem *base = bank->base;
+
+       if (bank->regs->wkup_en &&
+           !LINE_USED(bank->mod_usage, offset) &&
+           !LINE_USED(bank->irq_usage, offset)) {
+               /* Disable wake-up during idle for dynamic tick */
+               _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0);
+               bank->context.wake_en =
+                       __raw_readl(bank->base + bank->regs->wkup_en);
+       }
+
+       if (bank->regs->ctrl && !BANK_USED(bank)) {
+               void __iomem *reg = bank->base + bank->regs->ctrl;
+               u32 ctrl;
+
+               ctrl = __raw_readl(reg);
+               /* Module is disabled, clocks are gated */
+               ctrl |= GPIO_MOD_CTRL_BIT;
+               __raw_writel(ctrl, reg);
+               bank->context.ctrl = ctrl;
+       }
+}
+
+static int gpio_is_input(struct gpio_bank *bank, int mask)
+{
+       void __iomem *reg = bank->base + bank->regs->direction;
+
+       return __raw_readl(reg) & mask;
+}
+
 static int gpio_irq_type(struct irq_data *d, unsigned type)
 {
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
        unsigned gpio = 0;
        int retval;
        unsigned long flags;
+       unsigned offset;
 
-       if (WARN_ON(!bank->mod_usage))
-               return -EINVAL;
+       if (!BANK_USED(bank))
+               pm_runtime_get_sync(bank->dev);
 
 #ifdef CONFIG_ARCH_OMAP1
        if (d->irq > IH_MPUIO_BASE)
@@ -446,7 +504,17 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
                return -EINVAL;
 
        spin_lock_irqsave(&bank->lock, flags);
-       retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type);
+       offset = GPIO_INDEX(bank, gpio);
+       retval = _set_gpio_triggering(bank, offset, type);
+       if (!LINE_USED(bank->mod_usage, offset)) {
+               _enable_gpio_module(bank, offset);
+               _set_gpio_direction(bank, offset, 1);
+       } else if (!gpio_is_input(bank, 1 << offset)) {
+               spin_unlock_irqrestore(&bank->lock, flags);
+               return -EINVAL;
+       }
+
+       bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio);
        spin_unlock_irqrestore(&bank->lock, flags);
 
        if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
@@ -603,35 +671,19 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
         * If this is the first gpio_request for the bank,
         * enable the bank module.
         */
-       if (!bank->mod_usage)
+       if (!BANK_USED(bank))
                pm_runtime_get_sync(bank->dev);
 
        spin_lock_irqsave(&bank->lock, flags);
        /* Set trigger to none. You need to enable the desired trigger with
-        * request_irq() or set_irq_type().
+        * request_irq() or set_irq_type(). Only do this if the IRQ line has
+        * not already been requested.
         */
-       _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
-
-       if (bank->regs->pinctrl) {
-               void __iomem *reg = bank->base + bank->regs->pinctrl;
-
-               /* Claim the pin for MPU */
-               __raw_writel(__raw_readl(reg) | (1 << offset), reg);
-       }
-
-       if (bank->regs->ctrl && !bank->mod_usage) {
-               void __iomem *reg = bank->base + bank->regs->ctrl;
-               u32 ctrl;
-
-               ctrl = __raw_readl(reg);
-               /* Module is enabled, clocks are not gated */
-               ctrl &= ~GPIO_MOD_CTRL_BIT;
-               __raw_writel(ctrl, reg);
-               bank->context.ctrl = ctrl;
+       if (!LINE_USED(bank->irq_usage, offset)) {
+               _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+               _enable_gpio_module(bank, offset);
        }
-
        bank->mod_usage |= 1 << offset;
-
        spin_unlock_irqrestore(&bank->lock, flags);
 
        return 0;
@@ -640,31 +692,11 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
        struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
-       void __iomem *base = bank->base;
        unsigned long flags;
 
        spin_lock_irqsave(&bank->lock, flags);
-
-       if (bank->regs->wkup_en) {
-               /* Disable wake-up during idle for dynamic tick */
-               _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0);
-               bank->context.wake_en =
-                       __raw_readl(bank->base + bank->regs->wkup_en);
-       }
-
        bank->mod_usage &= ~(1 << offset);
-
-       if (bank->regs->ctrl && !bank->mod_usage) {
-               void __iomem *reg = bank->base + bank->regs->ctrl;
-               u32 ctrl;
-
-               ctrl = __raw_readl(reg);
-               /* Module is disabled, clocks are gated */
-               ctrl |= GPIO_MOD_CTRL_BIT;
-               __raw_writel(ctrl, reg);
-               bank->context.ctrl = ctrl;
-       }
-
+       _disable_gpio_module(bank, offset);
        _reset_gpio(bank, bank->chip.base + offset);
        spin_unlock_irqrestore(&bank->lock, flags);
 
@@ -672,7 +704,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
         * If this is the last gpio to be freed in the bank,
         * disable the bank module.
         */
-       if (!bank->mod_usage)
+       if (!BANK_USED(bank))
                pm_runtime_put(bank->dev);
 }
 
@@ -762,10 +794,20 @@ static void gpio_irq_shutdown(struct irq_data *d)
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
        unsigned int gpio = irq_to_gpio(bank, d->hwirq);
        unsigned long flags;
+       unsigned offset = GPIO_INDEX(bank, gpio);
 
        spin_lock_irqsave(&bank->lock, flags);
+       bank->irq_usage &= ~(1 << offset);
+       _disable_gpio_module(bank, offset);
        _reset_gpio(bank, gpio);
        spin_unlock_irqrestore(&bank->lock, flags);
+
+       /*
+        * If this is the last IRQ to be freed in the bank,
+        * disable the bank module.
+        */
+       if (!BANK_USED(bank))
+               pm_runtime_put(bank->dev);
 }
 
 static void gpio_ack_irq(struct irq_data *d)
@@ -897,13 +939,6 @@ static int gpio_input(struct gpio_chip *chip, unsigned offset)
        return 0;
 }
 
-static int gpio_is_input(struct gpio_bank *bank, int mask)
-{
-       void __iomem *reg = bank->base + bank->regs->direction;
-
-       return __raw_readl(reg) & mask;
-}
-
 static int gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct gpio_bank *bank;
@@ -922,13 +957,22 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct gpio_bank *bank;
        unsigned long flags;
+       int retval = 0;
 
        bank = container_of(chip, struct gpio_bank, chip);
        spin_lock_irqsave(&bank->lock, flags);
+
+       if (LINE_USED(bank->irq_usage, offset)) {
+                       retval = -EINVAL;
+                       goto exit;
+       }
+
        bank->set_dataout(bank, offset, value);
        _set_gpio_direction(bank, offset, 0);
+
+exit:
        spin_unlock_irqrestore(&bank->lock, flags);
-       return 0;
+       return retval;
 }
 
 static int gpio_debounce(struct gpio_chip *chip, unsigned offset,
@@ -1400,7 +1444,7 @@ void omap2_gpio_prepare_for_idle(int pwr_mode)
        struct gpio_bank *bank;
 
        list_for_each_entry(bank, &omap_gpio_list, node) {
-               if (!bank->mod_usage || !bank->loses_context)
+               if (!BANK_USED(bank) || !bank->loses_context)
                        continue;
 
                bank->power_mode = pwr_mode;
@@ -1414,7 +1458,7 @@ void omap2_gpio_resume_after_idle(void)
        struct gpio_bank *bank;
 
        list_for_each_entry(bank, &omap_gpio_list, node) {
-               if (!bank->mod_usage || !bank->loses_context)
+               if (!BANK_USED(bank) || !bank->loses_context)
                        continue;
 
                pm_runtime_get_sync(bank->dev);
index e3745eb..6038966 100644 (file)
@@ -293,10 +293,9 @@ static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p)
        if (pdata) {
                p->config = *pdata;
        } else if (IS_ENABLED(CONFIG_OF) && np) {
-               ret = of_parse_phandle_with_args(np, "gpio-ranges",
-                               "#gpio-range-cells", 0, &args);
-               p->config.number_of_pins = ret == 0 && args.args_count == 3
-                                        ? args.args[2]
+               ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0,
+                                                      &args);
+               p->config.number_of_pins = ret == 0 ? args.args[2]
                                         : RCAR_MAX_GPIO_PER_BANK;
                p->config.gpio_base = -1;
        }
index 86ef346..0dee0e0 100644 (file)
@@ -136,7 +136,7 @@ static struct gpio_desc *gpio_to_desc(unsigned gpio)
  */
 static int desc_to_gpio(const struct gpio_desc *desc)
 {
-       return desc->chip->base + gpio_chip_hwgpio(desc);
+       return desc - &gpio_desc[0];
 }
 
 
@@ -1398,7 +1398,7 @@ static int gpiod_request(struct gpio_desc *desc, const char *label)
        int                     status = -EPROBE_DEFER;
        unsigned long           flags;
 
-       if (!desc || !desc->chip) {
+       if (!desc) {
                pr_warn("%s: invalid GPIO\n", __func__);
                return -EINVAL;
        }
@@ -1406,6 +1406,8 @@ static int gpiod_request(struct gpio_desc *desc, const char *label)
        spin_lock_irqsave(&gpio_lock, flags);
 
        chip = desc->chip;
+       if (chip == NULL)
+               goto done;
 
        if (!try_module_get(chip->owner))
                goto done;
index 138de14..d9137e4 100644 (file)
@@ -61,7 +61,7 @@ static int drm_version(struct drm_device *dev, void *data,
 
 /** Ioctl table */
 static const struct drm_ioctl_desc drm_ioctls[] = {
-       DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
@@ -332,9 +332,16 @@ long drm_ioctl(struct file *filp,
                cmd = ioctl->cmd_drv;
        }
        else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
+               u32 drv_size;
+
                ioctl = &drm_ioctls[nr];
-               cmd = ioctl->cmd;
+
+               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;
 
index 7203523..0a19401 100644 (file)
@@ -403,14 +403,6 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
        struct drm_connector *connector;
        int i, j;
 
-       /*
-        * fbdev->blank can be called from irq context in case of a panic.
-        * Since we already have our own special panic handler which will
-        * restore the fbdev console mode completely, just bail out early.
-        */
-       if (oops_in_progress)
-               return;
-
        /*
         * fbdev->blank can be called from irq context in case of a panic.
         * Since we already have our own special panic handler which will
index 162f686..5a9a6a3 100644 (file)
@@ -634,6 +634,7 @@ const struct psb_ops cdv_chip_ops = {
        .crtcs = 2,
        .hdmi_mask = (1 << 0) | (1 << 1),
        .lvds_mask = (1 << 1),
+       .sdvo_mask = (1 << 0),
        .cursor_needs_phys = 0,
        .sgx_offset = MRST_SGX_OFFSET,
        .chip_setup = cdv_chip_setup,
index 01dd7d2..94b3fec 100644 (file)
@@ -714,7 +714,7 @@ static void psb_setup_outputs(struct drm_device *dev)
                        clone_mask = (1 << INTEL_OUTPUT_ANALOG);
                        break;
                case INTEL_OUTPUT_SDVO:
-                       crtc_mask = ((1 << 0) | (1 << 1));
+                       crtc_mask = dev_priv->ops->sdvo_mask;
                        clone_mask = (1 << INTEL_OUTPUT_SDVO);
                        break;
                case INTEL_OUTPUT_LVDS:
index 92babac..2db731f 100644 (file)
@@ -204,6 +204,7 @@ static int psb_gtt_attach_pages(struct gtt_range *gt)
        if (IS_ERR(pages))
                return PTR_ERR(pages);
 
+       gt->npage = gt->gem.size / PAGE_SIZE;
        gt->pages = pages;
 
        return 0;
index 62cd42e..566d330 100644 (file)
@@ -51,6 +51,9 @@
 #define wait_for(COND, MS) _wait_for(COND, MS, 1)
 #define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0)
 
+#define GMBUS_REG_READ(reg) ioread32(dev_priv->gmbus_reg + (reg))
+#define GMBUS_REG_WRITE(reg, val) iowrite32((val), dev_priv->gmbus_reg + (reg))
+
 /* Intel GPIO access functions */
 
 #define I2C_RISEFALL_TIME 20
@@ -71,7 +74,8 @@ struct intel_gpio {
 void
 gma_intel_i2c_reset(struct drm_device *dev)
 {
-       REG_WRITE(GMBUS0, 0);
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       GMBUS_REG_WRITE(GMBUS0, 0);
 }
 
 static void intel_i2c_quirk_set(struct drm_psb_private *dev_priv, bool enable)
@@ -98,11 +102,10 @@ static void intel_i2c_quirk_set(struct drm_psb_private *dev_priv, bool enable)
 static u32 get_reserved(struct intel_gpio *gpio)
 {
        struct drm_psb_private *dev_priv = gpio->dev_priv;
-       struct drm_device *dev = dev_priv->dev;
        u32 reserved = 0;
 
        /* On most chips, these bits must be preserved in software. */
-       reserved = REG_READ(gpio->reg) &
+       reserved = GMBUS_REG_READ(gpio->reg) &
                                     (GPIO_DATA_PULLUP_DISABLE |
                                      GPIO_CLOCK_PULLUP_DISABLE);
 
@@ -113,29 +116,26 @@ static int get_clock(void *data)
 {
        struct intel_gpio *gpio = data;
        struct drm_psb_private *dev_priv = gpio->dev_priv;
-       struct drm_device *dev = dev_priv->dev;
        u32 reserved = get_reserved(gpio);
-       REG_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
-       REG_WRITE(gpio->reg, reserved);
-       return (REG_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
+       GMBUS_REG_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
+       GMBUS_REG_WRITE(gpio->reg, reserved);
+       return (GMBUS_REG_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
 }
 
 static int get_data(void *data)
 {
        struct intel_gpio *gpio = data;
        struct drm_psb_private *dev_priv = gpio->dev_priv;
-       struct drm_device *dev = dev_priv->dev;
        u32 reserved = get_reserved(gpio);
-       REG_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
-       REG_WRITE(gpio->reg, reserved);
-       return (REG_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
+       GMBUS_REG_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
+       GMBUS_REG_WRITE(gpio->reg, reserved);
+       return (GMBUS_REG_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
 }
 
 static void set_clock(void *data, int state_high)
 {
        struct intel_gpio *gpio = data;
        struct drm_psb_private *dev_priv = gpio->dev_priv;
-       struct drm_device *dev = dev_priv->dev;
        u32 reserved = get_reserved(gpio);
        u32 clock_bits;
 
@@ -145,15 +145,14 @@ static void set_clock(void *data, int state_high)
                clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
                        GPIO_CLOCK_VAL_MASK;
 
-       REG_WRITE(gpio->reg, reserved | clock_bits);
-       REG_READ(gpio->reg); /* Posting */
+       GMBUS_REG_WRITE(gpio->reg, reserved | clock_bits);
+       GMBUS_REG_READ(gpio->reg); /* Posting */
 }
 
 static void set_data(void *data, int state_high)
 {
        struct intel_gpio *gpio = data;
        struct drm_psb_private *dev_priv = gpio->dev_priv;
-       struct drm_device *dev = dev_priv->dev;
        u32 reserved = get_reserved(gpio);
        u32 data_bits;
 
@@ -163,8 +162,8 @@ static void set_data(void *data, int state_high)
                data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
                        GPIO_DATA_VAL_MASK;
 
-       REG_WRITE(gpio->reg, reserved | data_bits);
-       REG_READ(gpio->reg);
+       GMBUS_REG_WRITE(gpio->reg, reserved | data_bits);
+       GMBUS_REG_READ(gpio->reg);
 }
 
 static struct i2c_adapter *
@@ -251,7 +250,6 @@ gmbus_xfer(struct i2c_adapter *adapter,
                                               struct intel_gmbus,
                                               adapter);
        struct drm_psb_private *dev_priv = adapter->algo_data;
-       struct drm_device *dev = dev_priv->dev;
        int i, reg_offset;
 
        if (bus->force_bit)
@@ -260,28 +258,30 @@ gmbus_xfer(struct i2c_adapter *adapter,
 
        reg_offset = 0;
 
-       REG_WRITE(GMBUS0 + reg_offset, bus->reg0);
+       GMBUS_REG_WRITE(GMBUS0 + reg_offset, bus->reg0);
 
        for (i = 0; i < num; i++) {
                u16 len = msgs[i].len;
                u8 *buf = msgs[i].buf;
 
                if (msgs[i].flags & I2C_M_RD) {
-                       REG_WRITE(GMBUS1 + reg_offset,
-                                  GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
-                                  (len << GMBUS_BYTE_COUNT_SHIFT) |
-                                  (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
-                                  GMBUS_SLAVE_READ | GMBUS_SW_RDY);
-                       REG_READ(GMBUS2+reg_offset);
+                       GMBUS_REG_WRITE(GMBUS1 + reg_offset,
+                                       GMBUS_CYCLE_WAIT |
+                                       (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
+                                       (len << GMBUS_BYTE_COUNT_SHIFT) |
+                                       (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+                                       GMBUS_SLAVE_READ | GMBUS_SW_RDY);
+                       GMBUS_REG_READ(GMBUS2+reg_offset);
                        do {
                                u32 val, loop = 0;
 
-                               if (wait_for(REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+                               if (wait_for(GMBUS_REG_READ(GMBUS2 + reg_offset) &
+                                            (GMBUS_SATOER | GMBUS_HW_RDY), 50))
                                        goto timeout;
-                               if (REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+                               if (GMBUS_REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
                                        goto clear_err;
 
-                               val = REG_READ(GMBUS3 + reg_offset);
+                               val = GMBUS_REG_READ(GMBUS3 + reg_offset);
                                do {
                                        *buf++ = val & 0xff;
                                        val >>= 8;
@@ -295,18 +295,20 @@ gmbus_xfer(struct i2c_adapter *adapter,
                                val |= *buf++ << (8 * loop);
                        } while (--len && ++loop < 4);
 
-                       REG_WRITE(GMBUS3 + reg_offset, val);
-                       REG_WRITE(GMBUS1 + reg_offset,
+                       GMBUS_REG_WRITE(GMBUS3 + reg_offset, val);
+                       GMBUS_REG_WRITE(GMBUS1 + reg_offset,
                                   (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) |
                                   (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
                                   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
                                   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
-                       REG_READ(GMBUS2+reg_offset);
+                       GMBUS_REG_READ(GMBUS2+reg_offset);
 
                        while (len) {
-                               if (wait_for(REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+                               if (wait_for(GMBUS_REG_READ(GMBUS2 + reg_offset) &
+                                            (GMBUS_SATOER | GMBUS_HW_RDY), 50))
                                        goto timeout;
-                               if (REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+                               if (GMBUS_REG_READ(GMBUS2 + reg_offset) &
+                                   GMBUS_SATOER)
                                        goto clear_err;
 
                                val = loop = 0;
@@ -314,14 +316,14 @@ gmbus_xfer(struct i2c_adapter *adapter,
                                        val |= *buf++ << (8 * loop);
                                } while (--len && ++loop < 4);
 
-                               REG_WRITE(GMBUS3 + reg_offset, val);
-                               REG_READ(GMBUS2+reg_offset);
+                               GMBUS_REG_WRITE(GMBUS3 + reg_offset, val);
+                               GMBUS_REG_READ(GMBUS2+reg_offset);
                        }
                }
 
-               if (i + 1 < num && wait_for(REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
+               if (i + 1 < num && wait_for(GMBUS_REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
                        goto timeout;
-               if (REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+               if (GMBUS_REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
                        goto clear_err;
        }
 
@@ -332,20 +334,20 @@ clear_err:
         * of resetting the GMBUS controller and so clearing the
         * BUS_ERROR raised by the slave's NAK.
         */
-       REG_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT);
-       REG_WRITE(GMBUS1 + reg_offset, 0);
+       GMBUS_REG_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT);
+       GMBUS_REG_WRITE(GMBUS1 + reg_offset, 0);
 
 done:
        /* Mark the GMBUS interface as disabled. We will re-enable it at the
         * start of the next xfer, till then let it sleep.
         */
-       REG_WRITE(GMBUS0 + reg_offset, 0);
+       GMBUS_REG_WRITE(GMBUS0 + reg_offset, 0);
        return i;
 
 timeout:
        DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
                 bus->reg0 & 0xff, bus->adapter.name);
-       REG_WRITE(GMBUS0 + reg_offset, 0);
+       GMBUS_REG_WRITE(GMBUS0 + reg_offset, 0);
 
        /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
        bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
@@ -399,6 +401,11 @@ int gma_intel_setup_gmbus(struct drm_device *dev)
        if (dev_priv->gmbus == NULL)
                return -ENOMEM;
 
+       if (IS_MRST(dev))
+               dev_priv->gmbus_reg = dev_priv->aux_reg;
+       else
+               dev_priv->gmbus_reg = dev_priv->vdc_reg;
+
        for (i = 0; i < GMBUS_NUM_PORTS; i++) {
                struct intel_gmbus *bus = &dev_priv->gmbus[i];
 
@@ -487,6 +494,7 @@ void gma_intel_teardown_gmbus(struct drm_device *dev)
                i2c_del_adapter(&bus->adapter);
        }
 
+       dev_priv->gmbus_reg = NULL; /* iounmap is done in driver_unload */
        kfree(dev_priv->gmbus);
        dev_priv->gmbus = NULL;
 }
index 54c9896..8195e85 100644 (file)
 #include "gma_display.h"
 #include "power.h"
 
-struct psb_intel_range_t {
-       int min, max;
-};
-
-struct oaktrail_limit_t {
-       struct psb_intel_range_t dot, m, p1;
-};
-
-struct oaktrail_clock_t {
-       /* derived values */
-       int dot;
-       int m;
-       int p1;
-};
-
-#define MRST_LIMIT_LVDS_100L       0
-#define MRST_LIMIT_LVDS_83         1
-#define MRST_LIMIT_LVDS_100        2
+#define MRST_LIMIT_LVDS_100L   0
+#define MRST_LIMIT_LVDS_83     1
+#define MRST_LIMIT_LVDS_100    2
+#define MRST_LIMIT_SDVO                3
 
 #define MRST_DOT_MIN             19750
 #define MRST_DOT_MAX             120000
@@ -57,21 +43,40 @@ struct oaktrail_clock_t {
 #define MRST_P1_MAX_0              7
 #define MRST_P1_MAX_1              8
 
-static const struct oaktrail_limit_t oaktrail_limits[] = {
+static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit,
+                                   struct drm_crtc *crtc, int target,
+                                   int refclk, struct gma_clock_t *best_clock);
+
+static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit,
+                                   struct drm_crtc *crtc, int target,
+                                   int refclk, struct gma_clock_t *best_clock);
+
+static const struct gma_limit_t mrst_limits[] = {
        {                       /* MRST_LIMIT_LVDS_100L */
         .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX},
         .m = {.min = MRST_M_MIN_100L, .max = MRST_M_MAX_100L},
         .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1},
+        .find_pll = mrst_lvds_find_best_pll,
         },
        {                       /* MRST_LIMIT_LVDS_83L */
         .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX},
         .m = {.min = MRST_M_MIN_83, .max = MRST_M_MAX_83},
         .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_0},
+        .find_pll = mrst_lvds_find_best_pll,
         },
        {                       /* MRST_LIMIT_LVDS_100 */
         .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX},
         .m = {.min = MRST_M_MIN_100, .max = MRST_M_MAX_100},
         .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1},
+        .find_pll = mrst_lvds_find_best_pll,
+        },
+       {                       /* MRST_LIMIT_SDVO */
+        .vco = {.min = 1400000, .max = 2800000},
+        .n = {.min = 3, .max = 7},
+        .m = {.min = 80, .max = 137},
+        .p1 = {.min = 1, .max = 2},
+        .p2 = {.dot_limit = 200000, .p2_slow = 10, .p2_fast = 10},
+        .find_pll = mrst_sdvo_find_best_pll,
         },
 };
 
@@ -82,9 +87,10 @@ static const u32 oaktrail_m_converts[] = {
        0x12, 0x09, 0x24, 0x32, 0x39, 0x1c,
 };
 
-static const struct oaktrail_limit_t *oaktrail_limit(struct drm_crtc *crtc)
+static const struct gma_limit_t *mrst_limit(struct drm_crtc *crtc,
+                                           int refclk)
 {
-       const struct oaktrail_limit_t *limit = NULL;
+       const struct gma_limit_t *limit = NULL;
        struct drm_device *dev = crtc->dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
 
@@ -92,45 +98,100 @@ static const struct oaktrail_limit_t *oaktrail_limit(struct drm_crtc *crtc)
            || gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)) {
                switch (dev_priv->core_freq) {
                case 100:
-                       limit = &oaktrail_limits[MRST_LIMIT_LVDS_100L];
+                       limit = &mrst_limits[MRST_LIMIT_LVDS_100L];
                        break;
                case 166:
-                       limit = &oaktrail_limits[MRST_LIMIT_LVDS_83];
+                       limit = &mrst_limits[MRST_LIMIT_LVDS_83];
                        break;
                case 200:
-                       limit = &oaktrail_limits[MRST_LIMIT_LVDS_100];
+                       limit = &mrst_limits[MRST_LIMIT_LVDS_100];
                        break;
                }
+       } else if (gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
+               limit = &mrst_limits[MRST_LIMIT_SDVO];
        } else {
                limit = NULL;
-               dev_err(dev->dev, "oaktrail_limit Wrong display type.\n");
+               dev_err(dev->dev, "mrst_limit Wrong display type.\n");
        }
 
        return limit;
 }
 
 /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
-static void oaktrail_clock(int refclk, struct oaktrail_clock_t *clock)
+static void mrst_lvds_clock(int refclk, struct gma_clock_t *clock)
 {
        clock->dot = (refclk * clock->m) / (14 * clock->p1);
 }
 
-static void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock)
+static void mrst_print_pll(struct gma_clock_t *clock)
 {
-       pr_debug("%s: dotclock = %d,  m = %d, p1 = %d.\n",
-            prefix, clock->dot, clock->m, clock->p1);
+       DRM_DEBUG_DRIVER("dotclock=%d,  m=%d, m1=%d, m2=%d, n=%d, p1=%d, p2=%d\n",
+                        clock->dot, clock->m, clock->m1, clock->m2, clock->n,
+                        clock->p1, clock->p2);
+}
+
+static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit,
+                                   struct drm_crtc *crtc, int target,
+                                   int refclk, struct gma_clock_t *best_clock)
+{
+       struct gma_clock_t clock;
+       u32 target_vco, actual_freq;
+       s32 freq_error, min_error = 100000;
+
+       memset(best_clock, 0, sizeof(*best_clock));
+
+       for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
+               for (clock.n = limit->n.min; clock.n <= limit->n.max;
+                    clock.n++) {
+                       for (clock.p1 = limit->p1.min;
+                            clock.p1 <= limit->p1.max; clock.p1++) {
+                               /* p2 value always stored in p2_slow on SDVO */
+                               clock.p = clock.p1 * limit->p2.p2_slow;
+                               target_vco = target * clock.p;
+
+                               /* VCO will increase at this point so break */
+                               if (target_vco > limit->vco.max)
+                                       break;
+
+                               if (target_vco < limit->vco.min)
+                                       continue;
+
+                               actual_freq = (refclk * clock.m) /
+                                             (clock.n * clock.p);
+                               freq_error = 10000 -
+                                            ((target * 10000) / actual_freq);
+
+                               if (freq_error < -min_error) {
+                                       /* freq_error will start to decrease at
+                                          this point so break */
+                                       break;
+                               }
+
+                               if (freq_error < 0)
+                                       freq_error = -freq_error;
+
+                               if (freq_error < min_error) {
+                                       min_error = freq_error;
+                                       *best_clock = clock;
+                               }
+                       }
+               }
+               if (min_error == 0)
+                       break;
+       }
+
+       return min_error == 0;
 }
 
 /**
  * Returns a set of divisors for the desired target clock with the given refclk,
  * or FALSE.  Divisor values are the actual divisors for
  */
-static bool
-mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk,
-               struct oaktrail_clock_t *best_clock)
+static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit,
+                                   struct drm_crtc *crtc, int target,
+                                   int refclk, struct gma_clock_t *best_clock)
 {
-       struct oaktrail_clock_t clock;
-       const struct oaktrail_limit_t *limit = oaktrail_limit(crtc);
+       struct gma_clock_t clock;
        int err = target;
 
        memset(best_clock, 0, sizeof(*best_clock));
@@ -140,7 +201,7 @@ mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk,
                     clock.p1++) {
                        int this_err;
 
-                       oaktrail_clock(refclk, &clock);
+                       mrst_lvds_clock(refclk, &clock);
 
                        this_err = abs(clock.dot - target);
                        if (this_err < err) {
@@ -149,7 +210,6 @@ mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk,
                        }
                }
        }
-       dev_dbg(crtc->dev->dev, "mrstFindBestPLL err = %d.\n", err);
        return err != target;
 }
 
@@ -167,8 +227,10 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode)
        int pipe = gma_crtc->pipe;
        const struct psb_offset *map = &dev_priv->regmap[pipe];
        u32 temp;
+       int i;
+       int need_aux = gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ? 1 : 0;
 
-       if (pipe == 1) {
+       if (gma_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) {
                oaktrail_crtc_hdmi_dpms(crtc, mode);
                return;
        }
@@ -183,35 +245,45 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode)
        case DRM_MODE_DPMS_ON:
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
-               /* Enable the DPLL */
-               temp = REG_READ(map->dpll);
-               if ((temp & DPLL_VCO_ENABLE) == 0) {
-                       REG_WRITE(map->dpll, temp);
-                       REG_READ(map->dpll);
-                       /* Wait for the clocks to stabilize. */
-                       udelay(150);
-                       REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
-                       REG_READ(map->dpll);
-                       /* Wait for the clocks to stabilize. */
-                       udelay(150);
-                       REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
-                       REG_READ(map->dpll);
-                       /* Wait for the clocks to stabilize. */
-                       udelay(150);
-               }
-               /* Enable the pipe */
-               temp = REG_READ(map->conf);
-               if ((temp & PIPEACONF_ENABLE) == 0)
-                       REG_WRITE(map->conf, temp | PIPEACONF_ENABLE);
-               /* Enable the plane */
-               temp = REG_READ(map->cntr);
-               if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-                       REG_WRITE(map->cntr,
-                                 temp | DISPLAY_PLANE_ENABLE);
-                       /* Flush the plane changes */
-                       REG_WRITE(map->base, REG_READ(map->base));
-               }
+               for (i = 0; i <= need_aux; i++) {
+                       /* Enable the DPLL */
+                       temp = REG_READ_WITH_AUX(map->dpll, i);
+                       if ((temp & DPLL_VCO_ENABLE) == 0) {
+                               REG_WRITE_WITH_AUX(map->dpll, temp, i);
+                               REG_READ_WITH_AUX(map->dpll, i);
+                               /* Wait for the clocks to stabilize. */
+                               udelay(150);
+                               REG_WRITE_WITH_AUX(map->dpll,
+                                                  temp | DPLL_VCO_ENABLE, i);
+                               REG_READ_WITH_AUX(map->dpll, i);
+                               /* Wait for the clocks to stabilize. */
+                               udelay(150);
+                               REG_WRITE_WITH_AUX(map->dpll,
+                                                  temp | DPLL_VCO_ENABLE, i);
+                               REG_READ_WITH_AUX(map->dpll, i);
+                               /* Wait for the clocks to stabilize. */
+                               udelay(150);
+                       }
+
+                       /* Enable the pipe */
+                       temp = REG_READ_WITH_AUX(map->conf, i);
+                       if ((temp & PIPEACONF_ENABLE) == 0) {
+                               REG_WRITE_WITH_AUX(map->conf,
+                                                  temp | PIPEACONF_ENABLE, i);
+                       }
+
+                       /* Enable the plane */
+                       temp = REG_READ_WITH_AUX(map->cntr, i);
+                       if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+                               REG_WRITE_WITH_AUX(map->cntr,
+                                                  temp | DISPLAY_PLANE_ENABLE,
+                                                  i);
+                               /* Flush the plane changes */
+                               REG_WRITE_WITH_AUX(map->base,
+                                       REG_READ_WITH_AUX(map->base, i), i);
+                       }
 
+               }
                gma_crtc_load_lut(crtc);
 
                /* Give the overlay scaler a chance to enable
@@ -223,48 +295,52 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode)
                 * if it's on this pipe */
                /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
 
-               /* Disable the VGA plane that we never use */
-               REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
-               /* Disable display plane */
-               temp = REG_READ(map->cntr);
-               if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-                       REG_WRITE(map->cntr,
-                                 temp & ~DISPLAY_PLANE_ENABLE);
-                       /* Flush the plane changes */
-                       REG_WRITE(map->base, REG_READ(map->base));
-                       REG_READ(map->base);
-               }
+               for (i = 0; i <= need_aux; i++) {
+                       /* Disable the VGA plane that we never use */
+                       REG_WRITE_WITH_AUX(VGACNTRL, VGA_DISP_DISABLE, i);
+                       /* Disable display plane */
+                       temp = REG_READ_WITH_AUX(map->cntr, i);
+                       if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
+                               REG_WRITE_WITH_AUX(map->cntr,
+                                       temp & ~DISPLAY_PLANE_ENABLE, i);
+                               /* Flush the plane changes */
+                               REG_WRITE_WITH_AUX(map->base,
+                                                  REG_READ(map->base), i);
+                               REG_READ_WITH_AUX(map->base, i);
+                       }
 
-               /* Next, disable display pipes */
-               temp = REG_READ(map->conf);
-               if ((temp & PIPEACONF_ENABLE) != 0) {
-                       REG_WRITE(map->conf, temp & ~PIPEACONF_ENABLE);
-                       REG_READ(map->conf);
-               }
-               /* Wait for for the pipe disable to take effect. */
-               gma_wait_for_vblank(dev);
+                       /* Next, disable display pipes */
+                       temp = REG_READ_WITH_AUX(map->conf, i);
+                       if ((temp & PIPEACONF_ENABLE) != 0) {
+                               REG_WRITE_WITH_AUX(map->conf,
+                                                  temp & ~PIPEACONF_ENABLE, i);
+                               REG_READ_WITH_AUX(map->conf, i);
+                       }
+                       /* Wait for for the pipe disable to take effect. */
+                       gma_wait_for_vblank(dev);
+
+                       temp = REG_READ_WITH_AUX(map->dpll, i);
+                       if ((temp & DPLL_VCO_ENABLE) != 0) {
+                               REG_WRITE_WITH_AUX(map->dpll,
+                                                  temp & ~DPLL_VCO_ENABLE, i);
+                               REG_READ_WITH_AUX(map->dpll, i);
+                       }
 
-               temp = REG_READ(map->dpll);
-               if ((temp & DPLL_VCO_ENABLE) != 0) {
-                       REG_WRITE(map->dpll, temp & ~DPLL_VCO_ENABLE);
-                       REG_READ(map->dpll);
+                       /* Wait for the clocks to turn off. */
+                       udelay(150);
                }
-
-               /* Wait for the clocks to turn off. */
-               udelay(150);
                break;
        }
 
-       /*Set FIFO Watermarks*/
-       REG_WRITE(DSPARB, 0x3FFF);
-       REG_WRITE(DSPFW1, 0x3F88080A);
-       REG_WRITE(DSPFW2, 0x0b060808);
+       /* Set FIFO Watermarks (values taken from EMGD) */
+       REG_WRITE(DSPARB, 0x3f80);
+       REG_WRITE(DSPFW1, 0x3f8f0404);
+       REG_WRITE(DSPFW2, 0x04040f04);
        REG_WRITE(DSPFW3, 0x0);
-       REG_WRITE(DSPFW4, 0x08030404);
+       REG_WRITE(DSPFW4, 0x04040404);
        REG_WRITE(DSPFW5, 0x04040404);
        REG_WRITE(DSPFW6, 0x78);
-       REG_WRITE(0x70400, REG_READ(0x70400) | 0x4000);
-       /* Must write Bit 14 of the Chicken Bit Register */
+       REG_WRITE(DSPCHICKENBIT, REG_READ(DSPCHICKENBIT) | 0xc040);
 
        gma_power_end(dev);
 }
@@ -297,7 +373,8 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
        int pipe = gma_crtc->pipe;
        const struct psb_offset *map = &dev_priv->regmap[pipe];
        int refclk = 0;
-       struct oaktrail_clock_t clock;
+       struct gma_clock_t clock;
+       const struct gma_limit_t *limit;
        u32 dpll = 0, fp = 0, dspcntr, pipeconf;
        bool ok, is_sdvo = false;
        bool is_lvds = false;
@@ -306,8 +383,10 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
        struct gma_encoder *gma_encoder = NULL;
        uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN;
        struct drm_connector *connector;
+       int i;
+       int need_aux = gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ? 1 : 0;
 
-       if (pipe == 1)
+       if (gma_pipe_has_type(crtc, INTEL_OUTPUT_HDMI))
                return oaktrail_crtc_hdmi_mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
 
        if (!gma_power_begin(dev, true))
@@ -340,15 +419,17 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
        }
 
        /* Disable the VGA plane that we never use */
-       REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
+       for (i = 0; i <= need_aux; i++)
+               REG_WRITE_WITH_AUX(VGACNTRL, VGA_DISP_DISABLE, i);
 
        /* Disable the panel fitter if it was on our pipe */
        if (oaktrail_panel_fitter_pipe(dev) == pipe)
                REG_WRITE(PFIT_CONTROL, 0);
 
-       REG_WRITE(map->src,
-                 ((mode->crtc_hdisplay - 1) << 16) |
-                 (mode->crtc_vdisplay - 1));
+       for (i = 0; i <= need_aux; i++) {
+               REG_WRITE_WITH_AUX(map->src, ((mode->crtc_hdisplay - 1) << 16) |
+                                            (mode->crtc_vdisplay - 1), i);
+       }
 
        if (gma_encoder)
                drm_object_property_get_value(&connector->base,
@@ -365,35 +446,39 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
                offsetY = (adjusted_mode->crtc_vdisplay -
                           mode->crtc_vdisplay) / 2;
 
-               REG_WRITE(map->htotal, (mode->crtc_hdisplay - 1) |
-                       ((adjusted_mode->crtc_htotal - 1) << 16));
-               REG_WRITE(map->vtotal, (mode->crtc_vdisplay - 1) |
-                       ((adjusted_mode->crtc_vtotal - 1) << 16));
-               REG_WRITE(map->hblank,
-                       (adjusted_mode->crtc_hblank_start - offsetX - 1) |
-                       ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16));
-               REG_WRITE(map->hsync,
-                       (adjusted_mode->crtc_hsync_start - offsetX - 1) |
-                       ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16));
-               REG_WRITE(map->vblank,
-                       (adjusted_mode->crtc_vblank_start - offsetY - 1) |
-                       ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16));
-               REG_WRITE(map->vsync,
-                       (adjusted_mode->crtc_vsync_start - offsetY - 1) |
-                       ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16));
+               for (i = 0; i <= need_aux; i++) {
+                       REG_WRITE_WITH_AUX(map->htotal, (mode->crtc_hdisplay - 1) |
+                               ((adjusted_mode->crtc_htotal - 1) << 16), i);
+                       REG_WRITE_WITH_AUX(map->vtotal, (mode->crtc_vdisplay - 1) |
+                               ((adjusted_mode->crtc_vtotal - 1) << 16), i);
+                       REG_WRITE_WITH_AUX(map->hblank,
+                               (adjusted_mode->crtc_hblank_start - offsetX - 1) |
+                               ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16), i);
+                       REG_WRITE_WITH_AUX(map->hsync,
+                               (adjusted_mode->crtc_hsync_start - offsetX - 1) |
+                               ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16), i);
+                       REG_WRITE_WITH_AUX(map->vblank,
+                               (adjusted_mode->crtc_vblank_start - offsetY - 1) |
+                               ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16), i);
+                       REG_WRITE_WITH_AUX(map->vsync,
+                               (adjusted_mode->crtc_vsync_start - offsetY - 1) |
+                               ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16), i);
+               }
        } else {
-               REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) |
-                       ((adjusted_mode->crtc_htotal - 1) << 16));
-               REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) |
-                       ((adjusted_mode->crtc_vtotal - 1) << 16));
-               REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) |
-                       ((adjusted_mode->crtc_hblank_end - 1) << 16));
-               REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) |
-                       ((adjusted_mode->crtc_hsync_end - 1) << 16));
-               REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) |
-                       ((adjusted_mode->crtc_vblank_end - 1) << 16));
-               REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) |
-                       ((adjusted_mode->crtc_vsync_end - 1) << 16));
+               for (i = 0; i <= need_aux; i++) {
+                       REG_WRITE_WITH_AUX(map->htotal, (adjusted_mode->crtc_hdisplay - 1) |
+                               ((adjusted_mode->crtc_htotal - 1) << 16), i);
+                       REG_WRITE_WITH_AUX(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) |
+                               ((adjusted_mode->crtc_vtotal - 1) << 16), i);
+                       REG_WRITE_WITH_AUX(map->hblank, (adjusted_mode->crtc_hblank_start - 1) |
+                               ((adjusted_mode->crtc_hblank_end - 1) << 16), i);
+                       REG_WRITE_WITH_AUX(map->hsync, (adjusted_mode->crtc_hsync_start - 1) |
+                               ((adjusted_mode->crtc_hsync_end - 1) << 16), i);
+                       REG_WRITE_WITH_AUX(map->vblank, (adjusted_mode->crtc_vblank_start - 1) |
+                               ((adjusted_mode->crtc_vblank_end - 1) << 16), i);
+                       REG_WRITE_WITH_AUX(map->vsync, (adjusted_mode->crtc_vsync_start - 1) |
+                               ((adjusted_mode->crtc_vsync_end - 1) << 16), i);
+               }
        }
 
        /* Flush the plane changes */
@@ -418,21 +503,30 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
        if (is_mipi)
                goto oaktrail_crtc_mode_set_exit;
 
-       refclk = dev_priv->core_freq * 1000;
 
        dpll = 0;               /*BIT16 = 0 for 100MHz reference */
 
-       ok = mrstFindBestPLL(crtc, adjusted_mode->clock, refclk, &clock);
+       refclk = is_sdvo ? 96000 : dev_priv->core_freq * 1000;
+       limit = mrst_limit(crtc, refclk);
+       ok = limit->find_pll(limit, crtc, adjusted_mode->clock,
+                            refclk, &clock);
 
-       if (!ok) {
-               dev_dbg(dev->dev, "mrstFindBestPLL fail in oaktrail_crtc_mode_set.\n");
-       } else {
-               dev_dbg(dev->dev, "oaktrail_crtc_mode_set pixel clock = %d,"
-                        "m = %x, p1 = %x.\n", clock.dot, clock.m,
-                        clock.p1);
+       if (is_sdvo) {
+               /* Convert calculated values to register values */
+               clock.p1 = (1L << (clock.p1 - 1));
+               clock.m -= 2;
+               clock.n = (1L << (clock.n - 1));
        }
 
-       fp = oaktrail_m_converts[(clock.m - MRST_M_MIN)] << 8;
+       if (!ok)
+               DRM_ERROR("Failed to find proper PLL settings");
+
+       mrst_print_pll(&clock);
+
+       if (is_sdvo)
+               fp = clock.n << 16 | clock.m;
+       else
+               fp = oaktrail_m_converts[(clock.m - MRST_M_MIN)] << 8;
 
        dpll |= DPLL_VGA_MODE_DIS;
 
@@ -456,38 +550,43 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
 
 
        /* compute bitmask from p1 value */
-       dpll |= (1 << (clock.p1 - 2)) << 17;
+       if (is_sdvo)
+               dpll |= clock.p1 << 16; // dpll |= (1 << (clock.p1 - 1)) << 16;
+       else
+               dpll |= (1 << (clock.p1 - 2)) << 17;
 
        dpll |= DPLL_VCO_ENABLE;
 
-       mrstPrintPll("chosen", &clock);
-
        if (dpll & DPLL_VCO_ENABLE) {
-               REG_WRITE(map->fp0, fp);
-               REG_WRITE(map->dpll, dpll & ~DPLL_VCO_ENABLE);
-               REG_READ(map->dpll);
-               /* Check the DPLLA lock bit PIPEACONF[29] */
-               udelay(150);
+               for (i = 0; i <= need_aux; i++) {
+                       REG_WRITE_WITH_AUX(map->fp0, fp, i);
+                       REG_WRITE_WITH_AUX(map->dpll, dpll & ~DPLL_VCO_ENABLE, i);
+                       REG_READ_WITH_AUX(map->dpll, i);
+                       /* Check the DPLLA lock bit PIPEACONF[29] */
+                       udelay(150);
+               }
        }
 
-       REG_WRITE(map->fp0, fp);
-       REG_WRITE(map->dpll, dpll);
-       REG_READ(map->dpll);
-       /* Wait for the clocks to stabilize. */
-       udelay(150);
+       for (i = 0; i <= need_aux; i++) {
+               REG_WRITE_WITH_AUX(map->fp0, fp, i);
+               REG_WRITE_WITH_AUX(map->dpll, dpll, i);
+               REG_READ_WITH_AUX(map->dpll, i);
+               /* Wait for the clocks to stabilize. */
+               udelay(150);
 
-       /* write it again -- the BIOS does, after all */
-       REG_WRITE(map->dpll, dpll);
-       REG_READ(map->dpll);
-       /* Wait for the clocks to stabilize. */
-       udelay(150);
+               /* write it again -- the BIOS does, after all */
+               REG_WRITE_WITH_AUX(map->dpll, dpll, i);
+               REG_READ_WITH_AUX(map->dpll, i);
+               /* Wait for the clocks to stabilize. */
+               udelay(150);
 
-       REG_WRITE(map->conf, pipeconf);
-       REG_READ(map->conf);
-       gma_wait_for_vblank(dev);
+               REG_WRITE_WITH_AUX(map->conf, pipeconf, i);
+               REG_READ_WITH_AUX(map->conf, i);
+               gma_wait_for_vblank(dev);
 
-       REG_WRITE(map->cntr, dspcntr);
-       gma_wait_for_vblank(dev);
+               REG_WRITE_WITH_AUX(map->cntr, dspcntr, i);
+               gma_wait_for_vblank(dev);
+       }
 
 oaktrail_crtc_mode_set_exit:
        gma_power_end(dev);
@@ -565,3 +664,9 @@ const struct drm_crtc_helper_funcs oaktrail_helper_funcs = {
        .commit = gma_crtc_commit,
 };
 
+/* Not used yet */
+const struct gma_clock_funcs mrst_clock_funcs = {
+       .clock = mrst_lvds_clock,
+       .limit = mrst_limit,
+       .pll_is_valid = gma_pll_is_valid,
+};
index 08747fd..27d3875 100644 (file)
@@ -40,6 +40,9 @@ static int oaktrail_output_init(struct drm_device *dev)
                dev_err(dev->dev, "DSI is not supported\n");
        if (dev_priv->hdmi_priv)
                oaktrail_hdmi_init(dev, &dev_priv->mode_dev);
+
+       psb_intel_sdvo_init(dev, SDVOB);
+
        return 0;
 }
 
@@ -526,6 +529,7 @@ static int oaktrail_chip_setup(struct drm_device *dev)
                psb_intel_opregion_init(dev);
                psb_intel_init_bios(dev);
        }
+       gma_intel_setup_gmbus(dev);
        oaktrail_hdmi_setup(dev);
        return 0;
 }
@@ -534,6 +538,7 @@ static void oaktrail_teardown(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
 
+       gma_intel_teardown_gmbus(dev);
        oaktrail_hdmi_teardown(dev);
        if (!dev_priv->has_gct)
                psb_intel_destroy_bios(dev);
@@ -546,6 +551,7 @@ const struct psb_ops oaktrail_chip_ops = {
        .crtcs = 2,
        .hdmi_mask = (1 << 1),
        .lvds_mask = (1 << 0),
+       .sdvo_mask = (1 << 1),
        .cursor_needs_phys = 0,
        .sgx_offset = MRST_SGX_OFFSET,
 
index e77d721..4c17c93 100644 (file)
@@ -218,30 +218,6 @@ static const struct drm_encoder_helper_funcs oaktrail_lvds_helper_funcs = {
        .commit = oaktrail_lvds_commit,
 };
 
-static struct drm_display_mode lvds_configuration_modes[] = {
-       /* hard coded fixed mode for TPO LTPS LPJ040K001A */
-       { DRM_MODE("800x480",  DRM_MODE_TYPE_DRIVER, 33264, 800, 836,
-                  846, 1056, 0, 480, 489, 491, 525, 0, 0) },
-       /* hard coded fixed mode for LVDS 800x480 */
-       { DRM_MODE("800x480",  DRM_MODE_TYPE_DRIVER, 30994, 800, 801,
-                  802, 1024, 0, 480, 481, 482, 525, 0, 0) },
-       /* hard coded fixed mode for Samsung 480wsvga LVDS 1024x600@75 */
-       { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 53990, 1024, 1072,
-                  1104, 1184, 0, 600, 603, 604, 608, 0, 0) },
-       /* hard coded fixed mode for Samsung 480wsvga LVDS 1024x600@75 */
-       { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 53990, 1024, 1104,
-                  1136, 1184, 0, 600, 603, 604, 608, 0, 0) },
-       /* hard coded fixed mode for Sharp wsvga LVDS 1024x600 */
-       { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 48885, 1024, 1124,
-                  1204, 1312, 0, 600, 607, 610, 621, 0, 0) },
-       /* hard coded fixed mode for LVDS 1024x768 */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
-                  1184, 1344, 0, 768, 771, 777, 806, 0, 0) },
-       /* hard coded fixed mode for LVDS 1366x768 */
-       { DRM_MODE("1366x768", DRM_MODE_TYPE_DRIVER, 77500, 1366, 1430,
-                  1558, 1664, 0, 768, 769, 770, 776, 0, 0) },
-};
-
 /* Returns the panel fixed mode from configuration. */
 
 static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev,
@@ -303,10 +279,10 @@ static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev,
                        mode_dev->panel_fixed_mode =
                                drm_mode_duplicate(dev,
                                        dev_priv->lfp_lvds_vbt_mode);
-       /* Then guess */
+
+       /* If we still got no mode then bail */
        if (mode_dev->panel_fixed_mode == NULL)
-               mode_dev->panel_fixed_mode
-                       = drm_mode_duplicate(dev, &lvds_configuration_modes[2]);
+               return;
 
        drm_mode_set_name(mode_dev->panel_fixed_mode);
        drm_mode_set_crtcinfo(mode_dev->panel_fixed_mode, 0);
index 6976786..23fb33f 100644 (file)
@@ -373,6 +373,7 @@ const struct psb_ops psb_chip_ops = {
        .crtcs = 2,
        .hdmi_mask = (1 << 0),
        .lvds_mask = (1 << 1),
+       .sdvo_mask = (1 << 0),
        .cursor_needs_phys = 1,
        .sgx_offset = PSB_SGX_OFFSET,
        .chip_setup = psb_chip_setup,
index 679f953..1199180 100644 (file)
@@ -251,6 +251,12 @@ static int psb_driver_unload(struct drm_device *dev)
                        iounmap(dev_priv->sgx_reg);
                        dev_priv->sgx_reg = NULL;
                }
+               if (dev_priv->aux_reg) {
+                       iounmap(dev_priv->aux_reg);
+                       dev_priv->aux_reg = NULL;
+               }
+               if (dev_priv->aux_pdev)
+                       pci_dev_put(dev_priv->aux_pdev);
 
                /* Destroy VBT data */
                psb_intel_destroy_bios(dev);
@@ -266,7 +272,7 @@ static int psb_driver_unload(struct drm_device *dev)
 static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
 {
        struct drm_psb_private *dev_priv;
-       unsigned long resource_start;
+       unsigned long resource_start, resource_len;
        unsigned long irqflags;
        int ret = -ENOMEM;
        struct drm_connector *connector;
@@ -296,6 +302,30 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
        if (!dev_priv->sgx_reg)
                goto out_err;
 
+       if (IS_MRST(dev)) {
+               dev_priv->aux_pdev = pci_get_bus_and_slot(0, PCI_DEVFN(3, 0));
+
+               if (dev_priv->aux_pdev) {
+                       resource_start = pci_resource_start(dev_priv->aux_pdev,
+                                                           PSB_AUX_RESOURCE);
+                       resource_len = pci_resource_len(dev_priv->aux_pdev,
+                                                       PSB_AUX_RESOURCE);
+                       dev_priv->aux_reg = ioremap_nocache(resource_start,
+                                                           resource_len);
+                       if (!dev_priv->aux_reg)
+                               goto out_err;
+
+                       DRM_DEBUG_KMS("Found aux vdc");
+               } else {
+                       /* Couldn't find the aux vdc so map to primary vdc */
+                       dev_priv->aux_reg = dev_priv->vdc_reg;
+                       DRM_DEBUG_KMS("Couldn't find aux pci device");
+               }
+               dev_priv->gmbus_reg = dev_priv->aux_reg;
+       } else {
+               dev_priv->gmbus_reg = dev_priv->vdc_reg;
+       }
+
        psb_intel_opregion_setup(dev);
 
        ret = dev_priv->ops->chip_setup(dev);
index 0bab46b..b59e658 100644 (file)
@@ -45,7 +45,7 @@ enum {
 };
 
 #define IS_PSB(dev) (((dev)->pdev->device & 0xfffe) == 0x8108)
-#define IS_MRST(dev) (((dev)->pdev->device & 0xfffc) == 0x4100)
+#define IS_MRST(dev) (((dev)->pdev->device & 0xfff0) == 0x4100)
 #define IS_MFLD(dev) (((dev)->pdev->device & 0xfff8) == 0x0130)
 #define IS_CDV(dev) (((dev)->pdev->device & 0xfff0) == 0x0be0)
 
@@ -75,6 +75,7 @@ enum {
  *     PCI resource identifiers
  */
 #define PSB_MMIO_RESOURCE       0
+#define PSB_AUX_RESOURCE        0
 #define PSB_GATT_RESOURCE       2
 #define PSB_GTT_RESOURCE        3
 /*
@@ -455,6 +456,7 @@ struct psb_ops;
 
 struct drm_psb_private {
        struct drm_device *dev;
+       struct pci_dev *aux_pdev; /* Currently only used by mrst */
        const struct psb_ops *ops;
        const struct psb_offset *regmap;
        
@@ -486,6 +488,7 @@ struct drm_psb_private {
 
        uint8_t __iomem *sgx_reg;
        uint8_t __iomem *vdc_reg;
+       uint8_t __iomem *aux_reg; /* Auxillary vdc pipe regs */
        uint32_t gatt_free_offset;
 
        /*
@@ -532,6 +535,7 @@ struct drm_psb_private {
 
        /* gmbus */
        struct intel_gmbus *gmbus;
+       uint8_t __iomem *gmbus_reg;
 
        /* Used by SDVO */
        int crt_ddc_pin;
@@ -672,6 +676,7 @@ struct psb_ops {
        int sgx_offset;         /* Base offset of SGX device */
        int hdmi_mask;          /* Mask of HDMI CRTCs */
        int lvds_mask;          /* Mask of LVDS CRTCs */
+       int sdvo_mask;          /* Mask of SDVO CRTCs */
        int cursor_needs_phys;  /* If cursor base reg need physical address */
 
        /* Sub functions */
@@ -927,16 +932,58 @@ static inline uint32_t REGISTER_READ(struct drm_device *dev, uint32_t reg)
        return ioread32(dev_priv->vdc_reg + reg);
 }
 
+static inline uint32_t REGISTER_READ_AUX(struct drm_device *dev, uint32_t reg)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       return ioread32(dev_priv->aux_reg + reg);
+}
+
 #define REG_READ(reg)         REGISTER_READ(dev, (reg))
+#define REG_READ_AUX(reg)      REGISTER_READ_AUX(dev, (reg))
+
+/* Useful for post reads */
+static inline uint32_t REGISTER_READ_WITH_AUX(struct drm_device *dev,
+                                             uint32_t reg, int aux)
+{
+       uint32_t val;
+
+       if (aux)
+               val = REG_READ_AUX(reg);
+       else
+               val = REG_READ(reg);
+
+       return val;
+}
+
+#define REG_READ_WITH_AUX(reg, aux) REGISTER_READ_WITH_AUX(dev, (reg), (aux))
 
 static inline void REGISTER_WRITE(struct drm_device *dev, uint32_t reg,
-                                     uint32_t val)
+                                 uint32_t val)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
        iowrite32((val), dev_priv->vdc_reg + (reg));
 }
 
+static inline void REGISTER_WRITE_AUX(struct drm_device *dev, uint32_t reg,
+                                     uint32_t val)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       iowrite32((val), dev_priv->aux_reg + (reg));
+}
+
 #define REG_WRITE(reg, val)    REGISTER_WRITE(dev, (reg), (val))
+#define REG_WRITE_AUX(reg, val)        REGISTER_WRITE_AUX(dev, (reg), (val))
+
+static inline void REGISTER_WRITE_WITH_AUX(struct drm_device *dev, uint32_t reg,
+                                     uint32_t val, int aux)
+{
+       if (aux)
+               REG_WRITE_AUX(reg, val);
+       else
+               REG_WRITE(reg, val);
+}
+
+#define REG_WRITE_WITH_AUX(reg, val, aux) REGISTER_WRITE_WITH_AUX(dev, (reg), (val), (aux))
 
 static inline void REGISTER_WRITE16(struct drm_device *dev,
                                        uint32_t reg, uint32_t val)
index 6f01cdf..07d3a9e 100644 (file)
@@ -228,24 +228,26 @@ static void psb_intel_sdvo_write_sdvox(struct psb_intel_sdvo *psb_intel_sdvo, u3
 {
        struct drm_device *dev = psb_intel_sdvo->base.base.dev;
        u32 bval = val, cval = val;
-       int i;
+       int i, j;
+       int need_aux = IS_MRST(dev) ? 1 : 0;
 
-       if (psb_intel_sdvo->sdvo_reg == SDVOB) {
-               cval = REG_READ(SDVOC);
-       } else {
-               bval = REG_READ(SDVOB);
-       }
-       /*
-        * Write the registers twice for luck. Sometimes,
-        * writing them only once doesn't appear to 'stick'.
-        * The BIOS does this too. Yay, magic
-        */
-       for (i = 0; i < 2; i++)
-       {
-               REG_WRITE(SDVOB, bval);
-               REG_READ(SDVOB);
-               REG_WRITE(SDVOC, cval);
-               REG_READ(SDVOC);
+       for (j = 0; j <= need_aux; j++) {
+               if (psb_intel_sdvo->sdvo_reg == SDVOB)
+                       cval = REG_READ_WITH_AUX(SDVOC, j);
+               else
+                       bval = REG_READ_WITH_AUX(SDVOB, j);
+
+               /*
+               * Write the registers twice for luck. Sometimes,
+               * writing them only once doesn't appear to 'stick'.
+               * The BIOS does this too. Yay, magic
+               */
+               for (i = 0; i < 2; i++) {
+                       REG_WRITE_WITH_AUX(SDVOB, bval, j);
+                       REG_READ_WITH_AUX(SDVOB, j);
+                       REG_WRITE_WITH_AUX(SDVOC, cval, j);
+                       REG_READ_WITH_AUX(SDVOC, j);
+               }
        }
 }
 
@@ -995,6 +997,7 @@ static void psb_intel_sdvo_mode_set(struct drm_encoder *encoder,
        struct psb_intel_sdvo_dtd input_dtd;
        int pixel_multiplier = psb_intel_mode_get_pixel_multiplier(adjusted_mode);
        int rate;
+       int need_aux = IS_MRST(dev) ? 1 : 0;
 
        if (!mode)
                return;
@@ -1060,7 +1063,11 @@ static void psb_intel_sdvo_mode_set(struct drm_encoder *encoder,
                return;
 
        /* Set the SDVO control regs. */
-       sdvox = REG_READ(psb_intel_sdvo->sdvo_reg);
+       if (need_aux)
+               sdvox = REG_READ_AUX(psb_intel_sdvo->sdvo_reg);
+       else
+               sdvox = REG_READ(psb_intel_sdvo->sdvo_reg);
+
        switch (psb_intel_sdvo->sdvo_reg) {
        case SDVOB:
                sdvox &= SDVOB_PRESERVE_MASK;
@@ -1090,6 +1097,8 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
        struct drm_device *dev = encoder->dev;
        struct psb_intel_sdvo *psb_intel_sdvo = to_psb_intel_sdvo(encoder);
        u32 temp;
+       int i;
+       int need_aux = IS_MRST(dev) ? 1 : 0;
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
@@ -1108,19 +1117,27 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
                        psb_intel_sdvo_set_encoder_power_state(psb_intel_sdvo, mode);
 
                if (mode == DRM_MODE_DPMS_OFF) {
-                       temp = REG_READ(psb_intel_sdvo->sdvo_reg);
+                       if (need_aux)
+                               temp = REG_READ_AUX(psb_intel_sdvo->sdvo_reg);
+                       else
+                               temp = REG_READ(psb_intel_sdvo->sdvo_reg);
+
                        if ((temp & SDVO_ENABLE) != 0) {
                                psb_intel_sdvo_write_sdvox(psb_intel_sdvo, temp & ~SDVO_ENABLE);
                        }
                }
        } else {
                bool input1, input2;
-               int i;
                u8 status;
 
-               temp = REG_READ(psb_intel_sdvo->sdvo_reg);
+               if (need_aux)
+                       temp = REG_READ_AUX(psb_intel_sdvo->sdvo_reg);
+               else
+                       temp = REG_READ(psb_intel_sdvo->sdvo_reg);
+
                if ((temp & SDVO_ENABLE) == 0)
                        psb_intel_sdvo_write_sdvox(psb_intel_sdvo, temp | SDVO_ENABLE);
+
                for (i = 0; i < 2; i++)
                        gma_wait_for_vblank(dev);
 
index 454e186..6ed45a9 100644 (file)
@@ -586,7 +586,53 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        if (ret)
                return ret;
 
-       if (IS_VALLEYVIEW(dev)) {
+       if (INTEL_INFO(dev)->gen >= 8) {
+               int i;
+               seq_printf(m, "Master Interrupt Control:\t%08x\n",
+                          I915_READ(GEN8_MASTER_IRQ));
+
+               for (i = 0; i < 4; i++) {
+                       seq_printf(m, "GT Interrupt IMR %d:\t%08x\n",
+                                  i, I915_READ(GEN8_GT_IMR(i)));
+                       seq_printf(m, "GT Interrupt IIR %d:\t%08x\n",
+                                  i, I915_READ(GEN8_GT_IIR(i)));
+                       seq_printf(m, "GT Interrupt IER %d:\t%08x\n",
+                                  i, I915_READ(GEN8_GT_IER(i)));
+               }
+
+               for_each_pipe(i) {
+                       seq_printf(m, "Pipe %c IMR:\t%08x\n",
+                                  pipe_name(i),
+                                  I915_READ(GEN8_DE_PIPE_IMR(i)));
+                       seq_printf(m, "Pipe %c IIR:\t%08x\n",
+                                  pipe_name(i),
+                                  I915_READ(GEN8_DE_PIPE_IIR(i)));
+                       seq_printf(m, "Pipe %c IER:\t%08x\n",
+                                  pipe_name(i),
+                                  I915_READ(GEN8_DE_PIPE_IER(i)));
+               }
+
+               seq_printf(m, "Display Engine port interrupt mask:\t%08x\n",
+                          I915_READ(GEN8_DE_PORT_IMR));
+               seq_printf(m, "Display Engine port interrupt identity:\t%08x\n",
+                          I915_READ(GEN8_DE_PORT_IIR));
+               seq_printf(m, "Display Engine port interrupt enable:\t%08x\n",
+                          I915_READ(GEN8_DE_PORT_IER));
+
+               seq_printf(m, "Display Engine misc interrupt mask:\t%08x\n",
+                          I915_READ(GEN8_DE_MISC_IMR));
+               seq_printf(m, "Display Engine misc interrupt identity:\t%08x\n",
+                          I915_READ(GEN8_DE_MISC_IIR));
+               seq_printf(m, "Display Engine misc interrupt enable:\t%08x\n",
+                          I915_READ(GEN8_DE_MISC_IER));
+
+               seq_printf(m, "PCU interrupt mask:\t%08x\n",
+                          I915_READ(GEN8_PCU_IMR));
+               seq_printf(m, "PCU interrupt identity:\t%08x\n",
+                          I915_READ(GEN8_PCU_IIR));
+               seq_printf(m, "PCU interrupt enable:\t%08x\n",
+                          I915_READ(GEN8_PCU_IER));
+       } else if (IS_VALLEYVIEW(dev)) {
                seq_printf(m, "Display IER:\t%08x\n",
                           I915_READ(VLV_IER));
                seq_printf(m, "Display IIR:\t%08x\n",
@@ -658,7 +704,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        seq_printf(m, "Interrupts received: %d\n",
                   atomic_read(&dev_priv->irq_received));
        for_each_ring(ring, dev_priv, i) {
-               if (IS_GEN6(dev) || IS_GEN7(dev)) {
+               if (INTEL_INFO(dev)->gen >= 6) {
                        seq_printf(m,
                                   "Graphics Interrupt mask (%s):       %08x\n",
                                   ring->name, I915_READ_IMR(ring));
@@ -1577,7 +1623,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
                           I915_READ16(C0DRB3));
                seq_printf(m, "C1DRB3 = 0x%04x\n",
                           I915_READ16(C1DRB3));
-       } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+       } else if (INTEL_INFO(dev)->gen >= 6) {
                seq_printf(m, "MAD_DIMM_C0 = 0x%08x\n",
                           I915_READ(MAD_DIMM_C0));
                seq_printf(m, "MAD_DIMM_C1 = 0x%08x\n",
@@ -1586,8 +1632,12 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
                           I915_READ(MAD_DIMM_C2));
                seq_printf(m, "TILECTL = 0x%08x\n",
                           I915_READ(TILECTL));
-               seq_printf(m, "ARB_MODE = 0x%08x\n",
-                          I915_READ(ARB_MODE));
+               if (IS_GEN8(dev))
+                       seq_printf(m, "GAMTARBMODE = 0x%08x\n",
+                                  I915_READ(GAMTARBMODE));
+               else
+                       seq_printf(m, "ARB_MODE = 0x%08x\n",
+                                  I915_READ(ARB_MODE));
                seq_printf(m, "DISP_ARB_CTL = 0x%08x\n",
                           I915_READ(DISP_ARB_CTL));
        }
@@ -1596,18 +1646,37 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
        return 0;
 }
 
-static int i915_ppgtt_info(struct seq_file *m, void *data)
+static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
 {
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
-       int i, ret;
+       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+       int unused, i;
 
+       if (!ppgtt)
+               return;
+
+       seq_printf(m, "Page directories: %d\n", ppgtt->num_pd_pages);
+       seq_printf(m, "Page tables: %d\n", ppgtt->num_pt_pages);
+       for_each_ring(ring, dev_priv, unused) {
+               seq_printf(m, "%s\n", ring->name);
+               for (i = 0; i < 4; i++) {
+                       u32 offset = 0x270 + i * 8;
+                       u64 pdp = I915_READ(ring->mmio_base + offset + 4);
+                       pdp <<= 32;
+                       pdp |= I915_READ(ring->mmio_base + offset);
+                       for (i = 0; i < 4; i++)
+                               seq_printf(m, "\tPDP%d 0x%016llx\n", i, pdp);
+               }
+       }
+}
+
+static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       int i;
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
-       if (ret)
-               return ret;
        if (INTEL_INFO(dev)->gen == 6)
                seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(GFX_MODE));
 
@@ -1626,6 +1695,22 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
                seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset);
        }
        seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK));
+}
+
+static int i915_ppgtt_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+
+       int ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       if (INTEL_INFO(dev)->gen >= 8)
+               gen8_ppgtt_info(m, dev);
+       else if (INTEL_INFO(dev)->gen >= 6)
+               gen6_ppgtt_info(m, dev);
+
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -1772,13 +1857,18 @@ static int i915_pipe_crc_open(struct inode *inode, struct file *filep)
        struct drm_i915_private *dev_priv = info->dev->dev_private;
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe];
 
-       if (!atomic_dec_and_test(&pipe_crc->available)) {
-               atomic_inc(&pipe_crc->available);
+       spin_lock_irq(&pipe_crc->lock);
+
+       if (pipe_crc->opened) {
+               spin_unlock_irq(&pipe_crc->lock);
                return -EBUSY; /* already open */
        }
 
+       pipe_crc->opened = true;
        filep->private_data = inode->i_private;
 
+       spin_unlock_irq(&pipe_crc->lock);
+
        return 0;
 }
 
@@ -1788,7 +1878,9 @@ static int i915_pipe_crc_release(struct inode *inode, struct file *filep)
        struct drm_i915_private *dev_priv = info->dev->dev_private;
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe];
 
-       atomic_inc(&pipe_crc->available); /* release the device */
+       spin_lock_irq(&pipe_crc->lock);
+       pipe_crc->opened = false;
+       spin_unlock_irq(&pipe_crc->lock);
 
        return 0;
 }
@@ -1800,12 +1892,9 @@ static int i915_pipe_crc_release(struct inode *inode, struct file *filep)
 
 static int pipe_crc_data_count(struct intel_pipe_crc *pipe_crc)
 {
-       int head, tail;
-
-       head = atomic_read(&pipe_crc->head);
-       tail = atomic_read(&pipe_crc->tail);
-
-       return CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR);
+       assert_spin_locked(&pipe_crc->lock);
+       return CIRC_CNT(pipe_crc->head, pipe_crc->tail,
+                       INTEL_PIPE_CRC_ENTRIES_NR);
 }
 
 static ssize_t
@@ -1831,20 +1920,30 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count,
                return 0;
 
        /* nothing to read */
+       spin_lock_irq(&pipe_crc->lock);
        while (pipe_crc_data_count(pipe_crc) == 0) {
-               if (filep->f_flags & O_NONBLOCK)
+               int ret;
+
+               if (filep->f_flags & O_NONBLOCK) {
+                       spin_unlock_irq(&pipe_crc->lock);
                        return -EAGAIN;
+               }
 
-               if (wait_event_interruptible(pipe_crc->wq,
-                                            pipe_crc_data_count(pipe_crc)))
-                        return -ERESTARTSYS;
+               ret = wait_event_interruptible_lock_irq(pipe_crc->wq,
+                               pipe_crc_data_count(pipe_crc), pipe_crc->lock);
+               if (ret) {
+                       spin_unlock_irq(&pipe_crc->lock);
+                       return ret;
+               }
        }
 
        /* We now have one or more entries to read */
-       head = atomic_read(&pipe_crc->head);
-       tail = atomic_read(&pipe_crc->tail);
+       head = pipe_crc->head;
+       tail = pipe_crc->tail;
        n_entries = min((size_t)CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR),
                        count / PIPE_CRC_LINE_LEN);
+       spin_unlock_irq(&pipe_crc->lock);
+
        bytes_read = 0;
        n = 0;
        do {
@@ -1864,10 +1963,13 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count,
 
                BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR);
                tail = (tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
-               atomic_set(&pipe_crc->tail, tail);
                n++;
        } while (--n_entries);
 
+       spin_lock_irq(&pipe_crc->lock);
+       pipe_crc->tail = tail;
+       spin_unlock_irq(&pipe_crc->lock);
+
        return bytes_read;
 }
 
@@ -1915,6 +2017,11 @@ static const char * const pipe_crc_sources[] = {
        "plane2",
        "pf",
        "pipe",
+       "TV",
+       "DP-B",
+       "DP-C",
+       "DP-D",
+       "auto",
 };
 
 static const char *pipe_crc_source_name(enum intel_pipe_crc_source source)
@@ -1943,33 +2050,279 @@ static int display_crc_ctl_open(struct inode *inode, struct file *file)
        return single_open(file, display_crc_ctl_show, dev);
 }
 
-static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source source,
+static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
+                                uint32_t *val)
+{
+       if (*source == INTEL_PIPE_CRC_SOURCE_AUTO)
+               *source = INTEL_PIPE_CRC_SOURCE_PIPE;
+
+       switch (*source) {
+       case INTEL_PIPE_CRC_SOURCE_PIPE:
+               *val = PIPE_CRC_ENABLE | PIPE_CRC_INCLUDE_BORDER_I8XX;
+               break;
+       case INTEL_PIPE_CRC_SOURCE_NONE:
+               *val = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe,
+                                    enum intel_pipe_crc_source *source)
+{
+       struct intel_encoder *encoder;
+       struct intel_crtc *crtc;
+       struct intel_digital_port *dig_port;
+       int ret = 0;
+
+       *source = INTEL_PIPE_CRC_SOURCE_PIPE;
+
+       mutex_lock(&dev->mode_config.mutex);
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               if (!encoder->base.crtc)
+                       continue;
+
+               crtc = to_intel_crtc(encoder->base.crtc);
+
+               if (crtc->pipe != pipe)
+                       continue;
+
+               switch (encoder->type) {
+               case INTEL_OUTPUT_TVOUT:
+                       *source = INTEL_PIPE_CRC_SOURCE_TV;
+                       break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+               case INTEL_OUTPUT_EDP:
+                       dig_port = enc_to_dig_port(&encoder->base);
+                       switch (dig_port->port) {
+                       case PORT_B:
+                               *source = INTEL_PIPE_CRC_SOURCE_DP_B;
+                               break;
+                       case PORT_C:
+                               *source = INTEL_PIPE_CRC_SOURCE_DP_C;
+                               break;
+                       case PORT_D:
+                               *source = INTEL_PIPE_CRC_SOURCE_DP_D;
+                               break;
+                       default:
+                               WARN(1, "nonexisting DP port %c\n",
+                                    port_name(dig_port->port));
+                               break;
+                       }
+                       break;
+               }
+       }
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
+static int vlv_pipe_crc_ctl_reg(struct drm_device *dev,
+                               enum pipe pipe,
+                               enum intel_pipe_crc_source *source,
+                               uint32_t *val)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       bool need_stable_symbols = false;
+
+       if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) {
+               int ret = i9xx_pipe_crc_auto_source(dev, pipe, source);
+               if (ret)
+                       return ret;
+       }
+
+       switch (*source) {
+       case INTEL_PIPE_CRC_SOURCE_PIPE:
+               *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PIPE_VLV;
+               break;
+       case INTEL_PIPE_CRC_SOURCE_DP_B:
+               *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_B_VLV;
+               need_stable_symbols = true;
+               break;
+       case INTEL_PIPE_CRC_SOURCE_DP_C:
+               *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_C_VLV;
+               need_stable_symbols = true;
+               break;
+       case INTEL_PIPE_CRC_SOURCE_NONE:
+               *val = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * When the pipe CRC tap point is after the transcoders we need
+        * to tweak symbol-level features to produce a deterministic series of
+        * symbols for a given frame. We need to reset those features only once
+        * a frame (instead of every nth symbol):
+        *   - DC-balance: used to ensure a better clock recovery from the data
+        *     link (SDVO)
+        *   - DisplayPort scrambling: used for EMI reduction
+        */
+       if (need_stable_symbols) {
+               uint32_t tmp = I915_READ(PORT_DFT2_G4X);
+
+               WARN_ON(!IS_G4X(dev));
+
+               tmp |= DC_BALANCE_RESET_VLV;
+               if (pipe == PIPE_A)
+                       tmp |= PIPE_A_SCRAMBLE_RESET;
+               else
+                       tmp |= PIPE_B_SCRAMBLE_RESET;
+
+               I915_WRITE(PORT_DFT2_G4X, tmp);
+       }
+
+       return 0;
+}
+
+static int i9xx_pipe_crc_ctl_reg(struct drm_device *dev,
+                                enum pipe pipe,
+                                enum intel_pipe_crc_source *source,
+                                uint32_t *val)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       bool need_stable_symbols = false;
+
+       if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) {
+               int ret = i9xx_pipe_crc_auto_source(dev, pipe, source);
+               if (ret)
+                       return ret;
+       }
+
+       switch (*source) {
+       case INTEL_PIPE_CRC_SOURCE_PIPE:
+               *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PIPE_I9XX;
+               break;
+       case INTEL_PIPE_CRC_SOURCE_TV:
+               if (!SUPPORTS_TV(dev))
+                       return -EINVAL;
+               *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_TV_PRE;
+               break;
+       case INTEL_PIPE_CRC_SOURCE_DP_B:
+               if (!IS_G4X(dev))
+                       return -EINVAL;
+               *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_B_G4X;
+               need_stable_symbols = true;
+               break;
+       case INTEL_PIPE_CRC_SOURCE_DP_C:
+               if (!IS_G4X(dev))
+                       return -EINVAL;
+               *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_C_G4X;
+               need_stable_symbols = true;
+               break;
+       case INTEL_PIPE_CRC_SOURCE_DP_D:
+               if (!IS_G4X(dev))
+                       return -EINVAL;
+               *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_D_G4X;
+               need_stable_symbols = true;
+               break;
+       case INTEL_PIPE_CRC_SOURCE_NONE:
+               *val = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * When the pipe CRC tap point is after the transcoders we need
+        * to tweak symbol-level features to produce a deterministic series of
+        * symbols for a given frame. We need to reset those features only once
+        * a frame (instead of every nth symbol):
+        *   - DC-balance: used to ensure a better clock recovery from the data
+        *     link (SDVO)
+        *   - DisplayPort scrambling: used for EMI reduction
+        */
+       if (need_stable_symbols) {
+               uint32_t tmp = I915_READ(PORT_DFT2_G4X);
+
+               WARN_ON(!IS_G4X(dev));
+
+               I915_WRITE(PORT_DFT_I9XX,
+                          I915_READ(PORT_DFT_I9XX) | DC_BALANCE_RESET);
+
+               if (pipe == PIPE_A)
+                       tmp |= PIPE_A_SCRAMBLE_RESET;
+               else
+                       tmp |= PIPE_B_SCRAMBLE_RESET;
+
+               I915_WRITE(PORT_DFT2_G4X, tmp);
+       }
+
+       return 0;
+}
+
+static void vlv_undo_pipe_scramble_reset(struct drm_device *dev,
+                                        enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t tmp = I915_READ(PORT_DFT2_G4X);
+
+       if (pipe == PIPE_A)
+               tmp &= ~PIPE_A_SCRAMBLE_RESET;
+       else
+               tmp &= ~PIPE_B_SCRAMBLE_RESET;
+       if (!(tmp & PIPE_SCRAMBLE_RESET_MASK))
+               tmp &= ~DC_BALANCE_RESET_VLV;
+       I915_WRITE(PORT_DFT2_G4X, tmp);
+
+}
+
+static void g4x_undo_pipe_scramble_reset(struct drm_device *dev,
+                                        enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t tmp = I915_READ(PORT_DFT2_G4X);
+
+       if (pipe == PIPE_A)
+               tmp &= ~PIPE_A_SCRAMBLE_RESET;
+       else
+               tmp &= ~PIPE_B_SCRAMBLE_RESET;
+       I915_WRITE(PORT_DFT2_G4X, tmp);
+
+       if (!(tmp & PIPE_SCRAMBLE_RESET_MASK)) {
+               I915_WRITE(PORT_DFT_I9XX,
+                          I915_READ(PORT_DFT_I9XX) & ~DC_BALANCE_RESET);
+       }
+}
+
+static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
                                uint32_t *val)
 {
-       switch (source) {
+       if (*source == INTEL_PIPE_CRC_SOURCE_AUTO)
+               *source = INTEL_PIPE_CRC_SOURCE_PIPE;
+
+       switch (*source) {
        case INTEL_PIPE_CRC_SOURCE_PLANE1:
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PRIMARY_ILK;
                break;
        case INTEL_PIPE_CRC_SOURCE_PLANE2:
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_ILK;
                break;
-       case INTEL_PIPE_CRC_SOURCE_PF:
-               return -EINVAL;
        case INTEL_PIPE_CRC_SOURCE_PIPE:
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PIPE_ILK;
                break;
-       default:
+       case INTEL_PIPE_CRC_SOURCE_NONE:
                *val = 0;
                break;
+       default:
+               return -EINVAL;
        }
 
        return 0;
 }
 
-static int ivb_pipe_crc_ctl_reg(enum intel_pipe_crc_source source,
+static int ivb_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
                                uint32_t *val)
 {
-       switch (source) {
+       if (*source == INTEL_PIPE_CRC_SOURCE_AUTO)
+               *source = INTEL_PIPE_CRC_SOURCE_PF;
+
+       switch (*source) {
        case INTEL_PIPE_CRC_SOURCE_PLANE1:
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PRIMARY_IVB;
                break;
@@ -1979,11 +2332,11 @@ static int ivb_pipe_crc_ctl_reg(enum intel_pipe_crc_source source,
        case INTEL_PIPE_CRC_SOURCE_PF:
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB;
                break;
-       case INTEL_PIPE_CRC_SOURCE_PIPE:
-               return -EINVAL;
-       default:
+       case INTEL_PIPE_CRC_SOURCE_NONE:
                *val = 0;
                break;
+       default:
+               return -EINVAL;
        }
 
        return 0;
@@ -1997,9 +2350,6 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
        u32 val;
        int ret;
 
-       if (!(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev)))
-               return -ENODEV;
-
        if (pipe_crc->source == source)
                return 0;
 
@@ -2007,10 +2357,16 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
        if (pipe_crc->source && source)
                return -EINVAL;
 
-       if (IS_GEN5(dev) || IS_GEN6(dev))
-               ret = ilk_pipe_crc_ctl_reg(source, &val);
+       if (IS_GEN2(dev))
+               ret = i8xx_pipe_crc_ctl_reg(&source, &val);
+       else if (INTEL_INFO(dev)->gen < 5)
+               ret = i9xx_pipe_crc_ctl_reg(dev, pipe, &source, &val);
+       else if (IS_VALLEYVIEW(dev))
+               ret = vlv_pipe_crc_ctl_reg(dev,pipe, &source, &val);
+       else if (IS_GEN5(dev) || IS_GEN6(dev))
+               ret = ilk_pipe_crc_ctl_reg(&source, &val);
        else
-               ret = ivb_pipe_crc_ctl_reg(source, &val);
+               ret = ivb_pipe_crc_ctl_reg(&source, &val);
 
        if (ret != 0)
                return ret;
@@ -2026,8 +2382,10 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
                if (!pipe_crc->entries)
                        return -ENOMEM;
 
-               atomic_set(&pipe_crc->head, 0);
-               atomic_set(&pipe_crc->tail, 0);
+               spin_lock_irq(&pipe_crc->lock);
+               pipe_crc->head = 0;
+               pipe_crc->tail = 0;
+               spin_unlock_irq(&pipe_crc->lock);
        }
 
        pipe_crc->source = source;
@@ -2037,13 +2395,24 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
 
        /* real source -> none transition */
        if (source == INTEL_PIPE_CRC_SOURCE_NONE) {
+               struct intel_pipe_crc_entry *entries;
+
                DRM_DEBUG_DRIVER("stopping CRCs for pipe %c\n",
                                 pipe_name(pipe));
 
                intel_wait_for_vblank(dev, pipe);
 
-               kfree(pipe_crc->entries);
+               spin_lock_irq(&pipe_crc->lock);
+               entries = pipe_crc->entries;
                pipe_crc->entries = NULL;
+               spin_unlock_irq(&pipe_crc->lock);
+
+               kfree(entries);
+
+               if (IS_G4X(dev))
+                       g4x_undo_pipe_scramble_reset(dev, pipe);
+               else if (IS_VALLEYVIEW(dev))
+                       vlv_undo_pipe_scramble_reset(dev, pipe);
        }
 
        return 0;
@@ -2738,7 +3107,8 @@ void intel_display_crc_init(struct drm_device *dev)
        for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) {
                struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[i];
 
-               atomic_set(&pipe_crc->available, 1);
+               pipe_crc->opened = false;
+               spin_lock_init(&pipe_crc->lock);
                init_waitqueue_head(&pipe_crc->wq);
        }
 }
index 4378866..0cab2d0 100644 (file)
@@ -1290,12 +1290,9 @@ static int i915_load_modeset_init(struct drm_device *dev)
         * then we do not take part in VGA arbitration and the
         * vga_client_register() fails with -ENODEV.
         */
-       if (!HAS_PCH_SPLIT(dev)) {
-               ret = vga_client_register(dev->pdev, dev, NULL,
-                                         i915_vga_set_decode);
-               if (ret && ret != -ENODEV)
-                       goto out;
-       }
+       ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
+       if (ret && ret != -ENODEV)
+               goto out;
 
        intel_register_dsm_handler();
 
@@ -1314,10 +1311,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                goto cleanup_gem_stolen;
 
-       intel_init_power_well(dev);
-
-       /* Keep VGA alive until i915_disable_vga_mem() */
-       intel_display_power_get(dev, POWER_DOMAIN_VGA);
+       intel_power_domains_init_hw(dev);
 
        /* Important: The output setup functions called by modeset_init need
         * working irqs for e.g. gmbus and dp aux transfers. */
@@ -1358,13 +1352,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
         */
        intel_fbdev_initial_config(dev);
 
-       /*
-        * Must do this after fbcon init so that
-        * vgacon_save_screen() works during the handover.
-        */
-       i915_disable_vga_mem(dev);
-       intel_display_power_put(dev, POWER_DOMAIN_VGA);
-
        /* Only enable hotplug handling once the fbdev is fully set up. */
        dev_priv->enable_hotplug_processing = true;
 
@@ -1653,7 +1640,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        }
 
        if (HAS_POWER_WELL(dev))
-               i915_init_power_well(dev);
+               intel_power_domains_init(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                ret = i915_load_modeset_init(dev);
@@ -1681,7 +1668,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
 out_power_well:
        if (HAS_POWER_WELL(dev))
-               i915_remove_power_well(dev);
+               intel_power_domains_remove(dev);
        drm_vblank_cleanup(dev);
 out_gem_unload:
        if (dev_priv->mm.inactive_shrinker.scan_objects)
@@ -1723,8 +1710,8 @@ int i915_driver_unload(struct drm_device *dev)
                /* The i915.ko module is still not prepared to be loaded when
                 * the power well is not enabled, so just enable it in case
                 * we're going to unload/reload. */
-               intel_set_power_well(dev, true);
-               i915_remove_power_well(dev);
+               intel_display_set_init_power(dev, true);
+               intel_power_domains_remove(dev);
        }
 
        i915_teardown_sysfs(dev);
index 1060a96..989be12 100644 (file)
@@ -336,6 +336,24 @@ static const struct intel_device_info intel_haswell_m_info = {
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
 };
 
+static const struct intel_device_info intel_broadwell_d_info = {
+       .is_preliminary = 1,
+       .gen = 8, .num_pipes = 3,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
+       .has_llc = 1,
+       .has_ddi = 1,
+};
+
+static const struct intel_device_info intel_broadwell_m_info = {
+       .is_preliminary = 1,
+       .gen = 8, .is_mobile = 1, .num_pipes = 3,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
+       .has_llc = 1,
+       .has_ddi = 1,
+};
+
 /*
  * Make sure any device matches here are from most specific to most
  * general.  For example, since the Quanta match is based on the subsystem
@@ -367,7 +385,9 @@ static const struct intel_device_info intel_haswell_m_info = {
        INTEL_HSW_D_IDS(&intel_haswell_d_info), \
        INTEL_HSW_M_IDS(&intel_haswell_m_info), \
        INTEL_VLV_M_IDS(&intel_valleyview_m_info),      \
-       INTEL_VLV_D_IDS(&intel_valleyview_d_info)
+       INTEL_VLV_D_IDS(&intel_valleyview_d_info),      \
+       INTEL_BDW_M_IDS(&intel_broadwell_m_info),       \
+       INTEL_BDW_D_IDS(&intel_broadwell_d_info)
 
 static const struct pci_device_id pciidlist[] = {              /* aka */
        INTEL_PCI_IDS,
@@ -428,6 +448,12 @@ void intel_detect_pch(struct drm_device *dev)
                                DRM_DEBUG_KMS("Found LynxPoint PCH\n");
                                WARN_ON(!IS_HASWELL(dev));
                                WARN_ON(IS_ULT(dev));
+                       } else if (IS_BROADWELL(dev)) {
+                               dev_priv->pch_type = PCH_LPT;
+                               dev_priv->pch_id =
+                                       INTEL_PCH_LPT_LP_DEVICE_ID_TYPE;
+                               DRM_DEBUG_KMS("This is Broadwell, assuming "
+                                             "LynxPoint LP PCH\n");
                        } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_LPT;
                                DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
@@ -452,6 +478,12 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen < 6)
                return 0;
 
+       /* Until we get further testing... */
+       if (IS_GEN8(dev)) {
+               WARN_ON(!i915_preliminary_hw_support);
+               return 0;
+       }
+
        if (i915_semaphores >= 0)
                return i915_semaphores;
 
@@ -477,7 +509,7 @@ static int i915_drm_freeze(struct drm_device *dev)
        /* We do a lot of poking in a lot of registers, make sure they work
         * properly. */
        hsw_disable_package_c8(dev_priv);
-       intel_set_power_well(dev, true);
+       intel_display_set_init_power(dev, true);
 
        drm_kms_helper_poll_disable(dev);
 
@@ -508,6 +540,8 @@ static int i915_drm_freeze(struct drm_device *dev)
                intel_modeset_suspend_hw(dev);
        }
 
+       i915_gem_suspend_gtt_mappings(dev);
+
        i915_save_state(dev);
 
        intel_opregion_fini(dev);
@@ -595,7 +629,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
                mutex_unlock(&dev->struct_mutex);
        }
 
-       intel_init_power_well(dev);
+       intel_power_domains_init_hw(dev);
 
        i915_restore_state(dev);
        intel_opregion_setup(dev);
@@ -656,6 +690,9 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
 
 static int i915_drm_thaw(struct drm_device *dev)
 {
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               i915_check_and_clear_faults(dev);
+
        return __i915_drm_thaw(dev, true);
 }
 
index 2ea33ee..8600c31 100644 (file)
@@ -54,6 +54,7 @@
 #define DRIVER_DATE            "20080730"
 
 enum pipe {
+       INVALID_PIPE = -1,
        PIPE_A = 0,
        PIPE_B,
        PIPE_C,
@@ -98,14 +99,29 @@ enum intel_display_power_domain {
        POWER_DOMAIN_TRANSCODER_A,
        POWER_DOMAIN_TRANSCODER_B,
        POWER_DOMAIN_TRANSCODER_C,
-       POWER_DOMAIN_TRANSCODER_EDP = POWER_DOMAIN_TRANSCODER_A + 0xF,
+       POWER_DOMAIN_TRANSCODER_EDP,
        POWER_DOMAIN_VGA,
+       POWER_DOMAIN_INIT,
+
+       POWER_DOMAIN_NUM,
 };
 
+#define POWER_DOMAIN_MASK (BIT(POWER_DOMAIN_NUM) - 1)
+
 #define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A)
 #define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \
                ((pipe) + POWER_DOMAIN_PIPE_A_PANEL_FITTER)
-#define POWER_DOMAIN_TRANSCODER(tran) ((tran) + POWER_DOMAIN_TRANSCODER_A)
+#define POWER_DOMAIN_TRANSCODER(tran) \
+       ((tran) == TRANSCODER_EDP ? POWER_DOMAIN_TRANSCODER_EDP : \
+        (tran) + POWER_DOMAIN_TRANSCODER_A)
+
+#define HSW_ALWAYS_ON_POWER_DOMAINS (          \
+       BIT(POWER_DOMAIN_PIPE_A) |              \
+       BIT(POWER_DOMAIN_TRANSCODER_EDP))
+#define BDW_ALWAYS_ON_POWER_DOMAINS (          \
+       BIT(POWER_DOMAIN_PIPE_A) |              \
+       BIT(POWER_DOMAIN_TRANSCODER_EDP) |      \
+       BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER))
 
 enum hpd_pin {
        HPD_NONE = 0,
@@ -231,6 +247,7 @@ struct intel_opregion {
        struct opregion_asle __iomem *asle;
        void __iomem *vbt;
        u32 __iomem *lid_state;
+       struct work_struct asle_work;
 };
 #define OPREGION_SIZE            (8*1024)
 
@@ -288,6 +305,7 @@ struct drm_i915_error_state {
        u32 cpu_ring_tail[I915_NUM_RINGS];
        u32 error; /* gen6+ */
        u32 err_int; /* gen7 */
+       u32 bbstate[I915_NUM_RINGS];
        u32 instpm[I915_NUM_RINGS];
        u32 instps[I915_NUM_RINGS];
        u32 extra_instdone[I915_NUM_INSTDONE_REG];
@@ -516,10 +534,12 @@ struct i915_address_space {
 
        /* FIXME: Need a more generic return type */
        gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr,
-                                    enum i915_cache_level level);
+                                    enum i915_cache_level level,
+                                    bool valid); /* Create a valid PTE */
        void (*clear_range)(struct i915_address_space *vm,
                            unsigned int first_entry,
-                           unsigned int num_entries);
+                           unsigned int num_entries,
+                           bool use_scratch);
        void (*insert_entries)(struct i915_address_space *vm,
                               struct sg_table *st,
                               unsigned int first_entry,
@@ -559,10 +579,21 @@ struct i915_gtt {
 struct i915_hw_ppgtt {
        struct i915_address_space base;
        unsigned num_pd_entries;
-       struct page **pt_pages;
-       uint32_t pd_offset;
-       dma_addr_t *pt_dma_addr;
-
+       union {
+               struct page **pt_pages;
+               struct page *gen8_pt_pages;
+       };
+       struct page *pd_pages;
+       int num_pd_pages;
+       int num_pt_pages;
+       union {
+               uint32_t pd_offset;
+               dma_addr_t pd_dma_addr[4];
+       };
+       union {
+               dma_addr_t *pt_dma_addr;
+               dma_addr_t *gen8_pt_dma_addr[4];
+       };
        int (*enable)(struct drm_device *dev);
 };
 
@@ -729,6 +760,9 @@ struct i915_suspend_saved_registers {
        u32 saveBLC_HIST_CTL;
        u32 saveBLC_PWM_CTL;
        u32 saveBLC_PWM_CTL2;
+       u32 saveBLC_HIST_CTL_B;
+       u32 saveBLC_PWM_CTL_B;
+       u32 saveBLC_PWM_CTL2_B;
        u32 saveBLC_CPU_PWM_CTL;
        u32 saveBLC_CPU_PWM_CTL2;
        u32 saveFPB0;
@@ -898,11 +932,21 @@ struct intel_ilk_power_mgmt {
 
 /* Power well structure for haswell */
 struct i915_power_well {
-       struct drm_device *device;
-       spinlock_t lock;
        /* power well enable/disable usage count */
        int count;
-       int i915_request;
+};
+
+#define I915_MAX_POWER_WELLS 1
+
+struct i915_power_domains {
+       /*
+        * Power wells needed for initialization at driver init and suspend
+        * time are on. They are kept on until after the first modeset.
+        */
+       bool init_power_on;
+
+       struct mutex lock;
+       struct i915_power_well power_wells[I915_MAX_POWER_WELLS];
 };
 
 struct i915_dri1_state {
@@ -1224,6 +1268,12 @@ enum intel_pipe_crc_source {
        INTEL_PIPE_CRC_SOURCE_PLANE2,
        INTEL_PIPE_CRC_SOURCE_PF,
        INTEL_PIPE_CRC_SOURCE_PIPE,
+       /* TV/DP on pre-gen5/vlv can't use the pipe source. */
+       INTEL_PIPE_CRC_SOURCE_TV,
+       INTEL_PIPE_CRC_SOURCE_DP_B,
+       INTEL_PIPE_CRC_SOURCE_DP_C,
+       INTEL_PIPE_CRC_SOURCE_DP_D,
+       INTEL_PIPE_CRC_SOURCE_AUTO,
        INTEL_PIPE_CRC_SOURCE_MAX,
 };
 
@@ -1234,10 +1284,11 @@ struct intel_pipe_crc_entry {
 
 #define INTEL_PIPE_CRC_ENTRIES_NR      128
 struct intel_pipe_crc {
-       atomic_t available;             /* exclusive access to the device */
+       spinlock_t lock;
+       bool opened;            /* exclusive access to the result file */
        struct intel_pipe_crc_entry *entries;
        enum intel_pipe_crc_source source;
-       atomic_t head, tail;
+       int head, tail;
        wait_queue_head_t wq;
 };
 
@@ -1286,7 +1337,10 @@ typedef struct drm_i915_private {
        struct mutex dpio_lock;
 
        /** Cached value of IMR to avoid reads in updating the bitfield */
-       u32 irq_mask;
+       union {
+               u32 irq_mask;
+               u32 de_irq_mask[I915_MAX_PIPES];
+       };
        u32 gt_irq_mask;
        u32 pm_irq_mask;
 
@@ -1365,6 +1419,10 @@ typedef struct drm_i915_private {
        struct drm_crtc *pipe_to_crtc_mapping[3];
        wait_queue_head_t pending_flip_queue;
 
+#ifdef CONFIG_DEBUG_FS
+       struct intel_pipe_crc pipe_crc[I915_MAX_PIPES];
+#endif
+
        int num_shared_dpll;
        struct intel_shared_dpll shared_dplls[I915_NUM_PLLS];
        struct intel_ddi_plls ddi_plls;
@@ -1390,8 +1448,7 @@ typedef struct drm_i915_private {
         * mchdev_lock in intel_pm.c */
        struct intel_ilk_power_mgmt ips;
 
-       /* Haswell power well */
-       struct i915_power_well power_well;
+       struct i915_power_domains power_domains;
 
        struct i915_psr psr;
 
@@ -1445,10 +1502,6 @@ typedef struct drm_i915_private {
        struct i915_dri1_state dri1;
        /* Old ums support infrastructure, same warning applies. */
        struct i915_ums_state ums;
-
-#ifdef CONFIG_DEBUG_FS
-       struct intel_pipe_crc pipe_crc[I915_MAX_PIPES];
-#endif
 } drm_i915_private_t;
 
 static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
@@ -1698,6 +1751,7 @@ struct drm_i915_file_private {
                                 (dev)->pdev->device == 0x010A)
 #define IS_VALLEYVIEW(dev)     (INTEL_INFO(dev)->is_valleyview)
 #define IS_HASWELL(dev)        (INTEL_INFO(dev)->is_haswell)
+#define IS_BROADWELL(dev)      (INTEL_INFO(dev)->gen == 8)
 #define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
 #define IS_HSW_EARLY_SDV(dev)  (IS_HASWELL(dev) && \
                                 ((dev)->pdev->device & 0xFF00) == 0x0C00)
@@ -1719,6 +1773,7 @@ struct drm_i915_file_private {
 #define IS_GEN5(dev)   (INTEL_INFO(dev)->gen == 5)
 #define IS_GEN6(dev)   (INTEL_INFO(dev)->gen == 6)
 #define IS_GEN7(dev)   (INTEL_INFO(dev)->gen == 7)
+#define IS_GEN8(dev)   (INTEL_INFO(dev)->gen == 8)
 
 #define RENDER_RING            (1<<RCS)
 #define BSD_RING               (1<<VCS)
@@ -1755,12 +1810,12 @@ struct drm_i915_file_private {
 #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
 #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
 
-#define HAS_IPS(dev)           (IS_ULT(dev))
+#define HAS_IPS(dev)           (IS_ULT(dev) || IS_BROADWELL(dev))
 
 #define HAS_DDI(dev)           (INTEL_INFO(dev)->has_ddi)
-#define HAS_POWER_WELL(dev)    (IS_HASWELL(dev))
+#define HAS_POWER_WELL(dev)    (IS_HASWELL(dev) || IS_BROADWELL(dev))
 #define HAS_FPGA_DBG_UNCLAIMED(dev)    (INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)           (IS_HASWELL(dev))
+#define HAS_PSR(dev)           (IS_HASWELL(dev) || IS_BROADWELL(dev))
 
 #define INTEL_PCH_DEVICE_ID_MASK               0xff00
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE           0x3b00
@@ -1784,27 +1839,6 @@ struct drm_i915_file_private {
 
 #include "i915_trace.h"
 
-/**
- * RC6 is a special power stage which allows the GPU to enter an very
- * low-voltage mode when idle, using down to 0V while at this stage.  This
- * stage is entered automatically when the GPU is idle when RC6 support is
- * enabled, and as soon as new workload arises GPU wakes up automatically as well.
- *
- * There are different RC6 modes available in Intel GPU, which differentiate
- * among each other with the latency required to enter and leave RC6 and
- * voltage consumed by the GPU in different states.
- *
- * The combination of the following flags define which states GPU is allowed
- * to enter, while RC6 is the normal RC6 state, RC6p is the deep RC6, and
- * RC6pp is deepest RC6. Their support by hardware varies according to the
- * GPU, BIOS, chipset and platform. RC6 is usually the safest one and the one
- * which brings the most power savings; deeper states save more power, but
- * require higher latency to switch to and wake up.
- */
-#define INTEL_RC6_ENABLE                       (1<<0)
-#define INTEL_RC6p_ENABLE                      (1<<1)
-#define INTEL_RC6pp_ENABLE                     (1<<2)
-
 extern const struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
 extern unsigned int i915_fbpercrtc __always_unused;
@@ -1878,10 +1912,10 @@ extern void intel_uncore_check_errors(struct drm_device *dev);
 extern void intel_uncore_fini(struct drm_device *dev);
 
 void
-i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
+i915_enable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask);
 
 void
-i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
+i915_disable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask);
 
 /* i915_gem.c */
 int i915_gem_init_ioctl(struct drm_device *dev, void *data,
@@ -2175,6 +2209,8 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
 void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
                              struct drm_i915_gem_object *obj);
 
+void i915_check_and_clear_faults(struct drm_device *dev);
+void i915_gem_suspend_gtt_mappings(struct drm_device *dev);
 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_bind_object(struct drm_i915_gem_object *obj,
index 34df59b..12bbd5e 100644 (file)
@@ -261,7 +261,7 @@ i915_gem_dumb_create(struct drm_file *file,
                     struct drm_mode_create_dumb *args)
 {
        /* have to work out size/pitch and return them */
-       args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64);
+       args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 64);
        args->size = args->pitch * args->height;
        return i915_gem_create(file, dev,
                               args->size, &args->handle);
@@ -2954,6 +2954,7 @@ static void i915_gem_write_fence(struct drm_device *dev, int reg,
             obj->stride, obj->tiling_mode);
 
        switch (INTEL_INFO(dev)->gen) {
+       case 8:
        case 7:
        case 6:
        case 5:
@@ -4361,6 +4362,8 @@ void i915_gem_init_swizzling(struct drm_device *dev)
                I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_SNB));
        else if (IS_GEN7(dev))
                I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB));
+       else if (IS_GEN8(dev))
+               I915_WRITE(GAMTARBMODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_BDW));
        else
                BUG();
 }
index cc619c1..72a3df3 100644 (file)
@@ -117,6 +117,9 @@ static int get_context_size(struct drm_device *dev)
                else
                        ret = GEN7_CXT_TOTAL_SIZE(reg) * 64;
                break;
+       case 8:
+               ret = GEN8_CXT_TOTAL_SIZE;
+               break;
        default:
                BUG();
        }
index 0ce0d47..885d595 100644 (file)
@@ -212,6 +212,7 @@ static int
 relocate_entry_cpu(struct drm_i915_gem_object *obj,
                   struct drm_i915_gem_relocation_entry *reloc)
 {
+       struct drm_device *dev = obj->base.dev;
        uint32_t page_offset = offset_in_page(reloc->offset);
        char *vaddr;
        int ret = -EINVAL;
@@ -223,6 +224,19 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
        vaddr = kmap_atomic(i915_gem_object_get_page(obj,
                                reloc->offset >> PAGE_SHIFT));
        *(uint32_t *)(vaddr + page_offset) = reloc->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));
+               }
+
+               *(uint32_t *)(vaddr + page_offset) = 0;
+       }
+
        kunmap_atomic(vaddr);
 
        return 0;
@@ -253,6 +267,21 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
        reloc_entry = (uint32_t __iomem *)
                (reloc_page + offset_in_page(reloc->offset));
        iowrite32(reloc->delta, reloc_entry);
+
+       if (INTEL_INFO(dev)->gen >= 8) {
+               reloc_entry += 1;
+
+               if (offset_in_page(reloc->offset + sizeof(uint32_t)) == 0) {
+                       io_mapping_unmap_atomic(reloc_page);
+                       reloc_page = io_mapping_map_atomic_wc(
+                                       dev_priv->gtt.mappable,
+                                       reloc->offset + sizeof(uint32_t));
+                       reloc_entry = reloc_page;
+               }
+
+               iowrite32(0, reloc_entry);
+       }
+
        io_mapping_unmap_atomic(reloc_page);
 
        return 0;
@@ -323,7 +352,8 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                return 0;
 
        /* Check that the relocation address is valid... */
-       if (unlikely(reloc->offset > obj->base.size - 4)) {
+       if (unlikely(reloc->offset >
+               obj->base.size - (INTEL_INFO(dev)->gen >= 8 ? 8 : 4))) {
                DRM_DEBUG("Relocation beyond object bounds: "
                          "obj %p target %d offset %d size %d.\n",
                          obj, reloc->target_handle,
@@ -1116,8 +1146,7 @@ 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 let's be paranoid and do it
-        * unconditionally for now. */
+        * hsw should have this fixed, but bdw mucks it up again. */
        if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping)
                i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level);
 
index e999496..3620a1b 100644 (file)
@@ -30,6 +30,8 @@
 
 #define GEN6_PPGTT_PD_ENTRIES 512
 #define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t))
+typedef uint64_t gen8_gtt_pte_t;
+typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
 
 /* PPGTT stuff */
 #define GEN6_GTT_ADDR_ENCODE(addr)     ((addr) | (((addr) >> 28) & 0xff0))
 #define HSW_WB_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0xb)
 #define HSW_WT_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0x6)
 
+#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_PDPS               4
+
+#define PPAT_UNCACHED_INDEX            (_PAGE_PWT | _PAGE_PCD)
+#define PPAT_CACHED_PDE_INDEX          0 /* WB LLC */
+#define PPAT_CACHED_INDEX              _PAGE_PAT /* WB LLCeLLC */
+#define PPAT_DISPLAY_ELLC_INDEX                _PAGE_PCD /* WT eLLC */
+
+static inline gen8_gtt_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;
+       pte |= addr;
+       if (level != I915_CACHE_NONE)
+               pte |= PPAT_CACHED_INDEX;
+       else
+               pte |= PPAT_UNCACHED_INDEX;
+       return pte;
+}
+
+static inline gen8_ppgtt_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;
+       pde |= addr;
+       if (level != I915_CACHE_NONE)
+               pde |= PPAT_CACHED_PDE_INDEX;
+       else
+               pde |= PPAT_UNCACHED_INDEX;
+       return pde;
+}
+
 static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level)
+                                    enum i915_cache_level level,
+                                    bool valid)
 {
-       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -79,9 +117,10 @@ static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
 }
 
 static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level)
+                                    enum i915_cache_level level,
+                                    bool valid)
 {
-       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -105,9 +144,10 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
 #define BYT_PTE_SNOOPED_BY_CPU_CACHES  (1 << 2)
 
 static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level)
+                                    enum i915_cache_level level,
+                                    bool valid)
 {
-       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        /* Mark the page as writeable.  Other platforms don't have a
@@ -122,9 +162,10 @@ static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
 }
 
 static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level)
+                                    enum i915_cache_level level,
+                                    bool valid)
 {
-       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
 
        if (level != I915_CACHE_NONE)
@@ -134,9 +175,10 @@ static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
 }
 
 static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
-                                     enum i915_cache_level level)
+                                     enum i915_cache_level level,
+                                     bool valid)
 {
-       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -153,6 +195,257 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
        return pte;
 }
 
+/* Broadwell Page Directory Pointer Descriptors */
+static int gen8_write_pdp(struct intel_ring_buffer *ring, unsigned entry,
+                          uint64_t val)
+{
+       int ret;
+
+       BUG_ON(entry >= 4);
+
+       ret = intel_ring_begin(ring, 6);
+       if (ret)
+               return ret;
+
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+       intel_ring_emit(ring, GEN8_RING_PDP_UDW(ring, entry));
+       intel_ring_emit(ring, (u32)(val >> 32));
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+       intel_ring_emit(ring, GEN8_RING_PDP_LDW(ring, entry));
+       intel_ring_emit(ring, (u32)(val));
+       intel_ring_advance(ring);
+
+       return 0;
+}
+
+static int gen8_ppgtt_enable(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+       int i, j, ret;
+
+       /* bit of a hack to find the actual last used pd */
+       int used_pd = ppgtt->num_pd_entries / GEN8_PDES_PER_PAGE;
+
+       for_each_ring(ring, dev_priv, j) {
+               I915_WRITE(RING_MODE_GEN7(ring),
+                          _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+       }
+
+       for (i = used_pd - 1; i >= 0; i--) {
+               dma_addr_t addr = ppgtt->pd_dma_addr[i];
+               for_each_ring(ring, dev_priv, j) {
+                       ret = gen8_write_pdp(ring, i, addr);
+                       if (ret)
+                               return ret;
+               }
+       }
+       return 0;
+}
+
+static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
+                                  unsigned first_entry,
+                                  unsigned num_entries,
+                                  bool use_scratch)
+{
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(vm, struct i915_hw_ppgtt, base);
+       gen8_gtt_pte_t *pt_vaddr, scratch_pte;
+       unsigned act_pt = first_entry / GEN8_PTES_PER_PAGE;
+       unsigned first_pte = first_entry % GEN8_PTES_PER_PAGE;
+       unsigned last_pte, i;
+
+       scratch_pte = gen8_pte_encode(ppgtt->base.scratch.addr,
+                                     I915_CACHE_LLC, use_scratch);
+
+       while (num_entries) {
+               struct page *page_table = &ppgtt->gen8_pt_pages[act_pt];
+
+               last_pte = first_pte + num_entries;
+               if (last_pte > GEN8_PTES_PER_PAGE)
+                       last_pte = GEN8_PTES_PER_PAGE;
+
+               pt_vaddr = kmap_atomic(page_table);
+
+               for (i = first_pte; i < last_pte; i++)
+                       pt_vaddr[i] = scratch_pte;
+
+               kunmap_atomic(pt_vaddr);
+
+               num_entries -= last_pte - first_pte;
+               first_pte = 0;
+               act_pt++;
+       }
+}
+
+static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
+                                     struct sg_table *pages,
+                                     unsigned first_entry,
+                                     enum i915_cache_level cache_level)
+{
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(vm, struct i915_hw_ppgtt, base);
+       gen8_gtt_pte_t *pt_vaddr;
+       unsigned act_pt = first_entry / GEN8_PTES_PER_PAGE;
+       unsigned act_pte = first_entry % GEN8_PTES_PER_PAGE;
+       struct sg_page_iter sg_iter;
+
+       pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]);
+       for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
+               dma_addr_t page_addr;
+
+               page_addr = sg_dma_address(sg_iter.sg) +
+                               (sg_iter.sg_pgoffset << PAGE_SHIFT);
+               pt_vaddr[act_pte] = gen8_pte_encode(page_addr, cache_level,
+                                                   true);
+               if (++act_pte == GEN8_PTES_PER_PAGE) {
+                       kunmap_atomic(pt_vaddr);
+                       act_pt++;
+                       pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]);
+                       act_pte = 0;
+
+               }
+       }
+       kunmap_atomic(pt_vaddr);
+}
+
+static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
+{
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(vm, struct i915_hw_ppgtt, base);
+       int i, j;
+
+       for (i = 0; i < ppgtt->num_pd_pages ; i++) {
+               if (ppgtt->pd_dma_addr[i]) {
+                       pci_unmap_page(ppgtt->base.dev->pdev,
+                                      ppgtt->pd_dma_addr[i],
+                                      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];
+                               if (addr)
+                                       pci_unmap_page(ppgtt->base.dev->pdev,
+                                                      addr,
+                                                      PAGE_SIZE,
+                                                      PCI_DMA_BIDIRECTIONAL);
+
+                       }
+               }
+               kfree(ppgtt->gen8_pt_dma_addr[i]);
+       }
+
+       __free_pages(ppgtt->gen8_pt_pages, ppgtt->num_pt_pages << PAGE_SHIFT);
+       __free_pages(ppgtt->pd_pages, ppgtt->num_pd_pages << PAGE_SHIFT);
+}
+
+/**
+ * GEN8 legacy ppgtt programming is accomplished through 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 space.
+ *
+ * TODO: Do something with the size parameter
+ **/
+static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
+{
+       struct page *pt_pages;
+       int i, j, ret = -ENOMEM;
+       const int max_pdp = DIV_ROUND_UP(size, 1 << 30);
+       const int num_pt_pages = GEN8_PDES_PER_PAGE * max_pdp;
+
+       if (size % (1<<30))
+               DRM_INFO("Pages will be wasted unless GTT size (%llu) is divisible by 1GB\n", size);
+
+       /* FIXME: split allocation into smaller pieces. For now we only ever do
+        * this once, but with full PPGTT, the multiple contiguous allocations
+        * will be bad.
+        */
+       ppgtt->pd_pages = alloc_pages(GFP_KERNEL, get_order(max_pdp << PAGE_SHIFT));
+       if (!ppgtt->pd_pages)
+               return -ENOMEM;
+
+       pt_pages = alloc_pages(GFP_KERNEL, get_order(num_pt_pages << PAGE_SHIFT));
+       if (!pt_pages) {
+               __free_pages(ppgtt->pd_pages, get_order(max_pdp << PAGE_SHIFT));
+               return -ENOMEM;
+       }
+
+       ppgtt->gen8_pt_pages = pt_pages;
+       ppgtt->num_pd_pages = 1 << get_order(max_pdp << PAGE_SHIFT);
+       ppgtt->num_pt_pages = 1 << get_order(num_pt_pages << PAGE_SHIFT);
+       ppgtt->num_pd_entries = max_pdp * GEN8_PDES_PER_PAGE;
+       ppgtt->enable = gen8_ppgtt_enable;
+       ppgtt->base.clear_range = gen8_ppgtt_clear_range;
+       ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
+       ppgtt->base.cleanup = gen8_ppgtt_cleanup;
+
+       BUG_ON(ppgtt->num_pd_pages > GEN8_LEGACY_PDPS);
+
+       /*
+        * - Create a mapping for the page directories.
+        * - For each page directory:
+        *      allocate space for page table mappings.
+        *      map each page table
+        */
+       for (i = 0; i < max_pdp; i++) {
+               dma_addr_t temp;
+               temp = pci_map_page(ppgtt->base.dev->pdev,
+                                   &ppgtt->pd_pages[i], 0,
+                                   PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+               if (pci_dma_mapping_error(ppgtt->base.dev->pdev, temp))
+                       goto err_out;
+
+               ppgtt->pd_dma_addr[i] = temp;
+
+               ppgtt->gen8_pt_dma_addr[i] = kmalloc(sizeof(dma_addr_t) * GEN8_PDES_PER_PAGE, GFP_KERNEL);
+               if (!ppgtt->gen8_pt_dma_addr[i])
+                       goto err_out;
+
+               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
+                       struct page *p = &pt_pages[i * GEN8_PDES_PER_PAGE + j];
+                       temp = pci_map_page(ppgtt->base.dev->pdev,
+                                           p, 0, PAGE_SIZE,
+                                           PCI_DMA_BIDIRECTIONAL);
+
+                       if (pci_dma_mapping_error(ppgtt->base.dev->pdev, temp))
+                               goto err_out;
+
+                       ppgtt->gen8_pt_dma_addr[i][j] = temp;
+               }
+       }
+
+       /* For now, the PPGTT helper functions all require that the PDEs are
+        * 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];
+                       pd_vaddr[j] = gen8_pde_encode(ppgtt->base.dev, addr,
+                                                     I915_CACHE_LLC);
+               }
+               kunmap_atomic(pd_vaddr);
+       }
+
+       ppgtt->base.clear_range(&ppgtt->base, 0,
+                               ppgtt->num_pd_entries * GEN8_PTES_PER_PAGE,
+                               true);
+
+       DRM_DEBUG_DRIVER("Allocated %d pages for page directories (%d wasted)\n",
+                        ppgtt->num_pd_pages, ppgtt->num_pd_pages - max_pdp);
+       DRM_DEBUG_DRIVER("Allocated %d pages for page tables (%lld wasted)\n",
+                        ppgtt->num_pt_pages,
+                        (ppgtt->num_pt_pages - num_pt_pages) +
+                        size % (1<<30));
+       return 0;
+
+err_out:
+       ppgtt->base.cleanup(&ppgtt->base);
+       return ret;
+}
+
 static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
 {
        struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
@@ -236,7 +529,8 @@ static int gen6_ppgtt_enable(struct drm_device *dev)
 /* PPGTT support for Sandybdrige/Gen6 and later */
 static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
                                   unsigned first_entry,
-                                  unsigned num_entries)
+                                  unsigned num_entries,
+                                  bool use_scratch)
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
@@ -245,7 +539,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
        unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        unsigned last_pte, i;
 
-       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true);
 
        while (num_entries) {
                last_pte = first_pte + num_entries;
@@ -282,7 +576,7 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                dma_addr_t page_addr;
 
                page_addr = sg_page_iter_dma_address(&sg_iter);
-               pt_vaddr[act_pte] = vm->pte_encode(page_addr, cache_level);
+               pt_vaddr[act_pte] = vm->pte_encode(page_addr, cache_level, true);
                if (++act_pte == I915_PPGTT_PT_ENTRIES) {
                        kunmap_atomic(pt_vaddr);
                        act_pt++;
@@ -367,7 +661,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
        }
 
        ppgtt->base.clear_range(&ppgtt->base, 0,
-                               ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES);
+                               ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES, true);
 
        ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t);
 
@@ -404,6 +698,8 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
 
        if (INTEL_INFO(dev)->gen < 8)
                ret = gen6_ppgtt_init(ppgtt);
+       else if (IS_GEN8(dev))
+               ret = gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
        else
                BUG();
 
@@ -444,7 +740,8 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
 {
        ppgtt->base.clear_range(&ppgtt->base,
                                i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
-                               obj->base.size >> PAGE_SHIFT);
+                               obj->base.size >> PAGE_SHIFT,
+                               true);
 }
 
 extern int intel_iommu_gfx_mapped;
@@ -485,15 +782,65 @@ static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible)
                dev_priv->mm.interruptible = interruptible;
 }
 
+void i915_check_and_clear_faults(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       int i;
+
+       if (INTEL_INFO(dev)->gen < 6)
+               return;
+
+       for_each_ring(ring, dev_priv, i) {
+               u32 fault_reg;
+               fault_reg = I915_READ(RING_FAULT_REG(ring));
+               if (fault_reg & RING_FAULT_VALID) {
+                       DRM_DEBUG_DRIVER("Unexpected fault\n"
+                                        "\tAddr: 0x%08lx\\n"
+                                        "\tAddress space: %s\n"
+                                        "\tSource ID: %d\n"
+                                        "\tType: %d\n",
+                                        fault_reg & PAGE_MASK,
+                                        fault_reg & RING_FAULT_GTTSEL_MASK ? "GGTT" : "PPGTT",
+                                        RING_FAULT_SRCID(fault_reg),
+                                        RING_FAULT_FAULT_TYPE(fault_reg));
+                       I915_WRITE(RING_FAULT_REG(ring),
+                                  fault_reg & ~RING_FAULT_VALID);
+               }
+       }
+       POSTING_READ(RING_FAULT_REG(&dev_priv->ring[RCS]));
+}
+
+void i915_gem_suspend_gtt_mappings(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /* Don't bother messing with faults pre GEN6 as we have little
+        * documentation supporting that it's a good idea.
+        */
+       if (INTEL_INFO(dev)->gen < 6)
+               return;
+
+       i915_check_and_clear_faults(dev);
+
+       dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
+                                      dev_priv->gtt.base.start / PAGE_SIZE,
+                                      dev_priv->gtt.base.total / PAGE_SIZE,
+                                      false);
+}
+
 void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
 
+       i915_check_and_clear_faults(dev);
+
        /* First fill our portion of the GTT with scratch pages */
        dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
                                       dev_priv->gtt.base.start / PAGE_SIZE,
-                                      dev_priv->gtt.base.total / PAGE_SIZE);
+                                      dev_priv->gtt.base.total / PAGE_SIZE,
+                                      true);
 
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                i915_gem_clflush_object(obj, obj->pin_display);
@@ -516,6 +863,57 @@ 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)
+{
+#ifdef writeq
+       writeq(pte, addr);
+#else
+       iowrite32((u32)pte, addr);
+       iowrite32(pte >> 32, addr + 4);
+#endif
+}
+
+static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
+                                    struct sg_table *st,
+                                    unsigned int first_entry,
+                                    enum i915_cache_level level)
+{
+       struct drm_i915_private *dev_priv = vm->dev->dev_private;
+       gen8_gtt_pte_t __iomem *gtt_entries =
+               (gen8_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
+       int i = 0;
+       struct sg_page_iter sg_iter;
+       dma_addr_t addr;
+
+       for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
+               addr = sg_dma_address(sg_iter.sg) +
+                       (sg_iter.sg_pgoffset << PAGE_SHIFT);
+               gen8_set_pte(&gtt_entries[i],
+                            gen8_pte_encode(addr, level, true));
+               i++;
+       }
+
+       /*
+        * XXX: This serves as a posting read to make sure that the PTE has
+        * actually been updated. There is some concern that even though
+        * registers and PTEs are within the same BAR that they are potentially
+        * of NUMA access patterns. Therefore, even with the way we assume
+        * hardware should work, we must keep this posting read for paranoia.
+        */
+       if (i != 0)
+               WARN_ON(readq(&gtt_entries[i-1])
+                       != gen8_pte_encode(addr, level, true));
+
+#if 0 /* TODO: Still needed on GEN8? */
+       /* This next bit makes the above posting read even more important. We
+        * want to flush the TLBs only after we're certain all the PTE updates
+        * have finished.
+        */
+       I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
+       POSTING_READ(GFX_FLSH_CNTL_GEN6);
+#endif
+}
+
 /*
  * Binds an object into the global gtt with the specified cache level. The object
  * will be accessible to the GPU via commands whose operands reference offsets
@@ -536,7 +934,7 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
 
        for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
                addr = sg_page_iter_dma_address(&sg_iter);
-               iowrite32(vm->pte_encode(addr, level), &gtt_entries[i]);
+               iowrite32(vm->pte_encode(addr, level, true), &gtt_entries[i]);
                i++;
        }
 
@@ -548,7 +946,7 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
         */
        if (i != 0)
                WARN_ON(readl(&gtt_entries[i-1]) !=
-                       vm->pte_encode(addr, level));
+                       vm->pte_encode(addr, level, true));
 
        /* This next bit makes the above posting read even more important. We
         * want to flush the TLBs only after we're certain all the PTE updates
@@ -558,9 +956,34 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
        POSTING_READ(GFX_FLSH_CNTL_GEN6);
 }
 
+static void gen8_ggtt_clear_range(struct i915_address_space *vm,
+                                 unsigned int first_entry,
+                                 unsigned int num_entries,
+                                 bool use_scratch)
+{
+       struct drm_i915_private *dev_priv = vm->dev->dev_private;
+       gen8_gtt_pte_t scratch_pte, __iomem *gtt_base =
+               (gen8_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
+       const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
+       int i;
+
+       if (WARN(num_entries > max_entries,
+                "First entry = %d; Num entries = %d (max=%d)\n",
+                first_entry, num_entries, max_entries))
+               num_entries = max_entries;
+
+       scratch_pte = gen8_pte_encode(vm->scratch.addr,
+                                     I915_CACHE_LLC,
+                                     use_scratch);
+       for (i = 0; i < num_entries; i++)
+               gen8_set_pte(&gtt_base[i], scratch_pte);
+       readl(gtt_base);
+}
+
 static void gen6_ggtt_clear_range(struct i915_address_space *vm,
                                  unsigned int first_entry,
-                                 unsigned int num_entries)
+                                 unsigned int num_entries,
+                                 bool use_scratch)
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        gen6_gtt_pte_t scratch_pte, __iomem *gtt_base =
@@ -573,13 +996,13 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
                 first_entry, num_entries, max_entries))
                num_entries = max_entries;
 
-       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, use_scratch);
+
        for (i = 0; i < num_entries; i++)
                iowrite32(scratch_pte, &gtt_base[i]);
        readl(gtt_base);
 }
 
-
 static void i915_ggtt_insert_entries(struct i915_address_space *vm,
                                     struct sg_table *st,
                                     unsigned int pg_start,
@@ -594,7 +1017,8 @@ static void i915_ggtt_insert_entries(struct i915_address_space *vm,
 
 static void i915_ggtt_clear_range(struct i915_address_space *vm,
                                  unsigned int first_entry,
-                                 unsigned int num_entries)
+                                 unsigned int num_entries,
+                                 bool unused)
 {
        intel_gtt_clear_range(first_entry, num_entries);
 }
@@ -622,7 +1046,8 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
 
        dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
                                       entry,
-                                      obj->base.size >> PAGE_SHIFT);
+                                      obj->base.size >> PAGE_SHIFT,
+                                      true);
 
        obj->has_global_gtt_mapping = 0;
 }
@@ -659,6 +1084,7 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node,
                        *end -= 4096;
        }
 }
+
 void i915_gem_setup_global_gtt(struct drm_device *dev,
                               unsigned long start,
                               unsigned long mappable_end,
@@ -709,11 +1135,11 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
                const unsigned long count = (hole_end - hole_start) / PAGE_SIZE;
                DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
                              hole_start, hole_end);
-               ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count);
+               ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count, true);
        }
 
        /* And finally clear the reserved guard page */
-       ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1);
+       ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1, true);
 }
 
 static bool
@@ -756,7 +1182,8 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
 
                DRM_ERROR("Aliased PPGTT setup failed %d\n", ret);
                drm_mm_takedown(&dev_priv->gtt.base.mm);
-               gtt_size += GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE;
+               if (INTEL_INFO(dev)->gen < 8)
+                       gtt_size += GEN6_PPGTT_PD_ENTRIES*PAGE_SIZE;
        }
        i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 }
@@ -806,6 +1233,15 @@ static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl)
        return snb_gmch_ctl << 20;
 }
 
+static inline unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl)
+{
+       bdw_gmch_ctl >>= BDW_GMCH_GGMS_SHIFT;
+       bdw_gmch_ctl &= BDW_GMCH_GGMS_MASK;
+       if (bdw_gmch_ctl)
+               bdw_gmch_ctl = 1 << bdw_gmch_ctl;
+       return bdw_gmch_ctl << 20;
+}
+
 static inline size_t gen6_get_stolen_size(u16 snb_gmch_ctl)
 {
        snb_gmch_ctl >>= SNB_GMCH_GMS_SHIFT;
@@ -813,6 +1249,108 @@ static inline size_t gen6_get_stolen_size(u16 snb_gmch_ctl)
        return snb_gmch_ctl << 25; /* 32 MB units */
 }
 
+static inline size_t gen8_get_stolen_size(u16 bdw_gmch_ctl)
+{
+       bdw_gmch_ctl >>= BDW_GMCH_GMS_SHIFT;
+       bdw_gmch_ctl &= BDW_GMCH_GMS_MASK;
+       return bdw_gmch_ctl << 25; /* 32 MB units */
+}
+
+static int ggtt_probe_common(struct drm_device *dev,
+                            size_t gtt_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       phys_addr_t gtt_bus_addr;
+       int ret;
+
+       /* For Modern GENs the PTEs and register space are split in the BAR */
+       gtt_bus_addr = pci_resource_start(dev->pdev, 0) +
+               (pci_resource_len(dev->pdev, 0) / 2);
+
+       dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size);
+       if (!dev_priv->gtt.gsm) {
+               DRM_ERROR("Failed to map the gtt page table\n");
+               return -ENOMEM;
+       }
+
+       ret = setup_scratch_page(dev);
+       if (ret) {
+               DRM_ERROR("Scratch setup failed\n");
+               /* iounmap will also get called at remove, but meh */
+               iounmap(dev_priv->gtt.gsm);
+       }
+
+       return ret;
+}
+
+/* The GGTT and PPGTT need a private PPAT setup in order to handle cacheability
+ * bits. When using advanced contexts each context stores its own PAT, but
+ * writing this data shouldn't be harmful even in those cases. */
+static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv)
+{
+#define GEN8_PPAT_UC           (0<<0)
+#define GEN8_PPAT_WC           (1<<0)
+#define GEN8_PPAT_WT           (2<<0)
+#define GEN8_PPAT_WB           (3<<0)
+#define GEN8_PPAT_ELLC_OVERRIDE        (0<<2)
+/* FIXME(BDW): Bspec is completely confused about cache control bits. */
+#define GEN8_PPAT_LLC          (1<<2)
+#define GEN8_PPAT_LLCELLC      (2<<2)
+#define GEN8_PPAT_LLCeLLC      (3<<2)
+#define GEN8_PPAT_AGE(x)       (x<<4)
+#define GEN8_PPAT(i, x) ((uint64_t) (x) << ((i) * 8))
+       uint64_t pat;
+
+       pat = GEN8_PPAT(0, GEN8_PPAT_WB | GEN8_PPAT_LLC)     | /* for normal objects, no eLLC */
+             GEN8_PPAT(1, GEN8_PPAT_WC | GEN8_PPAT_LLCELLC) | /* for something pointing to ptes? */
+             GEN8_PPAT(2, GEN8_PPAT_WT | GEN8_PPAT_LLCELLC) | /* for scanout with eLLC */
+             GEN8_PPAT(3, GEN8_PPAT_UC)                     | /* Uncached objects, mostly for scanout */
+             GEN8_PPAT(4, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(0)) |
+             GEN8_PPAT(5, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(1)) |
+             GEN8_PPAT(6, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(2)) |
+             GEN8_PPAT(7, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(3));
+
+       /* XXX: spec defines this as 2 distinct registers. It's unclear if a 64b
+        * write would work. */
+       I915_WRITE(GEN8_PRIVATE_PAT, pat);
+       I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32);
+}
+
+static int gen8_gmch_probe(struct drm_device *dev,
+                          size_t *gtt_total,
+                          size_t *stolen,
+                          phys_addr_t *mappable_base,
+                          unsigned long *mappable_end)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned int gtt_size;
+       u16 snb_gmch_ctl;
+       int ret;
+
+       /* TODO: We're not aware of mappable constraints on gen8 yet */
+       *mappable_base = pci_resource_start(dev->pdev, 2);
+       *mappable_end = pci_resource_len(dev->pdev, 2);
+
+       if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(39)))
+               pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(39));
+
+       pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+
+       *stolen = gen8_get_stolen_size(snb_gmch_ctl);
+
+       gtt_size = gen8_get_total_gtt_size(snb_gmch_ctl);
+       *gtt_total = (gtt_size / sizeof(gen8_gtt_pte_t)) << PAGE_SHIFT;
+
+       gen8_setup_private_ppat(dev_priv);
+
+       ret = ggtt_probe_common(dev, gtt_size);
+
+       dev_priv->gtt.base.clear_range = gen8_ggtt_clear_range;
+       dev_priv->gtt.base.insert_entries = gen8_ggtt_insert_entries;
+
+       return ret;
+}
+
 static int gen6_gmch_probe(struct drm_device *dev,
                           size_t *gtt_total,
                           size_t *stolen,
@@ -820,7 +1358,6 @@ static int gen6_gmch_probe(struct drm_device *dev,
                           unsigned long *mappable_end)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       phys_addr_t gtt_bus_addr;
        unsigned int gtt_size;
        u16 snb_gmch_ctl;
        int ret;
@@ -840,24 +1377,13 @@ static int gen6_gmch_probe(struct drm_device *dev,
        if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(40)))
                pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(40));
        pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
-       gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl);
 
        *stolen = gen6_get_stolen_size(snb_gmch_ctl);
-       *gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT;
 
-       /* For Modern GENs the PTEs and register space are split in the BAR */
-       gtt_bus_addr = pci_resource_start(dev->pdev, 0) +
-               (pci_resource_len(dev->pdev, 0) / 2);
-
-       dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size);
-       if (!dev_priv->gtt.gsm) {
-               DRM_ERROR("Failed to map the gtt page table\n");
-               return -ENOMEM;
-       }
+       gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl);
+       *gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT;
 
-       ret = setup_scratch_page(dev);
-       if (ret)
-               DRM_ERROR("Scratch setup failed\n");
+       ret = ggtt_probe_common(dev, gtt_size);
 
        dev_priv->gtt.base.clear_range = gen6_ggtt_clear_range;
        dev_priv->gtt.base.insert_entries = gen6_ggtt_insert_entries;
@@ -911,7 +1437,7 @@ int i915_gem_gtt_init(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen <= 5) {
                gtt->gtt_probe = i915_gmch_probe;
                gtt->base.cleanup = i915_gmch_remove;
-       } else {
+       } else if (INTEL_INFO(dev)->gen < 8) {
                gtt->gtt_probe = gen6_gmch_probe;
                gtt->base.cleanup = gen6_gmch_remove;
                if (IS_HASWELL(dev) && dev_priv->ellc_size)
@@ -924,6 +1450,9 @@ int i915_gem_gtt_init(struct drm_device *dev)
                        gtt->base.pte_encode = ivb_pte_encode;
                else
                        gtt->base.pte_encode = snb_pte_encode;
+       } else {
+               dev_priv->gtt.gtt_probe = gen8_gmch_probe;
+               dev_priv->gtt.base.cleanup = gen6_gmch_remove;
        }
 
        ret = gtt->gtt_probe(dev, &gtt->base.total, &gtt->stolen_size,
index 5dde810..79dcb8f 100644 (file)
@@ -249,7 +249,8 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
        err_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
        if (ring == RCS && INTEL_INFO(dev)->gen >= 4)
                err_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr);
-
+       if (INTEL_INFO(dev)->gen >= 4)
+               err_printf(m, "  BB_STATE: 0x%08x\n", error->bbstate[ring]);
        if (INTEL_INFO(dev)->gen >= 4)
                err_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
        err_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
@@ -623,6 +624,7 @@ static void i915_gem_record_fences(struct drm_device *dev,
 
        /* Fences */
        switch (INTEL_INFO(dev)->gen) {
+       case 8:
        case 7:
        case 6:
                for (i = 0; i < dev_priv->num_fence_regs; i++)
@@ -725,6 +727,7 @@ static void i915_record_ring_state(struct drm_device *dev,
                error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
                if (ring->id == RCS)
                        error->bbaddr = I915_READ64(BB_ADDR);
+               error->bbstate[ring->id] = I915_READ(RING_BBSTATE(ring->mmio_base));
        } else {
                error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX);
                error->ipeir[ring->id] = I915_READ(IPEIR);
@@ -1042,6 +1045,7 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone)
        default:
                WARN_ONCE(1, "Unsupported platform\n");
        case 7:
+       case 8:
                instdone[0] = I915_READ(GEN7_INSTDONE_1);
                instdone[1] = I915_READ(GEN7_SC_INSTDONE);
                instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE);
index a2274c7..5d1dedc 100644 (file)
@@ -270,6 +270,21 @@ static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
        }
 }
 
+static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev,
+                                                 enum pipe pipe, bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       if (enable)
+               dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN;
+       else
+               dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN;
+       I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
+       POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+}
+
 /**
  * ibx_display_interrupt_update - update SDEIMR
  * @dev_priv: driver private
@@ -382,6 +397,8 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
                ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
        else if (IS_GEN7(dev))
                ivybridge_set_fifo_underrun_reporting(dev, pipe, enable);
+       else if (IS_GEN8(dev))
+               broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
 
 done:
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
@@ -442,7 +459,7 @@ done:
 
 
 void
-i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
+i915_enable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask)
 {
        u32 reg = PIPESTAT(pipe);
        u32 pipestat = I915_READ(reg) & 0x7fff0000;
@@ -459,7 +476,7 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 }
 
 void
-i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
+i915_disable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask)
 {
        u32 reg = PIPESTAT(pipe);
        u32 pipestat = I915_READ(reg) & 0x7fff0000;
@@ -487,9 +504,10 @@ static void i915_enable_asle_pipestat(struct drm_device *dev)
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
-       i915_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_ENABLE);
        if (INTEL_INFO(dev)->gen >= 4)
-               i915_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE);
+               i915_enable_pipestat(dev_priv, PIPE_A,
+                                    PIPE_LEGACY_BLC_EVENT_ENABLE);
 
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
@@ -1150,6 +1168,56 @@ static void snb_gt_irq_handler(struct drm_device *dev,
                ivybridge_parity_error_irq_handler(dev, gt_iir);
 }
 
+static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
+                                      struct drm_i915_private *dev_priv,
+                                      u32 master_ctl)
+{
+       u32 rcs, bcs, vcs;
+       uint32_t tmp = 0;
+       irqreturn_t ret = IRQ_NONE;
+
+       if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
+               tmp = I915_READ(GEN8_GT_IIR(0));
+               if (tmp) {
+                       ret = IRQ_HANDLED;
+                       rcs = tmp >> GEN8_RCS_IRQ_SHIFT;
+                       bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
+                       if (rcs & GT_RENDER_USER_INTERRUPT)
+                               notify_ring(dev, &dev_priv->ring[RCS]);
+                       if (bcs & GT_RENDER_USER_INTERRUPT)
+                               notify_ring(dev, &dev_priv->ring[BCS]);
+                       I915_WRITE(GEN8_GT_IIR(0), tmp);
+               } else
+                       DRM_ERROR("The master control interrupt lied (GT0)!\n");
+       }
+
+       if (master_ctl & GEN8_GT_VCS1_IRQ) {
+               tmp = I915_READ(GEN8_GT_IIR(1));
+               if (tmp) {
+                       ret = IRQ_HANDLED;
+                       vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
+                       if (vcs & GT_RENDER_USER_INTERRUPT)
+                               notify_ring(dev, &dev_priv->ring[VCS]);
+                       I915_WRITE(GEN8_GT_IIR(1), tmp);
+               } else
+                       DRM_ERROR("The master control interrupt lied (GT1)!\n");
+       }
+
+       if (master_ctl & GEN8_GT_VECS_IRQ) {
+               tmp = I915_READ(GEN8_GT_IIR(3));
+               if (tmp) {
+                       ret = IRQ_HANDLED;
+                       vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
+                       if (vcs & GT_RENDER_USER_INTERRUPT)
+                               notify_ring(dev, &dev_priv->ring[VECS]);
+                       I915_WRITE(GEN8_GT_IIR(3), tmp);
+               } else
+                       DRM_ERROR("The master control interrupt lied (GT3)!\n");
+       }
+
+       return ret;
+}
+
 #define HPD_STORM_DETECT_PERIOD 1000
 #define HPD_STORM_THRESHOLD 5
 
@@ -1222,25 +1290,29 @@ static void dp_aux_irq_handler(struct drm_device *dev)
 }
 
 #if defined(CONFIG_DEBUG_FS)
-static void display_pipe_crc_update(struct drm_device *dev, enum pipe pipe,
-                                   uint32_t crc0, uint32_t crc1,
-                                   uint32_t crc2, uint32_t crc3,
-                                   uint32_t crc4)
+static void display_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe,
+                                        uint32_t crc0, uint32_t crc1,
+                                        uint32_t crc2, uint32_t crc3,
+                                        uint32_t crc4)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
        struct intel_pipe_crc_entry *entry;
        int head, tail;
 
+       spin_lock(&pipe_crc->lock);
+
        if (!pipe_crc->entries) {
+               spin_unlock(&pipe_crc->lock);
                DRM_ERROR("spurious interrupt\n");
                return;
        }
 
-       head = atomic_read(&pipe_crc->head);
-       tail = atomic_read(&pipe_crc->tail);
+       head = pipe_crc->head;
+       tail = pipe_crc->tail;
 
        if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) {
+               spin_unlock(&pipe_crc->lock);
                DRM_ERROR("CRC buffer overflowing\n");
                return;
        }
@@ -1255,48 +1327,63 @@ static void display_pipe_crc_update(struct drm_device *dev, enum pipe pipe,
        entry->crc[4] = crc4;
 
        head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
-       atomic_set(&pipe_crc->head, head);
+       pipe_crc->head = head;
+
+       spin_unlock(&pipe_crc->lock);
 
        wake_up_interruptible(&pipe_crc->wq);
 }
+#else
+static inline void
+display_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe,
+                            uint32_t crc0, uint32_t crc1,
+                            uint32_t crc2, uint32_t crc3,
+                            uint32_t crc4) {}
+#endif
+
 
-static void hsw_pipe_crc_update(struct drm_device *dev, enum pipe pipe)
+static void hsw_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       display_pipe_crc_update(dev, pipe,
-                               I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
-                               0, 0, 0, 0);
+       display_pipe_crc_irq_handler(dev, pipe,
+                                    I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
+                                    0, 0, 0, 0);
 }
 
-static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe)
+static void ivb_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       display_pipe_crc_update(dev, pipe,
-                               I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
-                               I915_READ(PIPE_CRC_RES_2_IVB(pipe)),
-                               I915_READ(PIPE_CRC_RES_3_IVB(pipe)),
-                               I915_READ(PIPE_CRC_RES_4_IVB(pipe)),
-                               I915_READ(PIPE_CRC_RES_5_IVB(pipe)));
+       display_pipe_crc_irq_handler(dev, pipe,
+                                    I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
+                                    I915_READ(PIPE_CRC_RES_2_IVB(pipe)),
+                                    I915_READ(PIPE_CRC_RES_3_IVB(pipe)),
+                                    I915_READ(PIPE_CRC_RES_4_IVB(pipe)),
+                                    I915_READ(PIPE_CRC_RES_5_IVB(pipe)));
 }
 
-static void ilk_pipe_crc_update(struct drm_device *dev, enum pipe pipe)
+static void i9xx_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t res1, res2;
+
+       if (INTEL_INFO(dev)->gen >= 3)
+               res1 = I915_READ(PIPE_CRC_RES_RES1_I915(pipe));
+       else
+               res1 = 0;
 
-       display_pipe_crc_update(dev, pipe,
-                               I915_READ(PIPE_CRC_RES_RED_ILK(pipe)),
-                               I915_READ(PIPE_CRC_RES_GREEN_ILK(pipe)),
-                               I915_READ(PIPE_CRC_RES_BLUE_ILK(pipe)),
-                               I915_READ(PIPE_CRC_RES_RES1_ILK(pipe)),
-                               I915_READ(PIPE_CRC_RES_RES2_ILK(pipe)));
+       if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
+               res2 = I915_READ(PIPE_CRC_RES_RES2_G4X(pipe));
+       else
+               res2 = 0;
+
+       display_pipe_crc_irq_handler(dev, pipe,
+                                    I915_READ(PIPE_CRC_RES_RED(pipe)),
+                                    I915_READ(PIPE_CRC_RES_GREEN(pipe)),
+                                    I915_READ(PIPE_CRC_RES_BLUE(pipe)),
+                                    res1, res2);
 }
-#else
-static inline void hsw_pipe_crc_update(struct drm_device *dev, int pipe) {}
-static inline void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {}
-static inline void ilk_pipe_crc_update(struct drm_device *dev, int pipe) {}
-#endif
 
 /* The RPS events need forcewake, so we add them to a work queue and mask their
  * IMR bits until the work is done. Other interrupts can be processed without
@@ -1365,13 +1452,16 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
                for_each_pipe(pipe) {
-                       if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
+                       if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
                                drm_handle_vblank(dev, pipe);
 
                        if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) {
                                intel_prepare_page_flip(dev, pipe);
                                intel_finish_page_flip(dev, pipe);
                        }
+
+                       if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
+                               i9xx_pipe_crc_irq_handler(dev, pipe);
                }
 
                /* Consume port.  Then clear IIR or we'll miss events */
@@ -1475,9 +1565,9 @@ static void ivb_err_int_handler(struct drm_device *dev)
 
                if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
                        if (IS_IVYBRIDGE(dev))
-                               ivb_pipe_crc_update(dev, pipe);
+                               ivb_pipe_crc_irq_handler(dev, pipe);
                        else
-                               hsw_pipe_crc_update(dev, pipe);
+                               hsw_pipe_crc_irq_handler(dev, pipe);
                }
        }
 
@@ -1550,6 +1640,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe;
 
        if (de_iir & DE_AUX_CHANNEL_A)
                dp_aux_irq_handler(dev);
@@ -1557,37 +1648,26 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
        if (de_iir & DE_GSE)
                intel_opregion_asle_intr(dev);
 
-       if (de_iir & DE_PIPEA_VBLANK)
-               drm_handle_vblank(dev, 0);
-
-       if (de_iir & DE_PIPEB_VBLANK)
-               drm_handle_vblank(dev, 1);
-
        if (de_iir & DE_POISON)
                DRM_ERROR("Poison interrupt\n");
 
-       if (de_iir & DE_PIPEA_FIFO_UNDERRUN)
-               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false))
-                       DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n");
-
-       if (de_iir & DE_PIPEB_FIFO_UNDERRUN)
-               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false))
-                       DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n");
-
-       if (de_iir & DE_PIPEA_CRC_DONE)
-               ilk_pipe_crc_update(dev, PIPE_A);
+       for_each_pipe(pipe) {
+               if (de_iir & DE_PIPE_VBLANK(pipe))
+                       drm_handle_vblank(dev, pipe);
 
-       if (de_iir & DE_PIPEB_CRC_DONE)
-               ilk_pipe_crc_update(dev, PIPE_B);
+               if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
+                       if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
+                                                pipe_name(pipe));
 
-       if (de_iir & DE_PLANEA_FLIP_DONE) {
-               intel_prepare_page_flip(dev, 0);
-               intel_finish_page_flip_plane(dev, 0);
-       }
+               if (de_iir & DE_PIPE_CRC_DONE(pipe))
+                       i9xx_pipe_crc_irq_handler(dev, pipe);
 
-       if (de_iir & DE_PLANEB_FLIP_DONE) {
-               intel_prepare_page_flip(dev, 1);
-               intel_finish_page_flip_plane(dev, 1);
+               /* plane/pipes map 1:1 on ilk+ */
+               if (de_iir & DE_PLANE_FLIP_DONE(pipe)) {
+                       intel_prepare_page_flip(dev, pipe);
+                       intel_finish_page_flip_plane(dev, pipe);
+               }
        }
 
        /* check event from PCH */
@@ -1610,7 +1690,7 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
+       enum pipe i;
 
        if (de_iir & DE_ERR_INT_IVB)
                ivb_err_int_handler(dev);
@@ -1621,10 +1701,12 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
        if (de_iir & DE_GSE_IVB)
                intel_opregion_asle_intr(dev);
 
-       for (i = 0; i < 3; i++) {
-               if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
+       for_each_pipe(i) {
+               if (de_iir & (DE_PIPE_VBLANK_IVB(i)))
                        drm_handle_vblank(dev, i);
-               if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) {
+
+               /* plane/pipes map 1:1 on ilk+ */
+               if (de_iir & DE_PLANE_FLIP_DONE_IVB(i)) {
                        intel_prepare_page_flip(dev, i);
                        intel_finish_page_flip_plane(dev, i);
                }
@@ -1709,6 +1791,117 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        return ret;
 }
 
+static irqreturn_t gen8_irq_handler(int irq, void *arg)
+{
+       struct drm_device *dev = arg;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 master_ctl;
+       irqreturn_t ret = IRQ_NONE;
+       uint32_t tmp = 0;
+       enum pipe pipe;
+
+       atomic_inc(&dev_priv->irq_received);
+
+       master_ctl = I915_READ(GEN8_MASTER_IRQ);
+       master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
+       if (!master_ctl)
+               return IRQ_NONE;
+
+       I915_WRITE(GEN8_MASTER_IRQ, 0);
+       POSTING_READ(GEN8_MASTER_IRQ);
+
+       ret = gen8_gt_irq_handler(dev, dev_priv, master_ctl);
+
+       if (master_ctl & GEN8_DE_MISC_IRQ) {
+               tmp = I915_READ(GEN8_DE_MISC_IIR);
+               if (tmp & GEN8_DE_MISC_GSE)
+                       intel_opregion_asle_intr(dev);
+               else if (tmp)
+                       DRM_ERROR("Unexpected DE Misc interrupt\n");
+               else
+                       DRM_ERROR("The master control interrupt lied (DE MISC)!\n");
+
+               if (tmp) {
+                       I915_WRITE(GEN8_DE_MISC_IIR, tmp);
+                       ret = IRQ_HANDLED;
+               }
+       }
+
+       if (master_ctl & GEN8_DE_PORT_IRQ) {
+               tmp = I915_READ(GEN8_DE_PORT_IIR);
+               if (tmp & GEN8_AUX_CHANNEL_A)
+                       dp_aux_irq_handler(dev);
+               else if (tmp)
+                       DRM_ERROR("Unexpected DE Port interrupt\n");
+               else
+                       DRM_ERROR("The master control interrupt lied (DE PORT)!\n");
+
+               if (tmp) {
+                       I915_WRITE(GEN8_DE_PORT_IIR, tmp);
+                       ret = IRQ_HANDLED;
+               }
+       }
+
+       for_each_pipe(pipe) {
+               uint32_t pipe_iir;
+
+               if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
+                       continue;
+
+               pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
+               if (pipe_iir & GEN8_PIPE_VBLANK)
+                       drm_handle_vblank(dev, pipe);
+
+               if (pipe_iir & GEN8_PIPE_FLIP_DONE) {
+                       intel_prepare_page_flip(dev, pipe);
+                       intel_finish_page_flip_plane(dev, pipe);
+               }
+
+               if (pipe_iir & GEN8_PIPE_CDCLK_CRC_DONE)
+                       hsw_pipe_crc_irq_handler(dev, pipe);
+
+               if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
+                       if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
+                                                                 false))
+                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
+                                                pipe_name(pipe));
+               }
+
+               if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
+                       DRM_ERROR("Fault errors on pipe %c\n: 0x%08x",
+                                 pipe_name(pipe),
+                                 pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS);
+               }
+
+               if (pipe_iir) {
+                       ret = IRQ_HANDLED;
+                       I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
+               } else
+                       DRM_ERROR("The master control interrupt lied (DE PIPE)!\n");
+       }
+
+       if (!HAS_PCH_NOP(dev) && master_ctl & GEN8_DE_PCH_IRQ) {
+               /*
+                * FIXME(BDW): Assume for now that the new interrupt handling
+                * scheme also closed the SDE interrupt handling race we've seen
+                * on older pch-split platforms. But this needs testing.
+                */
+               u32 pch_iir = I915_READ(SDEIIR);
+
+               cpt_irq_handler(dev, pch_iir);
+
+               if (pch_iir) {
+                       I915_WRITE(SDEIIR, pch_iir);
+                       ret = IRQ_HANDLED;
+               }
+       }
+
+       I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
+       POSTING_READ(GEN8_MASTER_IRQ);
+
+       return ret;
+}
+
 static void i915_error_wake_up(struct drm_i915_private *dev_priv,
                               bool reset_completed)
 {
@@ -2027,7 +2220,7 @@ static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
        uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
-                                                    DE_PIPE_VBLANK_ILK(pipe);
+                                                    DE_PIPE_VBLANK(pipe);
 
        if (!i915_pipe_enabled(dev, pipe))
                return -EINVAL;
@@ -2050,7 +2243,7 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        imr = I915_READ(VLV_IMR);
-       if (pipe == 0)
+       if (pipe == PIPE_A)
                imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
        else
                imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
@@ -2062,6 +2255,22 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
        return 0;
 }
 
+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]);
+       POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       return 0;
+}
+
 /* Called from drm generic code, passed 'crtc' which
  * we use as a pipe index
  */
@@ -2085,7 +2294,7 @@ static void ironlake_disable_vblank(struct drm_device *dev, int pipe)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
        uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
-                                                    DE_PIPE_VBLANK_ILK(pipe);
+                                                    DE_PIPE_VBLANK(pipe);
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        ironlake_disable_display_irq(dev_priv, bit);
@@ -2102,7 +2311,7 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
        i915_disable_pipestat(dev_priv, pipe,
                              PIPE_START_VBLANK_INTERRUPT_ENABLE);
        imr = I915_READ(VLV_IMR);
-       if (pipe == 0)
+       if (pipe == PIPE_A)
                imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
        else
                imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
@@ -2110,6 +2319,21 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
+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]);
+       POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
 static u32
 ring_last_seqno(struct intel_ring_buffer *ring)
 {
@@ -2268,8 +2492,12 @@ static void i915_hangcheck_elapsed(unsigned long data)
                                if (waitqueue_active(&ring->irq_queue)) {
                                        /* Issue a wake-up to catch stuck h/w. */
                                        if (!test_and_set_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings)) {
-                                               DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
-                                                         ring->name);
+                                               if (!(dev_priv->gpu_error.test_irq_rings & intel_ring_flag(ring)))
+                                                       DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
+                                                                 ring->name);
+                                               else
+                                                       DRM_INFO("Fake missed irq on %s\n",
+                                                                ring->name);
                                                wake_up_all(&ring->irq_queue);
                                        }
                                        /* Safeguard against driver failure */
@@ -2440,6 +2668,53 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
        POSTING_READ(VLV_IER);
 }
 
+static void gen8_irq_preinstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe;
+
+       atomic_set(&dev_priv->irq_received, 0);
+
+       I915_WRITE(GEN8_MASTER_IRQ, 0);
+       POSTING_READ(GEN8_MASTER_IRQ);
+
+       /* IIR can theoretically queue up two events. Be paranoid */
+#define GEN8_IRQ_INIT_NDX(type, which) do { \
+               I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
+               POSTING_READ(GEN8_##type##_IMR(which)); \
+               I915_WRITE(GEN8_##type##_IER(which), 0); \
+               I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
+               POSTING_READ(GEN8_##type##_IIR(which)); \
+               I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
+       } while (0)
+
+#define GEN8_IRQ_INIT(type) do { \
+               I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \
+               POSTING_READ(GEN8_##type##_IMR); \
+               I915_WRITE(GEN8_##type##_IER, 0); \
+               I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \
+               POSTING_READ(GEN8_##type##_IIR); \
+               I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \
+       } while (0)
+
+       GEN8_IRQ_INIT_NDX(GT, 0);
+       GEN8_IRQ_INIT_NDX(GT, 1);
+       GEN8_IRQ_INIT_NDX(GT, 2);
+       GEN8_IRQ_INIT_NDX(GT, 3);
+
+       for_each_pipe(pipe) {
+               GEN8_IRQ_INIT_NDX(DE_PIPE, pipe);
+       }
+
+       GEN8_IRQ_INIT(DE_PORT);
+       GEN8_IRQ_INIT(DE_MISC);
+       GEN8_IRQ_INIT(PCU);
+#undef GEN8_IRQ_INIT
+#undef GEN8_IRQ_INIT_NDX
+
+       POSTING_READ(GEN8_PCU_IIR);
+}
+
 static void ibx_hpd_irq_setup(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -2593,7 +2868,8 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 enable_mask;
-       u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
+       u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV |
+               PIPE_CRC_DONE_ENABLE;
        unsigned long irqflags;
 
        enable_mask = I915_DISPLAY_PORT_INTERRUPT;
@@ -2623,9 +2899,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, 0, pipestat_enable);
-       i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
-       i915_enable_pipestat(dev_priv, 1, pipestat_enable);
+       i915_enable_pipestat(dev_priv, PIPE_A, pipestat_enable);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, pipestat_enable);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        I915_WRITE(VLV_IIR, 0xffffffff);
@@ -2644,6 +2920,117 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
+static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
+{
+       int i;
+
+       /* These are interrupts we'll toggle with the ring mask register */
+       uint32_t gt_interrupts[] = {
+               GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+                       GT_RENDER_L3_PARITY_ERROR_INTERRUPT |
+                       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
+               GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
+                       GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
+               0,
+               GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT
+               };
+
+       for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) {
+               u32 tmp = I915_READ(GEN8_GT_IIR(i));
+               if (tmp)
+                       DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n",
+                                 i, tmp);
+               I915_WRITE(GEN8_GT_IMR(i), ~gt_interrupts[i]);
+               I915_WRITE(GEN8_GT_IER(i), gt_interrupts[i]);
+       }
+       POSTING_READ(GEN8_GT_IER(0));
+}
+
+static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE |
+               GEN8_PIPE_CDCLK_CRC_DONE |
+               GEN8_PIPE_FIFO_UNDERRUN |
+               GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
+       uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK;
+       int pipe;
+       dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked;
+       dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
+       dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked;
+
+       for_each_pipe(pipe) {
+               u32 tmp = I915_READ(GEN8_DE_PIPE_IIR(pipe));
+               if (tmp)
+                       DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n",
+                                 pipe, tmp);
+               I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
+               I915_WRITE(GEN8_DE_PIPE_IER(pipe), de_pipe_enables);
+       }
+       POSTING_READ(GEN8_DE_PIPE_ISR(0));
+
+       I915_WRITE(GEN8_DE_PORT_IMR, ~GEN8_AUX_CHANNEL_A);
+       I915_WRITE(GEN8_DE_PORT_IER, GEN8_AUX_CHANNEL_A);
+       POSTING_READ(GEN8_DE_PORT_IER);
+}
+
+static int gen8_irq_postinstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       gen8_gt_irq_postinstall(dev_priv);
+       gen8_de_irq_postinstall(dev_priv);
+
+       ibx_irq_postinstall(dev);
+
+       I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL);
+       POSTING_READ(GEN8_MASTER_IRQ);
+
+       return 0;
+}
+
+static void gen8_irq_uninstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe;
+
+       if (!dev_priv)
+               return;
+
+       atomic_set(&dev_priv->irq_received, 0);
+
+       I915_WRITE(GEN8_MASTER_IRQ, 0);
+
+#define GEN8_IRQ_FINI_NDX(type, which) do { \
+               I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
+               I915_WRITE(GEN8_##type##_IER(which), 0); \
+               I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
+       } while (0)
+
+#define GEN8_IRQ_FINI(type) do { \
+               I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \
+               I915_WRITE(GEN8_##type##_IER, 0); \
+               I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \
+       } while (0)
+
+       GEN8_IRQ_FINI_NDX(GT, 0);
+       GEN8_IRQ_FINI_NDX(GT, 1);
+       GEN8_IRQ_FINI_NDX(GT, 2);
+       GEN8_IRQ_FINI_NDX(GT, 3);
+
+       for_each_pipe(pipe) {
+               GEN8_IRQ_FINI_NDX(DE_PIPE, pipe);
+       }
+
+       GEN8_IRQ_FINI(DE_PORT);
+       GEN8_IRQ_FINI(DE_MISC);
+       GEN8_IRQ_FINI(PCU);
+#undef GEN8_IRQ_FINI
+#undef GEN8_IRQ_FINI_NDX
+
+       POSTING_READ(GEN8_PCU_IIR);
+}
+
 static void valleyview_irq_uninstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -2716,6 +3103,7 @@ static void i8xx_irq_preinstall(struct drm_device * dev)
 static int i8xx_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
 
        I915_WRITE16(EMR,
                     ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
@@ -2736,6 +3124,13 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
                     I915_USER_INTERRUPT);
        POSTING_READ16(IER);
 
+       /* Interrupt setup is already guaranteed to be single-threaded, this is
+        * just to make the assert_spin_locked check happy. */
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
        return 0;
 }
 
@@ -2822,13 +3217,14 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                if (iir & I915_USER_INTERRUPT)
                        notify_ring(dev, &dev_priv->ring[RCS]);
 
-               if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS &&
-                   i8xx_handle_vblank(dev, 0, iir))
-                       flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(0);
+               for_each_pipe(pipe) {
+                       if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
+                           i8xx_handle_vblank(dev, pipe, iir))
+                               flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
 
-               if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS &&
-                   i8xx_handle_vblank(dev, 1, iir))
-                       flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(1);
+                       if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
+                               i9xx_pipe_crc_irq_handler(dev, pipe);
+               }
 
                iir = new_iir;
        }
@@ -2875,6 +3271,7 @@ static int i915_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 enable_mask;
+       unsigned long irqflags;
 
        I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
 
@@ -2910,6 +3307,13 @@ static int i915_irq_postinstall(struct drm_device *dev)
 
        i915_enable_asle_pipestat(dev);
 
+       /* Interrupt setup is already guaranteed to be single-threaded, this is
+        * just to make the assert_spin_locked check happy. */
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
        return 0;
 }
 
@@ -3021,6 +3425,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
                                blc_event = true;
+
+                       if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
+                               i9xx_pipe_crc_irq_handler(dev, pipe);
                }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
@@ -3119,7 +3526,9 @@ static int i965_irq_postinstall(struct drm_device *dev)
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        /*
@@ -3265,6 +3674,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
                                blc_event = true;
+
+                       if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
+                               i9xx_pipe_crc_irq_handler(dev, pipe);
                }
 
 
@@ -3398,6 +3810,14 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->enable_vblank = valleyview_enable_vblank;
                dev->driver->disable_vblank = valleyview_disable_vblank;
                dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
+       } else if (IS_GEN8(dev)) {
+               dev->driver->irq_handler = gen8_irq_handler;
+               dev->driver->irq_preinstall = gen8_irq_preinstall;
+               dev->driver->irq_postinstall = gen8_irq_postinstall;
+               dev->driver->irq_uninstall = gen8_irq_uninstall;
+               dev->driver->enable_vblank = gen8_enable_vblank;
+               dev->driver->disable_vblank = gen8_disable_vblank;
+               dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
        } else if (HAS_PCH_SPLIT(dev)) {
                dev->driver->irq_handler = ironlake_irq_handler;
                dev->driver->irq_preinstall = ironlake_irq_preinstall;
index 0e7488b..f9eafb6 100644 (file)
 #define RING_PP_DIR_DCLV(ring)         ((ring)->mmio_base+0x220)
 #define   PP_DIR_DCLV_2G               0xffffffff
 
+#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 GAM_ECOCHK                     0x4090
 #define   ECOCHK_SNB_BIT               (1<<10)
 #define   HSW_ECOCHK_ARB_PRIO_SOL      (1<<6)
 #define   MI_BATCH_NON_SECURE_HSW      (1<<13)
 #define MI_BATCH_BUFFER_START  MI_INSTR(0x31, 0)
 #define   MI_BATCH_GTT             (2<<6) /* aliased with (1<<7) on gen4 */
+#define MI_BATCH_BUFFER_START_GEN8     MI_INSTR(0x31, 1)
 #define MI_SEMAPHORE_MBOX      MI_INSTR(0x16, 1) /* gen6+ */
 #define  MI_SEMAPHORE_GLOBAL_GTT    (1<<22)
 #define  MI_SEMAPHORE_UPDATE       (1<<21)
 
 #define _DPIO_TX3_SWING_CTL4_A         0x690
 #define _DPIO_TX3_SWING_CTL4_B         0x2a90
-#define DPIO_TX3_SWING_CTL4(pipe) _PIPE(pipe, _DPIO_TX_SWING_CTL4_A, \
+#define DPIO_TX3_SWING_CTL4(pipe) _PIPE(pipe, _DPIO_TX3_SWING_CTL4_A, \
                                        _DPIO_TX3_SWING_CTL4_B)
 
 /*
 #define ARB_MODE               0x04030
 #define   ARB_MODE_SWIZZLE_SNB (1<<4)
 #define   ARB_MODE_SWIZZLE_IVB (1<<5)
+#define GAMTARBMODE            0x04a08
+#define   ARB_MODE_BWGTLB_DISABLE (1<<9)
+#define   ARB_MODE_SWIZZLE_BDW (1<<1)
 #define RENDER_HWS_PGA_GEN7    (0x04080)
 #define RING_FAULT_REG(ring)   (0x4094 + 0x100*(ring)->id)
+#define   RING_FAULT_GTTSEL_MASK (1<<11)
+#define   RING_FAULT_SRCID(x)  ((x >> 3) & 0xff)
+#define   RING_FAULT_FAULT_TYPE(x) ((x >> 1) & 0x3)
+#define   RING_FAULT_VALID     (1<<0)
 #define DONE_REG               0x40b0
+#define GEN8_PRIVATE_PAT       0x40e0
 #define BSD_HWS_PGA_GEN7       (0x04180)
 #define BLT_HWS_PGA_GEN7       (0x04280)
 #define VEBOX_HWS_PGA_GEN7     (0x04380)
 #define NOPID          0x02094
 #define HWSTAM         0x02098
 #define DMA_FADD_I8XX  0x020d0
+#define RING_BBSTATE(base)     ((base)+0x110)
 
 #define ERROR_GEN6     0x040a0
 #define GEN7_ERR_INT   0x44040
 #define   FPGA_DBG_RM_NOCLAIM  (1<<31)
 
 #define DERRMR         0x44050
+/* Note that HBLANK events are reserved on bdw+ */
 #define   DERRMR_PIPEA_SCANLINE                (1<<0)
 #define   DERRMR_PIPEA_PRI_FLIP_DONE   (1<<1)
 #define   DERRMR_PIPEA_SPR_FLIP_DONE   (1<<2)
 #define _3D_CHICKEN3   0x02090
 #define  _3D_CHICKEN_SF_DISABLE_OBJEND_CULL            (1 << 10)
 #define  _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL         (1 << 5)
+#define  _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x)      ((x)<<1)
 
 #define MI_MODE                0x0209c
 # define VS_TIMER_DISPATCH                             (1 << 6)
                                             _HSW_PIPE_SLICE_CHICKEN_1_A, + \
                                             _HSW_PIPE_SLICE_CHICKEN_1_B)
 
-#define HSW_CLKGATE_DISABLE_PART_1     0x46500
-#define   HSW_DPFC_GATING_DISABLE      (1<<23)
-
 /*
  * GPIO regs
  */
 #define MCHBAR_MIRROR_BASE_SNB 0x140000
 
 /* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */
-#define DCLK 0x5e04
+#define DCLK (MCHBAR_MIRROR_BASE_SNB + 0x5e04)
 
 /** 915-945 and GM965 MCH register controlling DRAM channel access */
 #define DCC                    0x10200
 #define GEN6_GT_THREAD_STATUS_CORE_MASK 0x7
 #define GEN6_GT_THREAD_STATUS_CORE_MASK_HSW (0x7 | (0x07 << 16))
 
-#define GEN6_GT_PERF_STATUS    0x145948
-#define GEN6_RP_STATE_LIMITS   0x145994
-#define GEN6_RP_STATE_CAP      0x145998
+#define GEN6_GT_PERF_STATUS    (MCHBAR_MIRROR_BASE_SNB + 0x5948)
+#define GEN6_RP_STATE_LIMITS   (MCHBAR_MIRROR_BASE_SNB + 0x5994)
+#define GEN6_RP_STATE_CAP      (MCHBAR_MIRROR_BASE_SNB + 0x5998)
 
 /*
  * Logical Context regs
  * on HSW) - so the final size is 66944 bytes, which rounds to 17 pages.
  */
 #define HSW_CXT_TOTAL_SIZE             (17 * PAGE_SIZE)
+/* Same as Haswell, but 72064 bytes now. */
+#define GEN8_CXT_TOTAL_SIZE            (18 * PAGE_SIZE)
+
 
 #define VLV_CLK_CTL2                   0x101104
 #define   CLK_CTL2_CZCOUNT_30NS_SHIFT  28
 /* Pipe A CRC regs */
 #define _PIPE_CRC_CTL_A                (dev_priv->info->display_mmio_offset + 0x60050)
 #define   PIPE_CRC_ENABLE              (1 << 31)
+/* ivb+ source selection */
 #define   PIPE_CRC_SOURCE_PRIMARY_IVB  (0 << 29)
 #define   PIPE_CRC_SOURCE_SPRITE_IVB   (1 << 29)
 #define   PIPE_CRC_SOURCE_PF_IVB       (2 << 29)
+/* ilk+ source selection */
 #define   PIPE_CRC_SOURCE_PRIMARY_ILK  (0 << 28)
 #define   PIPE_CRC_SOURCE_SPRITE_ILK   (1 << 28)
 #define   PIPE_CRC_SOURCE_PIPE_ILK     (2 << 28)
 /* embedded DP port on the north display block, reserved on ivb */
 #define   PIPE_CRC_SOURCE_PORT_A_ILK   (4 << 28)
 #define   PIPE_CRC_SOURCE_FDI_ILK      (5 << 28) /* reserved on ivb */
+/* vlv source selection */
+#define   PIPE_CRC_SOURCE_PIPE_VLV     (0 << 27)
+#define   PIPE_CRC_SOURCE_HDMIB_VLV    (1 << 27)
+#define   PIPE_CRC_SOURCE_HDMIC_VLV    (2 << 27)
+/* with DP port the pipe source is invalid */
+#define   PIPE_CRC_SOURCE_DP_D_VLV     (3 << 27)
+#define   PIPE_CRC_SOURCE_DP_B_VLV     (6 << 27)
+#define   PIPE_CRC_SOURCE_DP_C_VLV     (7 << 27)
+/* gen3+ source selection */
+#define   PIPE_CRC_SOURCE_PIPE_I9XX    (0 << 28)
+#define   PIPE_CRC_SOURCE_SDVOB_I9XX   (1 << 28)
+#define   PIPE_CRC_SOURCE_SDVOC_I9XX   (2 << 28)
+/* with DP/TV port the pipe source is invalid */
+#define   PIPE_CRC_SOURCE_DP_D_G4X     (3 << 28)
+#define   PIPE_CRC_SOURCE_TV_PRE       (4 << 28)
+#define   PIPE_CRC_SOURCE_TV_POST      (5 << 28)
+#define   PIPE_CRC_SOURCE_DP_B_G4X     (6 << 28)
+#define   PIPE_CRC_SOURCE_DP_C_G4X     (7 << 28)
+/* gen2 doesn't have source selection bits */
+#define   PIPE_CRC_INCLUDE_BORDER_I8XX (1 << 30)
+
 #define _PIPE_CRC_RES_1_A_IVB          0x60064
 #define _PIPE_CRC_RES_2_A_IVB          0x60068
 #define _PIPE_CRC_RES_3_A_IVB          0x6006c
 #define _PIPE_CRC_RES_4_A_IVB          0x60070
 #define _PIPE_CRC_RES_5_A_IVB          0x60074
 
-#define _PIPE_CRC_RES_RED_A_ILK                0x60060
-#define _PIPE_CRC_RES_GREEN_A_ILK      0x60064
-#define _PIPE_CRC_RES_BLUE_A_ILK       0x60068
-#define _PIPE_CRC_RES_RES1_A_ILK       0x6006c
-#define _PIPE_CRC_RES_RES2_A_ILK       0x60080
+#define _PIPE_CRC_RES_RED_A            (dev_priv->info->display_mmio_offset + 0x60060)
+#define _PIPE_CRC_RES_GREEN_A          (dev_priv->info->display_mmio_offset + 0x60064)
+#define _PIPE_CRC_RES_BLUE_A           (dev_priv->info->display_mmio_offset + 0x60068)
+#define _PIPE_CRC_RES_RES1_A_I915      (dev_priv->info->display_mmio_offset + 0x6006c)
+#define _PIPE_CRC_RES_RES2_A_G4X       (dev_priv->info->display_mmio_offset + 0x60080)
 
 /* Pipe B CRC regs */
-#define _PIPE_CRC_CTL_B                        0x61050
 #define _PIPE_CRC_RES_1_B_IVB          0x61064
 #define _PIPE_CRC_RES_2_B_IVB          0x61068
 #define _PIPE_CRC_RES_3_B_IVB          0x6106c
 #define _PIPE_CRC_RES_4_B_IVB          0x61070
 #define _PIPE_CRC_RES_5_B_IVB          0x61074
 
-#define PIPE_CRC_CTL(pipe)     _PIPE(pipe, _PIPE_CRC_CTL_A, _PIPE_CRC_CTL_B)
+#define PIPE_CRC_CTL(pipe)     _PIPE_INC(pipe, _PIPE_CRC_CTL_A, 0x01000)
 #define PIPE_CRC_RES_1_IVB(pipe)       \
        _PIPE(pipe, _PIPE_CRC_RES_1_A_IVB, _PIPE_CRC_RES_1_B_IVB)
 #define PIPE_CRC_RES_2_IVB(pipe)       \
 #define PIPE_CRC_RES_5_IVB(pipe)       \
        _PIPE(pipe, _PIPE_CRC_RES_5_A_IVB, _PIPE_CRC_RES_5_B_IVB)
 
-#define PIPE_CRC_RES_RED_ILK(pipe) \
-       _PIPE_INC(pipe, _PIPE_CRC_RES_RED_A_ILK, 0x01000)
-#define PIPE_CRC_RES_GREEN_ILK(pipe) \
-       _PIPE_INC(pipe, _PIPE_CRC_RES_GREEN_A_ILK, 0x01000)
-#define PIPE_CRC_RES_BLUE_ILK(pipe) \
-       _PIPE_INC(pipe, _PIPE_CRC_RES_BLUE_A_ILK, 0x01000)
-#define PIPE_CRC_RES_RES1_ILK(pipe) \
-       _PIPE_INC(pipe, _PIPE_CRC_RES_RES1_A_ILK, 0x01000)
-#define PIPE_CRC_RES_RES2_ILK(pipe) \
-       _PIPE_INC(pipe, _PIPE_CRC_RES_RES2_A_ILK, 0x01000)
+#define PIPE_CRC_RES_RED(pipe) \
+       _PIPE_INC(pipe, _PIPE_CRC_RES_RED_A, 0x01000)
+#define PIPE_CRC_RES_GREEN(pipe) \
+       _PIPE_INC(pipe, _PIPE_CRC_RES_GREEN_A, 0x01000)
+#define PIPE_CRC_RES_BLUE(pipe) \
+       _PIPE_INC(pipe, _PIPE_CRC_RES_BLUE_A, 0x01000)
+#define PIPE_CRC_RES_RES1_I915(pipe) \
+       _PIPE_INC(pipe, _PIPE_CRC_RES_RES1_A_I915, 0x01000)
+#define PIPE_CRC_RES_RES2_G4X(pipe) \
+       _PIPE_INC(pipe, _PIPE_CRC_RES_RES2_A_G4X, 0x01000)
 
 /* Pipe A timing regs */
 #define _HTOTAL_A      (dev_priv->info->display_mmio_offset + 0x60000)
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
-/* HSW eDP PSR registers */
-#define EDP_PSR_BASE(dev)                      0x64800
+/* HSW+ eDP PSR registers */
+#define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)                       (EDP_PSR_BASE(dev) + 0)
 #define   EDP_PSR_ENABLE                       (1<<31)
 #define   EDP_PSR_LINK_DISABLE                 (0<<27)
 #define PCH_HDMIC      0xe1150
 #define PCH_HDMID      0xe1160
 
+#define PORT_DFT_I9XX                          0x61150
+#define   DC_BALANCE_RESET                     (1 << 25)
+#define PORT_DFT2_G4X                          0x61154
+#define   DC_BALANCE_RESET_VLV                 (1 << 31)
+#define   PIPE_SCRAMBLE_RESET_MASK             (0x3 << 0)
+#define   PIPE_B_SCRAMBLE_RESET                        (1 << 1)
+#define   PIPE_A_SCRAMBLE_RESET                        (1 << 0)
+
 /* Gen 3 SDVO bits: */
 #define   SDVO_ENABLE                          (1 << 31)
 #define   SDVO_PIPE_SEL(pipe)                  ((pipe) << 30)
 
 #define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238)
 
+#define _VLV_BLC_PWM_CTL2_A (dev_priv->info->display_mmio_offset + 0x61250)
+#define _VLV_BLC_PWM_CTL2_B (dev_priv->info->display_mmio_offset + 0x61350)
+#define VLV_BLC_PWM_CTL2(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \
+                                    _VLV_BLC_PWM_CTL2_B)
+
+#define _VLV_BLC_PWM_CTL_A (dev_priv->info->display_mmio_offset + 0x61254)
+#define _VLV_BLC_PWM_CTL_B (dev_priv->info->display_mmio_offset + 0x61354)
+#define VLV_BLC_PWM_CTL(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL_A, \
+                                   _VLV_BLC_PWM_CTL_B)
+
+#define _VLV_BLC_HIST_CTL_A (dev_priv->info->display_mmio_offset + 0x61260)
+#define _VLV_BLC_HIST_CTL_B (dev_priv->info->display_mmio_offset + 0x61360)
+#define VLV_BLC_HIST_CTL(pipe) _PIPE(pipe, _VLV_BLC_HIST_CTL_A, \
+                                    _VLV_BLC_HIST_CTL_B)
+
 /* Backlight control */
 #define BLC_PWM_CTL2   (dev_priv->info->display_mmio_offset + 0x61250) /* 965+ only */
 #define   BLM_PWM_ENABLE               (1 << 31)
 #define PIPEFRAMEPIXEL(pipe)  _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL)
 #define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT)
 
+#define _PIPE_MISC_A                   0x70030
+#define _PIPE_MISC_B                   0x71030
+#define   PIPEMISC_DITHER_BPC_MASK     (7<<5)
+#define   PIPEMISC_DITHER_8_BPC                (0<<5)
+#define   PIPEMISC_DITHER_10_BPC       (1<<5)
+#define   PIPEMISC_DITHER_6_BPC                (2<<5)
+#define   PIPEMISC_DITHER_12_BPC       (3<<5)
+#define   PIPEMISC_DITHER_ENABLE       (1<<4)
+#define   PIPEMISC_DITHER_TYPE_MASK    (3<<2)
+#define   PIPEMISC_DITHER_TYPE_SP      (0<<2)
+#define PIPEMISC(pipe) _PIPE(pipe, _PIPE_MISC_A, _PIPE_MISC_B)
+
 #define VLV_DPFLIPSTAT                         (VLV_DISPLAY_BASE + 0x70028)
 #define   PIPEB_LINE_COMPARE_INT_EN            (1<<29)
 #define   PIPEB_HLINE_INT_EN                   (1<<28)
 #define  WM1_LP_LATENCY_MASK   (0x7f<<24)
 #define  WM1_LP_FBC_MASK       (0xf<<20)
 #define  WM1_LP_FBC_SHIFT      20
+#define  WM1_LP_FBC_SHIFT_BDW  19
 #define  WM1_LP_SR_MASK                (0x7ff<<8)
 #define  WM1_LP_SR_SHIFT       8
 #define  WM1_LP_CURSOR_MASK    (0xff)
 #define DE_SPRITEA_FLIP_DONE    (1 << 28)
 #define DE_PLANEB_FLIP_DONE     (1 << 27)
 #define DE_PLANEA_FLIP_DONE     (1 << 26)
+#define DE_PLANE_FLIP_DONE(plane) (1 << (26 + (plane)))
 #define DE_PCU_EVENT            (1 << 25)
 #define DE_GTT_FAULT            (1 << 24)
 #define DE_POISON               (1 << 23)
 #define DE_PIPEB_CRC_DONE      (1 << 10)
 #define DE_PIPEB_FIFO_UNDERRUN  (1 << 8)
 #define DE_PIPEA_VBLANK         (1 << 7)
+#define DE_PIPE_VBLANK(pipe)    (1 << (7 + 8*(pipe)))
 #define DE_PIPEA_EVEN_FIELD     (1 << 6)
 #define DE_PIPEA_ODD_FIELD      (1 << 5)
 #define DE_PIPEA_LINE_COMPARE   (1 << 4)
 #define DE_PIPEA_VSYNC          (1 << 3)
 #define DE_PIPEA_CRC_DONE      (1 << 2)
+#define DE_PIPE_CRC_DONE(pipe) (1 << (2 + 8*(pipe)))
 #define DE_PIPEA_FIFO_UNDERRUN  (1 << 0)
+#define DE_PIPE_FIFO_UNDERRUN(pipe)  (1 << (8*(pipe)))
 
 /* More Ivybridge lolz */
 #define DE_ERR_INT_IVB                 (1<<30)
 #define DE_PIPEB_VBLANK_IVB            (1<<5)
 #define DE_SPRITEA_FLIP_DONE_IVB       (1<<4)
 #define DE_PLANEA_FLIP_DONE_IVB                (1<<3)
+#define DE_PLANE_FLIP_DONE_IVB(plane)  (1<< (3 + 5*(plane)))
 #define DE_PIPEA_VBLANK_IVB            (1<<0)
-
-#define DE_PIPE_VBLANK_ILK(pipe)       (1 << ((pipe * 8) + 7))
 #define DE_PIPE_VBLANK_IVB(pipe)       (1 << (pipe * 5))
 
 #define VLV_MASTER_IER                 0x4400c /* Gunit master IER */
 #define GTIIR   0x44018
 #define GTIER   0x4401c
 
+#define GEN8_MASTER_IRQ                        0x44200
+#define  GEN8_MASTER_IRQ_CONTROL       (1<<31)
+#define  GEN8_PCU_IRQ                  (1<<30)
+#define  GEN8_DE_PCH_IRQ               (1<<23)
+#define  GEN8_DE_MISC_IRQ              (1<<22)
+#define  GEN8_DE_PORT_IRQ              (1<<20)
+#define  GEN8_DE_PIPE_C_IRQ            (1<<18)
+#define  GEN8_DE_PIPE_B_IRQ            (1<<17)
+#define  GEN8_DE_PIPE_A_IRQ            (1<<16)
+#define  GEN8_DE_PIPE_IRQ(pipe)                (1<<(16+pipe))
+#define  GEN8_GT_VECS_IRQ              (1<<6)
+#define  GEN8_GT_VCS2_IRQ              (1<<3)
+#define  GEN8_GT_VCS1_IRQ              (1<<2)
+#define  GEN8_GT_BCS_IRQ               (1<<1)
+#define  GEN8_GT_RCS_IRQ               (1<<0)
+
+#define GEN8_GT_ISR(which) (0x44300 + (0x10 * (which)))
+#define GEN8_GT_IMR(which) (0x44304 + (0x10 * (which)))
+#define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
+#define GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
+
+#define GEN8_BCS_IRQ_SHIFT 16
+#define GEN8_RCS_IRQ_SHIFT 0
+#define GEN8_VCS2_IRQ_SHIFT 16
+#define GEN8_VCS1_IRQ_SHIFT 0
+#define GEN8_VECS_IRQ_SHIFT 0
+
+#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe)))
+#define  GEN8_PIPE_FIFO_UNDERRUN       (1 << 31)
+#define  GEN8_PIPE_CDCLK_CRC_ERROR     (1 << 29)
+#define  GEN8_PIPE_CDCLK_CRC_DONE      (1 << 28)
+#define  GEN8_PIPE_CURSOR_FAULT                (1 << 10)
+#define  GEN8_PIPE_SPRITE_FAULT                (1 << 9)
+#define  GEN8_PIPE_PRIMARY_FAULT       (1 << 8)
+#define  GEN8_PIPE_SPRITE_FLIP_DONE    (1 << 5)
+#define  GEN8_PIPE_FLIP_DONE           (1 << 4)
+#define  GEN8_PIPE_SCAN_LINE_EVENT     (1 << 2)
+#define  GEN8_PIPE_VSYNC               (1 << 1)
+#define  GEN8_PIPE_VBLANK              (1 << 0)
+#define GEN8_DE_PIPE_IRQ_FAULT_ERRORS \
+       (GEN8_PIPE_CURSOR_FAULT | \
+        GEN8_PIPE_SPRITE_FAULT | \
+        GEN8_PIPE_PRIMARY_FAULT)
+
+#define GEN8_DE_PORT_ISR 0x44440
+#define GEN8_DE_PORT_IMR 0x44444
+#define GEN8_DE_PORT_IIR 0x44448
+#define GEN8_DE_PORT_IER 0x4444c
+#define  GEN8_PORT_DP_A_HOTPLUG                (1 << 3)
+#define  GEN8_AUX_CHANNEL_A            (1 << 0)
+
+#define GEN8_DE_MISC_ISR 0x44460
+#define GEN8_DE_MISC_IMR 0x44464
+#define GEN8_DE_MISC_IIR 0x44468
+#define GEN8_DE_MISC_IER 0x4446c
+#define  GEN8_DE_MISC_GSE              (1 << 27)
+
+#define GEN8_PCU_ISR 0x444e0
+#define GEN8_PCU_IMR 0x444e4
+#define GEN8_PCU_IIR 0x444e8
+#define GEN8_PCU_IER 0x444ec
+
 #define ILK_DISPLAY_CHICKEN2   0x42004
 /* Required on all Ironlake and Sandybridge according to the B-Spec. */
 #define  ILK_ELPIN_409_SELECT  (1 << 25)
 # define CHICKEN3_DGMG_DONE_FIX_DISABLE                (1 << 2)
 
 #define CHICKEN_PAR1_1         0x42080
+#define  DPA_MASK_VBLANK_SRD   (1 << 15)
 #define  FORCE_ARB_IDLE_PLANES (1 << 14)
 
+#define _CHICKEN_PIPESL_1_A    0x420b0
+#define _CHICKEN_PIPESL_1_B    0x420b4
+#define  DPRS_MASK_VBLANK_SRD  (1 << 0)
+#define CHICKEN_PIPESL_1(pipe) _PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)
+
 #define DISP_ARB_CTL   0x45000
 #define  DISP_TILE_SURFACE_SWIZZLING   (1<<13)
 #define  DISP_FBC_WM_DIS               (1<<15)
 /* GEN7 chicken */
 #define GEN7_COMMON_SLICE_CHICKEN1             0x7010
 # define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC     ((1<<10) | (1<<26))
+#define COMMON_SLICE_CHICKEN2                  0x7014
+# define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE  (1<<0)
 
 #define GEN7_L3CNTLREG1                                0xB01C
 #define  GEN7_WA_FOR_GEN7_L3_CONTROL                   0x3C4FFF8C
 #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG         0x9030
 #define  GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB      (1<<11)
 
+#define HSW_SCRATCH1                           0xb038
+#define  HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE  (1<<27)
+
 #define HSW_FUSE_STRAP         0x42014
 #define  HSW_CDCLK_LIMIT       (1 << 24)
 
 #define FDI_RX_CHICKEN(pipe) _PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN)
 
 #define SOUTH_DSPCLK_GATE_D    0xc2020
+#define  PCH_DPLUNIT_CLOCK_GATE_DISABLE (1<<30)
 #define  PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29)
+#define  PCH_CPUNIT_CLOCK_GATE_DISABLE (1<<14)
 #define  PCH_LP_PARTITION_LEVEL_DISABLE  (1<<12)
 
 /* CPU: FDI_TX */
 #define   GEN6_PCODE_WRITE_D_COMP              0x11
 #define   GEN6_ENCODE_RC6_VID(mv)              (((mv) - 245) / 5)
 #define   GEN6_DECODE_RC6_VID(vids)            (((vids) * 5) + 245)
+#define   DISPLAY_IPS_CONTROL                  0x19
 #define GEN6_PCODE_DATA                                0x138128
 #define   GEN6_PCODE_FREQ_IA_RATIO_SHIFT       8
 #define   GEN6_PCODE_FREQ_RING_RATIO_SHIFT     16
 #define GEN7_HALF_SLICE_CHICKEN1       0xe100 /* IVB GT1 + VLV */
 #define GEN7_HALF_SLICE_CHICKEN1_GT2   0xf100
 #define   GEN7_MAX_PS_THREAD_DEP               (8<<12)
+#define   GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE  (1<<10)
 #define   GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1<<3)
 
 #define GEN7_ROW_CHICKEN2              0xe4f4
 #define GEN7_ROW_CHICKEN2_GT2          0xf4f4
 #define   DOP_CLOCK_GATING_DISABLE     (1<<0)
 
+#define HSW_ROW_CHICKEN3               0xe49c
+#define  HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE    (1 << 6)
+
+#define HALF_SLICE_CHICKEN3            0xe184
+#define   GEN8_CENTROID_PIXEL_OPT_DIS  (1<<8)
+#define   GEN8_SAMPLER_POWER_BYPASS_DIS        (1<<1)
+
 #define G4X_AUD_VID_DID                        (dev_priv->info->display_mmio_offset + 0x62020)
 #define INTEL_AUDIO_DEVCL              0x808629FB
 #define INTEL_AUDIO_DEVBLC             0x80862801
                                        CPT_AUD_CNTL_ST_B)
 #define CPT_AUD_CNTRL_ST2              0xE50C0
 
+#define VLV_HDMIW_HDMIEDID_A           (VLV_DISPLAY_BASE + 0x62050)
+#define VLV_HDMIW_HDMIEDID_B           (VLV_DISPLAY_BASE + 0x62150)
+#define VLV_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \
+                                       VLV_HDMIW_HDMIEDID_A, \
+                                       VLV_HDMIW_HDMIEDID_B)
+#define VLV_AUD_CNTL_ST_A              (VLV_DISPLAY_BASE + 0x620B4)
+#define VLV_AUD_CNTL_ST_B              (VLV_DISPLAY_BASE + 0x621B4)
+#define VLV_AUD_CNTL_ST(pipe) _PIPE(pipe, \
+                                       VLV_AUD_CNTL_ST_A, \
+                                       VLV_AUD_CNTL_ST_B)
+#define VLV_AUD_CNTL_ST2               (VLV_DISPLAY_BASE + 0x620C0)
+
 /* These are the 4 32-bit write offset registers for each stream
  * output buffer.  It determines the offset from the
  * 3DSTATE_SO_BUFFERs that the next streamed vertex output goes to.
 #define CPT_AUD_CFG(pipe) _PIPE(pipe, \
                                        CPT_AUD_CONFIG_A, \
                                        CPT_AUD_CONFIG_B)
+#define VLV_AUD_CONFIG_A               (VLV_DISPLAY_BASE + 0x62000)
+#define VLV_AUD_CONFIG_B               (VLV_DISPLAY_BASE + 0x62100)
+#define VLV_AUD_CFG(pipe) _PIPE(pipe, \
+                                       VLV_AUD_CONFIG_A, \
+                                       VLV_AUD_CONFIG_B)
+
 #define   AUD_CONFIG_N_VALUE_INDEX             (1 << 29)
 #define   AUD_CONFIG_N_PROG_ENABLE             (1 << 28)
 #define   AUD_CONFIG_UPPER_N_SHIFT             20
 #define DDI_BUF_CTL_B                          0x64100
 #define DDI_BUF_CTL(port) _PORT(port, DDI_BUF_CTL_A, DDI_BUF_CTL_B)
 #define  DDI_BUF_CTL_ENABLE                    (1<<31)
+/* Haswell */
 #define  DDI_BUF_EMP_400MV_0DB_HSW             (0<<24)   /* Sel0 */
 #define  DDI_BUF_EMP_400MV_3_5DB_HSW           (1<<24)   /* Sel1 */
 #define  DDI_BUF_EMP_400MV_6DB_HSW             (2<<24)   /* Sel2 */
 #define  DDI_BUF_EMP_600MV_6DB_HSW             (6<<24)   /* Sel6 */
 #define  DDI_BUF_EMP_800MV_0DB_HSW             (7<<24)   /* Sel7 */
 #define  DDI_BUF_EMP_800MV_3_5DB_HSW           (8<<24)   /* Sel8 */
+/* Broadwell */
+#define  DDI_BUF_EMP_400MV_0DB_BDW             (0<<24)   /* Sel0 */
+#define  DDI_BUF_EMP_400MV_3_5DB_BDW           (1<<24)   /* Sel1 */
+#define  DDI_BUF_EMP_400MV_6DB_BDW             (2<<24)   /* Sel2 */
+#define  DDI_BUF_EMP_600MV_0DB_BDW             (3<<24)   /* Sel3 */
+#define  DDI_BUF_EMP_600MV_3_5DB_BDW           (4<<24)   /* Sel4 */
+#define  DDI_BUF_EMP_600MV_6DB_BDW             (5<<24)   /* Sel5 */
+#define  DDI_BUF_EMP_800MV_0DB_BDW             (6<<24)   /* Sel6 */
+#define  DDI_BUF_EMP_800MV_3_5DB_BDW           (7<<24)   /* Sel7 */
+#define  DDI_BUF_EMP_1200MV_0DB_BDW            (8<<24)   /* Sel8 */
 #define  DDI_BUF_EMP_MASK                      (0xf<<24)
 #define  DDI_BUF_PORT_REVERSAL                 (1<<16)
 #define  DDI_BUF_IS_IDLE                       (1<<7)
 #define  LCPLL_PLL_LOCK                        (1<<30)
 #define  LCPLL_CLK_FREQ_MASK           (3<<26)
 #define  LCPLL_CLK_FREQ_450            (0<<26)
+#define  LCPLL_CLK_FREQ_54O_BDW                (1<<26)
+#define  LCPLL_CLK_FREQ_337_5_BDW      (2<<26)
+#define  LCPLL_CLK_FREQ_675_BDW                (3<<26)
 #define  LCPLL_CD_CLOCK_DISABLE                (1<<25)
 #define  LCPLL_CD2X_CLOCK_DISABLE      (1<<23)
 #define  LCPLL_POWER_DOWN_ALLOW                (1<<22)
index a088f1f..98790c7 100644 (file)
@@ -214,6 +214,22 @@ static void i915_save_display(struct drm_device *dev)
                dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2);
                if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
                        dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS);
+       } else if (IS_VALLEYVIEW(dev)) {
+               dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
+               dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
+
+               dev_priv->regfile.saveBLC_PWM_CTL =
+                       I915_READ(VLV_BLC_PWM_CTL(PIPE_A));
+               dev_priv->regfile.saveBLC_HIST_CTL =
+                       I915_READ(VLV_BLC_HIST_CTL(PIPE_A));
+               dev_priv->regfile.saveBLC_PWM_CTL2 =
+                       I915_READ(VLV_BLC_PWM_CTL2(PIPE_A));
+               dev_priv->regfile.saveBLC_PWM_CTL_B =
+                       I915_READ(VLV_BLC_PWM_CTL(PIPE_B));
+               dev_priv->regfile.saveBLC_HIST_CTL_B =
+                       I915_READ(VLV_BLC_HIST_CTL(PIPE_B));
+               dev_priv->regfile.saveBLC_PWM_CTL2_B =
+                       I915_READ(VLV_BLC_PWM_CTL2(PIPE_B));
        } else {
                dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
                dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
@@ -302,6 +318,19 @@ static void i915_restore_display(struct drm_device *dev)
                I915_WRITE(PCH_PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
                I915_WRITE(RSTDBYCTL,
                           dev_priv->regfile.saveMCHBAR_RENDER_STANDBY);
+       } else if (IS_VALLEYVIEW(dev)) {
+               I915_WRITE(VLV_BLC_PWM_CTL(PIPE_A),
+                          dev_priv->regfile.saveBLC_PWM_CTL);
+               I915_WRITE(VLV_BLC_HIST_CTL(PIPE_A),
+                          dev_priv->regfile.saveBLC_HIST_CTL);
+               I915_WRITE(VLV_BLC_PWM_CTL2(PIPE_A),
+                          dev_priv->regfile.saveBLC_PWM_CTL2);
+               I915_WRITE(VLV_BLC_PWM_CTL(PIPE_B),
+                          dev_priv->regfile.saveBLC_PWM_CTL);
+               I915_WRITE(VLV_BLC_HIST_CTL(PIPE_B),
+                          dev_priv->regfile.saveBLC_HIST_CTL);
+               I915_WRITE(VLV_BLC_PWM_CTL2(PIPE_B),
+                          dev_priv->regfile.saveBLC_PWM_CTL2);
        } else {
                I915_WRITE(PFIT_PGM_RATIOS, dev_priv->regfile.savePFIT_PGM_RATIOS);
                I915_WRITE(BLC_PWM_CTL, dev_priv->regfile.saveBLC_PWM_CTL);
index e29bcae..6dd622d 100644 (file)
@@ -624,11 +624,11 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
 
        aux_channel = child->raw[25];
 
-       is_dvi = child->common.device_type & (1 << 4);
-       is_dp = child->common.device_type & (1 << 2);
-       is_crt = child->common.device_type & (1 << 0);
-       is_hdmi = is_dvi && (child->common.device_type & (1 << 11)) == 0;
-       is_edp = is_dp && (child->common.device_type & (1 << 12));
+       is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING;
+       is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT;
+       is_crt = child->common.device_type & DEVICE_TYPE_ANALOG_OUTPUT;
+       is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0;
+       is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR);
 
        info->supports_dvi = is_dvi;
        info->supports_hdmi = is_hdmi;
index 287cc5a..f580a2b 100644 (file)
@@ -638,6 +638,40 @@ int intel_parse_bios(struct drm_device *dev);
 #define         DEVICE_TYPE_DP         0x68C6
 #define         DEVICE_TYPE_eDP        0x78C6
 
+#define  DEVICE_TYPE_CLASS_EXTENSION   (1 << 15)
+#define  DEVICE_TYPE_POWER_MANAGEMENT  (1 << 14)
+#define  DEVICE_TYPE_HOTPLUG_SIGNALING (1 << 13)
+#define  DEVICE_TYPE_INTERNAL_CONNECTOR        (1 << 12)
+#define  DEVICE_TYPE_NOT_HDMI_OUTPUT   (1 << 11)
+#define  DEVICE_TYPE_MIPI_OUTPUT       (1 << 10)
+#define  DEVICE_TYPE_COMPOSITE_OUTPUT  (1 << 9)
+#define  DEVICE_TYPE_DUAL_CHANNEL      (1 << 8)
+#define  DEVICE_TYPE_HIGH_SPEED_LINK   (1 << 6)
+#define  DEVICE_TYPE_LVDS_SINGALING    (1 << 5)
+#define  DEVICE_TYPE_TMDS_DVI_SIGNALING        (1 << 4)
+#define  DEVICE_TYPE_VIDEO_SIGNALING   (1 << 3)
+#define  DEVICE_TYPE_DISPLAYPORT_OUTPUT        (1 << 2)
+#define  DEVICE_TYPE_DIGITAL_OUTPUT    (1 << 1)
+#define  DEVICE_TYPE_ANALOG_OUTPUT     (1 << 0)
+
+/*
+ * Bits we care about when checking for DEVICE_TYPE_eDP
+ * Depending on the system, the other bits may or may not
+ * be set for eDP outputs.
+ */
+#define DEVICE_TYPE_eDP_BITS \
+       (DEVICE_TYPE_INTERNAL_CONNECTOR | \
+        DEVICE_TYPE_NOT_HDMI_OUTPUT | \
+        DEVICE_TYPE_MIPI_OUTPUT | \
+        DEVICE_TYPE_COMPOSITE_OUTPUT | \
+        DEVICE_TYPE_DUAL_CHANNEL | \
+        DEVICE_TYPE_LVDS_SINGALING | \
+        DEVICE_TYPE_TMDS_DVI_SIGNALING | \
+        DEVICE_TYPE_VIDEO_SIGNALING | \
+        DEVICE_TYPE_DISPLAYPORT_OUTPUT | \
+        DEVICE_TYPE_DIGITAL_OUTPUT | \
+        DEVICE_TYPE_ANALOG_OUTPUT)
+
 /* define the DVO port for HDMI output type */
 #define                DVO_B           1
 #define                DVO_C           2
index 2e01bd3..b5b1b9b 100644 (file)
@@ -822,16 +822,15 @@ void intel_crt_init(struct drm_device *dev)
        crt->base.mode_set = intel_crt_mode_set;
        crt->base.disable = intel_disable_crt;
        crt->base.enable = intel_enable_crt;
-       if (IS_HASWELL(dev))
-               crt->base.get_config = hsw_crt_get_config;
-       else
-               crt->base.get_config = intel_crt_get_config;
        if (I915_HAS_HOTPLUG(dev))
                crt->base.hpd_pin = HPD_CRT;
-       if (HAS_DDI(dev))
+       if (HAS_DDI(dev)) {
+               crt->base.get_config = hsw_crt_get_config;
                crt->base.get_hw_state = intel_ddi_get_hw_state;
-       else
+       } else {
+               crt->base.get_config = intel_crt_get_config;
                crt->base.get_hw_state = intel_crt_get_hw_state;
+       }
        intel_connector->get_hw_state = intel_connector_get_hw_state;
 
        drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
index 31f4fe2..1591576 100644 (file)
@@ -72,6 +72,45 @@ static const u32 hsw_ddi_translations_hdmi[] = {
        0x80FFFFFF, 0x00030002, /* 11:  1000            1000            0   */
 };
 
+static const u32 bdw_ddi_translations_edp[] = {
+       0x00FFFFFF, 0x00000012,         /* DP parameters */
+       0x00EBAFFF, 0x00020011,
+       0x00C71FFF, 0x0006000F,
+       0x00FFFFFF, 0x00020011,
+       0x00DB6FFF, 0x0005000F,
+       0x00BEEFFF, 0x000A000C,
+       0x00FFFFFF, 0x0005000F,
+       0x00DB6FFF, 0x000A000C,
+       0x00FFFFFF, 0x000A000C,
+       0x00FFFFFF, 0x00140006          /* HDMI parameters 800mV 0dB*/
+};
+
+static const u32 bdw_ddi_translations_dp[] = {
+       0x00FFFFFF, 0x0007000E,         /* DP parameters */
+       0x00D75FFF, 0x000E000A,
+       0x00BEFFFF, 0x00140006,
+       0x00FFFFFF, 0x000E000A,
+       0x00D75FFF, 0x00180004,
+       0x80CB2FFF, 0x001B0002,
+       0x00F7DFFF, 0x00180004,
+       0x80D75FFF, 0x001B0002,
+       0x80FFFFFF, 0x001B0002,
+       0x00FFFFFF, 0x00140006          /* HDMI parameters 800mV 0dB*/
+};
+
+static const u32 bdw_ddi_translations_fdi[] = {
+       0x00FFFFFF, 0x0001000E,         /* FDI parameters */
+       0x00D75FFF, 0x0004000A,
+       0x00C30FFF, 0x00070006,
+       0x00AAAFFF, 0x000C0000,
+       0x00FFFFFF, 0x0004000A,
+       0x00D75FFF, 0x00090004,
+       0x00C30FFF, 0x000C0000,
+       0x00FFFFFF, 0x00070006,
+       0x00D75FFF, 0x000C0000,
+       0x00FFFFFF, 0x00140006          /* HDMI parameters 800mV 0dB*/
+};
+
 enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
 {
        struct drm_encoder *encoder = &intel_encoder->base;
@@ -92,8 +131,9 @@ enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
        }
 }
 
-/* On Haswell, DDI port buffers must be programmed with correct values
- * in advance. The buffer values are different for FDI and DP modes,
+/*
+ * Starting with Haswell, DDI port buffers must be programmed with correct
+ * values in advance. The buffer values are different for FDI and DP modes,
  * but the HDMI/DVI fields are shared among those. So we program the DDI
  * in either FDI or DP modes only, as HDMI connections will work with both
  * of those
@@ -103,10 +143,47 @@ 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;
-       const u32 *ddi_translations = (port == PORT_E) ?
-               hsw_ddi_translations_fdi :
-               hsw_ddi_translations_dp;
        int hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift;
+       const u32 *ddi_translations_fdi;
+       const u32 *ddi_translations_dp;
+       const u32 *ddi_translations_edp;
+       const u32 *ddi_translations;
+
+       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;
+       } 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;
+       } 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;
+       }
+
+       switch (port) {
+       case PORT_A:
+               ddi_translations = ddi_translations_edp;
+               break;
+       case PORT_B:
+       case PORT_C:
+               ddi_translations = ddi_translations_dp;
+               break;
+       case PORT_D:
+               if (intel_dpd_is_edp(dev))
+                       ddi_translations = ddi_translations_edp;
+               else
+                       ddi_translations = ddi_translations_dp;
+               break;
+       case PORT_E:
+               ddi_translations = ddi_translations_fdi;
+               break;
+       default:
+               BUG();
+       }
 
        for (i = 0, reg = DDI_BUF_TRANS(port);
             i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) {
@@ -756,7 +833,8 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
        struct drm_encoder *encoder = &intel_encoder->base;
-       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe = intel_crtc->pipe;
        enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        enum port port = intel_ddi_get_encoder_port(intel_encoder);
@@ -792,10 +870,11 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
        if (cpu_transcoder == TRANSCODER_EDP) {
                switch (pipe) {
                case PIPE_A:
-                       /* Can only use the always-on power well for eDP when
-                        * not using the panel fitter, and when not using motion
-                         * blur mitigation (which we don't support). */
-                       if (intel_crtc->config.pch_pfit.enabled)
+                       /* On Haswell, can only use the always-on power well for
+                        * eDP when not using the panel fitter, and when not
+                        * using motion blur mitigation (which we don't
+                        * support). */
+                       if (IS_HASWELL(dev) && intel_crtc->config.pch_pfit.enabled)
                                temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
                        else
                                temp |= TRANS_DDI_EDP_INPUT_A_ON;
@@ -1156,18 +1235,29 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
 
 int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
 {
+       struct drm_device *dev = dev_priv->dev;
        uint32_t lcpll = I915_READ(LCPLL_CTL);
+       uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
 
-       if (lcpll & LCPLL_CD_SOURCE_FCLK)
+       if (lcpll & LCPLL_CD_SOURCE_FCLK) {
                return 800000;
-       else if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT)
+       } else if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT) {
                return 450000;
-       else if ((lcpll & LCPLL_CLK_FREQ_MASK) == LCPLL_CLK_FREQ_450)
+       } else if (freq == LCPLL_CLK_FREQ_450) {
                return 450000;
-       else if (IS_ULT(dev_priv->dev))
-               return 337500;
-       else
-               return 540000;
+       } else if (IS_HASWELL(dev)) {
+               if (IS_ULT(dev))
+                       return 337500;
+               else
+                       return 540000;
+       } else {
+               if (freq == LCPLL_CLK_FREQ_54O_BDW)
+                       return 540000;
+               else if (freq == LCPLL_CLK_FREQ_337_5_BDW)
+                       return 337500;
+               else
+                       return 675000;
+       }
 }
 
 void intel_ddi_pll_init(struct drm_device *dev)
index 3cf284f..3cddd50 100644 (file)
@@ -2156,7 +2156,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
        else
                dspcntr &= ~DISPPLANE_TILED;
 
-       if (IS_HASWELL(dev))
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                dspcntr &= ~DISPPLANE_TRICKLE_FEED_DISABLE;
        else
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
@@ -2176,7 +2176,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        I915_MODIFY_DISPBASE(DSPSURF(plane),
                             i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
-       if (IS_HASWELL(dev)) {
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
        } else {
                I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
@@ -2421,9 +2421,10 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
                           FDI_FE_ERRC_ENABLE);
 }
 
-static bool pipe_has_enabled_pch(struct intel_crtc *intel_crtc)
+static bool pipe_has_enabled_pch(struct intel_crtc *crtc)
 {
-       return intel_crtc->base.enabled && intel_crtc->config.has_pch_encoder;
+       return crtc->base.enabled && crtc->active &&
+               crtc->config.has_pch_encoder;
 }
 
 static void ivb_modeset_global_resources(struct drm_device *dev)
@@ -3074,6 +3075,48 @@ 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)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t temp;
+
+       temp = I915_READ(SOUTH_CHICKEN1);
+       if (temp & FDI_BC_BIFURCATION_SELECT)
+               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");
+       I915_WRITE(SOUTH_CHICKEN1, temp);
+       POSTING_READ(SOUTH_CHICKEN1);
+}
+
+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);
+               else
+                       cpt_enable_fdi_bc_bifurcation(dev);
+
+               break;
+       case PIPE_C:
+               cpt_enable_fdi_bc_bifurcation(dev);
+
+               break;
+       default:
+               BUG();
+       }
+}
+
 /*
  * Enable PCH resources required for PCH ports:
  *   - PCH PLLs
@@ -3092,6 +3135,9 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
 
        assert_pch_transcoder_disabled(dev_priv, pipe);
 
+       if (IS_IVYBRIDGE(dev))
+               ivybridge_update_fdi_bc_bifurcation(intel_crtc);
+
        /* Write the TU size bits before fdi link training, so that error
         * detection works. */
        I915_WRITE(FDI_RX_TUSIZE1(pipe),
@@ -3347,15 +3393,26 @@ void hsw_enable_ips(struct intel_crtc *crtc)
         * only after intel_enable_plane. And intel_enable_plane already waits
         * for a vblank, so all we need to do here is to enable the IPS bit. */
        assert_plane_enabled(dev_priv, crtc->plane);
-       I915_WRITE(IPS_CTL, IPS_ENABLE);
-
-       /* The bit only becomes 1 in the next vblank, so this wait here is
-        * essentially intel_wait_for_vblank. If we don't have this and don't
-        * wait for vblanks until the end of crtc_enable, then the HW state
-        * readout code will complain that the expected IPS_CTL value is not the
-        * one we read. */
-       if (wait_for(I915_READ_NOTRACE(IPS_CTL) & IPS_ENABLE, 50))
-               DRM_ERROR("Timed out waiting for IPS enable\n");
+       if (IS_BROADWELL(crtc->base.dev)) {
+               mutex_lock(&dev_priv->rps.hw_lock);
+               WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0xc0000000));
+               mutex_unlock(&dev_priv->rps.hw_lock);
+               /* Quoting Art Runyan: "its not safe to expect any particular
+                * value in IPS_CTL bit 31 after enabling IPS through the
+                * mailbox." Therefore we need to defer waiting on the state
+                * change.
+                * TODO: need to fix this for state checker
+                */
+       } else {
+               I915_WRITE(IPS_CTL, IPS_ENABLE);
+               /* The bit only becomes 1 in the next vblank, so this wait here
+                * is essentially intel_wait_for_vblank. If we don't have this
+                * and don't wait for vblanks until the end of crtc_enable, then
+                * the HW state readout code will complain that the expected
+                * IPS_CTL value is not the one we read. */
+               if (wait_for(I915_READ_NOTRACE(IPS_CTL) & IPS_ENABLE, 50))
+                       DRM_ERROR("Timed out waiting for IPS enable\n");
+       }
 }
 
 void hsw_disable_ips(struct intel_crtc *crtc)
@@ -3367,7 +3424,12 @@ void hsw_disable_ips(struct intel_crtc *crtc)
                return;
 
        assert_plane_enabled(dev_priv, crtc->plane);
-       I915_WRITE(IPS_CTL, 0);
+       if (IS_BROADWELL(crtc->base.dev)) {
+               mutex_lock(&dev_priv->rps.hw_lock);
+               WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0));
+               mutex_unlock(&dev_priv->rps.hw_lock);
+       } else
+               I915_WRITE(IPS_CTL, 0);
        POSTING_READ(IPS_CTL);
 
        /* We need to wait for a vblank before we can disable the plane. */
@@ -4156,8 +4218,6 @@ static void intel_connector_check_state(struct intel_connector *connector)
  * consider. */
 void intel_connector_dpms(struct drm_connector *connector, int mode)
 {
-       struct intel_encoder *encoder = intel_attached_encoder(connector);
-
        /* All the simple cases only support two dpms states. */
        if (mode != DRM_MODE_DPMS_ON)
                mode = DRM_MODE_DPMS_OFF;
@@ -4168,10 +4228,8 @@ void intel_connector_dpms(struct drm_connector *connector, int mode)
        connector->dpms = mode;
 
        /* Only need to change hw state when actually enabled */
-       if (encoder->base.crtc)
-               intel_encoder_dpms(encoder, mode);
-       else
-               WARN_ON(encoder->connectors_active != false);
+       if (connector->encoder)
+               intel_encoder_dpms(to_intel_encoder(connector->encoder), mode);
 
        intel_modeset_check_state(connector->dev);
 }
@@ -4202,7 +4260,7 @@ static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
                return false;
        }
 
-       if (IS_HASWELL(dev)) {
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                if (pipe_config->fdi_lanes > 2) {
                        DRM_DEBUG_KMS("only 2 lanes on haswell, required: %i lanes\n",
                                      pipe_config->fdi_lanes);
@@ -5776,14 +5834,16 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc)
 
 static void haswell_set_pipeconf(struct drm_crtc *crtc)
 {
-       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+       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;
        enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        uint32_t val;
 
        val = 0;
 
-       if (intel_crtc->config.dither)
+       if (IS_HASWELL(dev) && intel_crtc->config.dither)
                val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
 
        if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
@@ -5796,6 +5856,33 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
 
        I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT);
        POSTING_READ(GAMMA_MODE(intel_crtc->pipe));
+
+       if (IS_BROADWELL(dev)) {
+               val = 0;
+
+               switch (intel_crtc->config.pipe_bpp) {
+               case 18:
+                       val |= PIPEMISC_DITHER_6_BPC;
+                       break;
+               case 24:
+                       val |= PIPEMISC_DITHER_8_BPC;
+                       break;
+               case 30:
+                       val |= PIPEMISC_DITHER_10_BPC;
+                       break;
+               case 36:
+                       val |= PIPEMISC_DITHER_12_BPC;
+                       break;
+               default:
+                       /* Case prevented by pipe_config_set_bpp. */
+                       BUG();
+               }
+
+               if (intel_crtc->config.dither)
+                       val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP;
+
+               I915_WRITE(PIPEMISC(pipe), val);
+       }
 }
 
 static bool ironlake_compute_clocks(struct drm_crtc *crtc,
@@ -5849,48 +5936,6 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
        return true;
 }
 
-static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t temp;
-
-       temp = I915_READ(SOUTH_CHICKEN1);
-       if (temp & FDI_BC_BIFURCATION_SELECT)
-               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");
-       I915_WRITE(SOUTH_CHICKEN1, temp);
-       POSTING_READ(SOUTH_CHICKEN1);
-}
-
-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);
-               else
-                       cpt_enable_fdi_bc_bifurcation(dev);
-
-               break;
-       case PIPE_C:
-               cpt_enable_fdi_bc_bifurcation(dev);
-
-               break;
-       default:
-               BUG();
-       }
-}
-
 int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp)
 {
        /*
@@ -6079,9 +6124,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                                             &intel_crtc->config.fdi_m_n);
        }
 
-       if (IS_IVYBRIDGE(dev))
-               ivybridge_update_fdi_bc_bifurcation(intel_crtc);
-
        ironlake_set_pipeconf(crtc);
 
        /* Set up the display plane register */
@@ -6557,22 +6599,79 @@ static void hsw_package_c8_gpu_busy(struct drm_i915_private *dev_priv)
        }
 }
 
-static void haswell_modeset_global_resources(struct drm_device *dev)
+#define for_each_power_domain(domain, mask)                            \
+       for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++)     \
+               if ((1 << (domain)) & (mask))
+
+static unsigned long get_pipe_power_domains(struct drm_device *dev,
+                                           enum pipe pipe, bool pfit_enabled)
 {
-       bool enable = false;
+       unsigned long mask;
+       enum transcoder transcoder;
+
+       transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe);
+
+       mask = BIT(POWER_DOMAIN_PIPE(pipe));
+       mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder));
+       if (pfit_enabled)
+               mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe));
+
+       return mask;
+}
+
+void intel_display_set_init_power(struct drm_device *dev, bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->power_domains.init_power_on == enable)
+               return;
+
+       if (enable)
+               intel_display_power_get(dev, POWER_DOMAIN_INIT);
+       else
+               intel_display_power_put(dev, POWER_DOMAIN_INIT);
+
+       dev_priv->power_domains.init_power_on = enable;
+}
+
+static void modeset_update_power_wells(struct drm_device *dev)
+{
+       unsigned long pipe_domains[I915_MAX_PIPES] = { 0, };
        struct intel_crtc *crtc;
 
+       /*
+        * First get all needed power domains, then put all unneeded, to avoid
+        * any unnecessary toggling of the power wells.
+        */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+               enum intel_display_power_domain domain;
+
                if (!crtc->base.enabled)
                        continue;
 
-               if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.enabled ||
-                   crtc->config.cpu_transcoder != TRANSCODER_EDP)
-                       enable = true;
+               pipe_domains[crtc->pipe] = get_pipe_power_domains(dev,
+                                               crtc->pipe,
+                                               crtc->config.pch_pfit.enabled);
+
+               for_each_power_domain(domain, pipe_domains[crtc->pipe])
+                       intel_display_power_get(dev, domain);
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+               enum intel_display_power_domain domain;
+
+               for_each_power_domain(domain, crtc->enabled_power_domains)
+                       intel_display_power_put(dev, domain);
+
+               crtc->enabled_power_domains = pipe_domains[crtc->pipe];
        }
 
-       intel_set_power_well(dev, enable);
+       intel_display_set_init_power(dev, false);
+}
 
+static void haswell_modeset_global_resources(struct drm_device *dev)
+{
+       modeset_update_power_wells(dev);
        hsw_update_package_c8(dev);
 }
 
@@ -6935,6 +7034,11 @@ static void ironlake_write_eld(struct drm_connector *connector,
                aud_config = IBX_AUD_CFG(pipe);
                aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
                aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
+       } else if (IS_VALLEYVIEW(connector->dev)) {
+               hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe);
+               aud_config = VLV_AUD_CFG(pipe);
+               aud_cntl_st = VLV_AUD_CNTL_ST(pipe);
+               aud_cntrl_st2 = VLV_AUD_CNTL_ST2;
        } else {
                hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe);
                aud_config = CPT_AUD_CFG(pipe);
@@ -6944,8 +7048,19 @@ static void ironlake_write_eld(struct drm_connector *connector,
 
        DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe));
 
-       i = I915_READ(aud_cntl_st);
-       i = (i >> 29) & DIP_PORT_SEL_MASK;              /* DIP_Port_Select, 0x1 = PortB */
+       if (IS_VALLEYVIEW(connector->dev))  {
+               struct intel_encoder *intel_encoder;
+               struct intel_digital_port *intel_dig_port;
+
+               intel_encoder = intel_attached_encoder(connector);
+               intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+               i = intel_dig_port->port;
+       } else {
+               i = I915_READ(aud_cntl_st);
+               i = (i >> 29) & DIP_PORT_SEL_MASK;
+               /* DIP_Port_Select, 0x1 = PortB */
+       }
+
        if (!i) {
                DRM_DEBUG_DRIVER("Audio directed to unknown port\n");
                /* operate blindly on all ports */
@@ -7089,7 +7204,7 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
                        cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
                        cntl |= CURSOR_MODE_DISABLE;
                }
-               if (IS_HASWELL(dev)) {
+               if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                        cntl |= CURSOR_PIPE_CSC_ENABLE;
                        cntl &= ~CURSOR_TRICKLE_FEED_DISABLE;
                }
@@ -7145,7 +7260,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
        if (!visible && !intel_crtc->cursor_visible)
                return;
 
-       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
+       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                I915_WRITE(CURPOS_IVB(pipe), pos);
                ivb_update_cursor(crtc, base);
        } else {
@@ -7276,8 +7391,8 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       intel_crtc->cursor_x = x;
-       intel_crtc->cursor_y = y;
+       intel_crtc->cursor_x = clamp_t(int, x, SHRT_MIN, SHRT_MAX);
+       intel_crtc->cursor_y = clamp_t(int, y, SHRT_MIN, SHRT_MAX);
 
        if (intel_crtc->active)
                intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
@@ -9804,6 +9919,18 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 }
 
+enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
+{
+       struct drm_encoder *encoder = connector->base.encoder;
+
+       WARN_ON(!mutex_is_locked(&connector->base.dev->mode_config.mutex));
+
+       if (!encoder)
+               return INVALID_PIPE;
+
+       return to_intel_crtc(encoder->crtc)->pipe;
+}
+
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
                                struct drm_file *file)
 {
@@ -10255,7 +10382,7 @@ static void intel_init_display(struct drm_device *dev)
                        dev_priv->display.write_eld = ironlake_write_eld;
                        dev_priv->display.modeset_global_resources =
                                ivb_modeset_global_resources;
-               } else if (IS_HASWELL(dev)) {
+               } else if (IS_HASWELL(dev) || IS_GEN8(dev)) {
                        dev_priv->display.fdi_link_train = hsw_fdi_link_train;
                        dev_priv->display.write_eld = haswell_write_eld;
                        dev_priv->display.modeset_global_resources =
@@ -10263,7 +10390,8 @@ static void intel_init_display(struct drm_device *dev)
                }
        } else if (IS_G4X(dev)) {
                dev_priv->display.write_eld = g4x_write_eld;
-       }
+       } else if (IS_VALLEYVIEW(dev))
+               dev_priv->display.write_eld = ironlake_write_eld;
 
        /* Default just returns -ENODEV to indicate unsupported */
        dev_priv->display.queue_flip = intel_default_queue_flip;
@@ -10286,6 +10414,7 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.queue_flip = intel_gen6_queue_flip;
                break;
        case 7:
+       case 8: /* FIXME(BDW): Check that the gen8 RCS flip works. */
                dev_priv->display.queue_flip = intel_gen7_queue_flip;
                break;
        }
@@ -10441,33 +10570,6 @@ static void i915_disable_vga(struct drm_device *dev)
        POSTING_READ(vga_reg);
 }
 
-static void i915_enable_vga_mem(struct drm_device *dev)
-{
-       /* Enable VGA memory on Intel HD */
-       if (HAS_PCH_SPLIT(dev)) {
-               vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
-               outb(inb(VGA_MSR_READ) | VGA_MSR_MEM_EN, VGA_MSR_WRITE);
-               vga_set_legacy_decoding(dev->pdev, VGA_RSRC_LEGACY_IO |
-                                                  VGA_RSRC_LEGACY_MEM |
-                                                  VGA_RSRC_NORMAL_IO |
-                                                  VGA_RSRC_NORMAL_MEM);
-               vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
-       }
-}
-
-void i915_disable_vga_mem(struct drm_device *dev)
-{
-       /* Disable VGA memory on Intel HD */
-       if (HAS_PCH_SPLIT(dev)) {
-               vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
-               outb(inb(VGA_MSR_READ) & ~VGA_MSR_MEM_EN, VGA_MSR_WRITE);
-               vga_set_legacy_decoding(dev->pdev, VGA_RSRC_LEGACY_IO |
-                                                  VGA_RSRC_NORMAL_IO |
-                                                  VGA_RSRC_NORMAL_MEM);
-               vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
-       }
-}
-
 void intel_modeset_init_hw(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -10753,7 +10855,6 @@ void i915_redisable_vga(struct drm_device *dev)
        if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) {
                DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
                i915_disable_vga(dev);
-               i915_disable_vga_mem(dev);
        }
 }
 
@@ -10960,8 +11061,6 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        intel_disable_fbc(dev);
 
-       i915_enable_vga_mem(dev);
-
        intel_disable_gt_powersave(dev);
 
        ironlake_teardown_rc6(dev);
@@ -11073,7 +11172,7 @@ intel_display_capture_error_state(struct drm_device *dev)
        if (INTEL_INFO(dev)->num_pipes == 0)
                return NULL;
 
-       error = kmalloc(sizeof(*error), GFP_ATOMIC);
+       error = kzalloc(sizeof(*error), GFP_ATOMIC);
        if (error == NULL)
                return NULL;
 
@@ -11081,6 +11180,9 @@ intel_display_capture_error_state(struct drm_device *dev)
                error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER);
 
        for_each_pipe(i) {
+               if (!intel_display_power_enabled(dev, POWER_DOMAIN_PIPE(i)))
+                       continue;
+
                if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) {
                        error->cursor[i].control = I915_READ(CURCNTR(i));
                        error->cursor[i].position = I915_READ(CURPOS(i));
@@ -11114,6 +11216,10 @@ intel_display_capture_error_state(struct drm_device *dev)
        for (i = 0; i < error->num_transcoders; i++) {
                enum transcoder cpu_transcoder = transcoders[i];
 
+               if (!intel_display_power_enabled(dev,
+                               POWER_DOMAIN_TRANSCODER(cpu_transcoder)))
+                       continue;
+
                error->transcoder[i].cpu_transcoder = cpu_transcoder;
 
                error->transcoder[i].conf = I915_READ(PIPECONF(cpu_transcoder));
@@ -11125,12 +11231,6 @@ intel_display_capture_error_state(struct drm_device *dev)
                error->transcoder[i].vsync = I915_READ(VSYNC(cpu_transcoder));
        }
 
-       /* In the code above we read the registers without checking if the power
-        * well was on, so here we have to clear the FPGA_DBG_RM_NOCLAIM bit to
-        * prevent the next I915_WRITE from detecting it and printing an error
-        * message. */
-       intel_uncore_clear_errors(dev);
-
        return error;
 }
 
@@ -11175,7 +11275,7 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
        }
 
        for (i = 0; i < error->num_transcoders; i++) {
-               err_printf(m, "  CPU transcoder: %c\n",
+               err_printf(m, "CPU transcoder: %c\n",
                           transcoder_name(error->transcoder[i].cpu_transcoder));
                err_printf(m, "  CONF: %08x\n", error->transcoder[i].conf);
                err_printf(m, "  HTOTAL: %08x\n", error->transcoder[i].htotal);
index 1e3d272..eb8139d 100644 (file)
@@ -405,6 +405,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        uint32_t status;
        int try, precharge, clock = 0;
        bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev);
+       uint32_t timeout;
 
        /* dp aux is extremely sensitive to irq latency, hence request the
         * lowest possible wakeup latency and so prevent the cpu from going into
@@ -419,6 +420,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        else
                precharge = 5;
 
+       if (IS_BROADWELL(dev) && ch_ctl == DPA_AUX_CH_CTL)
+               timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
+       else
+               timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
+
        intel_aux_display_runtime_get(dev_priv);
 
        /* Try to wait for any previous AUX channel activity */
@@ -454,7 +460,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                        I915_WRITE(ch_ctl,
                                   DP_AUX_CH_CTL_SEND_BUSY |
                                   (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
-                                  DP_AUX_CH_CTL_TIME_OUT_400us |
+                                  timeout |
                                   (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
                                   (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
                                   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
@@ -623,6 +629,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
        int reply_bytes;
        int ret;
 
+       ironlake_edp_panel_vdd_on(intel_dp);
        intel_dp_check_edp(intel_dp);
        /* Set up the command byte */
        if (mode & MODE_I2C_READ)
@@ -665,7 +672,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                                      reply, reply_bytes);
                if (ret < 0) {
                        DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
-                       return ret;
+                       goto out;
                }
 
                switch (reply[0] & AUX_NATIVE_REPLY_MASK) {
@@ -676,7 +683,8 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                        break;
                case AUX_NATIVE_REPLY_NACK:
                        DRM_DEBUG_KMS("aux_ch native nack\n");
-                       return -EREMOTEIO;
+                       ret = -EREMOTEIO;
+                       goto out;
                case AUX_NATIVE_REPLY_DEFER:
                        /*
                         * For now, just give more slack to branch devices. We
@@ -694,7 +702,8 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                default:
                        DRM_ERROR("aux_ch invalid native reply 0x%02x\n",
                                  reply[0]);
-                       return -EREMOTEIO;
+                       ret = -EREMOTEIO;
+                       goto out;
                }
 
                switch (reply[0] & AUX_I2C_REPLY_MASK) {
@@ -702,22 +711,29 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                        if (mode == MODE_I2C_READ) {
                                *read_byte = reply[1];
                        }
-                       return reply_bytes - 1;
+                       ret = reply_bytes - 1;
+                       goto out;
                case AUX_I2C_REPLY_NACK:
                        DRM_DEBUG_KMS("aux_i2c nack\n");
-                       return -EREMOTEIO;
+                       ret = -EREMOTEIO;
+                       goto out;
                case AUX_I2C_REPLY_DEFER:
                        DRM_DEBUG_KMS("aux_i2c defer\n");
                        udelay(100);
                        break;
                default:
                        DRM_ERROR("aux_i2c invalid reply 0x%02x\n", reply[0]);
-                       return -EREMOTEIO;
+                       ret = -EREMOTEIO;
+                       goto out;
                }
        }
 
        DRM_ERROR("too many retries, giving up\n");
-       return -EREMOTEIO;
+       ret = -EREMOTEIO;
+
+out:
+       ironlake_edp_panel_vdd_off(intel_dp, false);
+       return ret;
 }
 
 static int
@@ -739,9 +755,7 @@ intel_dp_i2c_init(struct intel_dp *intel_dp,
        intel_dp->adapter.algo_data = &intel_dp->algo;
        intel_dp->adapter.dev.parent = intel_connector->base.kdev;
 
-       ironlake_edp_panel_vdd_on(intel_dp);
        ret = i2c_dp_aux_add_bus(&intel_dp->adapter);
-       ironlake_edp_panel_vdd_off(intel_dp, false);
        return ret;
 }
 
@@ -1069,17 +1083,16 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
 
        if (!is_edp(intel_dp))
                return;
-       DRM_DEBUG_KMS("Turn eDP VDD on\n");
 
        WARN(intel_dp->want_panel_vdd,
             "eDP VDD already requested on\n");
 
        intel_dp->want_panel_vdd = true;
 
-       if (ironlake_edp_have_panel_vdd(intel_dp)) {
-               DRM_DEBUG_KMS("eDP VDD already on\n");
+       if (ironlake_edp_have_panel_vdd(intel_dp))
                return;
-       }
+
+       DRM_DEBUG_KMS("Turning eDP VDD on\n");
 
        if (!ironlake_edp_have_panel_power(intel_dp))
                ironlake_wait_panel_power_cycle(intel_dp);
@@ -1113,11 +1126,13 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
        WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
 
        if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) {
+               DRM_DEBUG_KMS("Turning eDP VDD off\n");
+
                pp = ironlake_get_pp_control(intel_dp);
                pp &= ~EDP_FORCE_VDD;
 
-               pp_stat_reg = _pp_ctrl_reg(intel_dp);
-               pp_ctrl_reg = _pp_stat_reg(intel_dp);
+               pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+               pp_stat_reg = _pp_stat_reg(intel_dp);
 
                I915_WRITE(pp_ctrl_reg, pp);
                POSTING_READ(pp_ctrl_reg);
@@ -1145,7 +1160,6 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
        if (!is_edp(intel_dp))
                return;
 
-       DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd);
        WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on");
 
        intel_dp->want_panel_vdd = false;
@@ -1241,7 +1255,6 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int pipe = to_intel_crtc(intel_dig_port->base.base.crtc)->pipe;
        u32 pp;
        u32 pp_ctrl_reg;
 
@@ -1264,7 +1277,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
 
-       intel_panel_enable_backlight(dev, pipe);
+       intel_panel_enable_backlight(intel_dp->attached_connector);
 }
 
 void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
@@ -1277,7 +1290,7 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
        if (!is_edp(intel_dp))
                return;
 
-       intel_panel_disable_backlight(dev);
+       intel_panel_disable_backlight(intel_dp->attached_connector);
 
        DRM_DEBUG_KMS("\n");
        pp = ironlake_get_pp_control(intel_dp);
@@ -1476,6 +1489,26 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
                ironlake_check_encoder_dotclock(pipe_config, dotclock);
 
        pipe_config->adjusted_mode.crtc_clock = dotclock;
+
+       if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp &&
+           pipe_config->pipe_bpp > dev_priv->vbt.edp_bpp) {
+               /*
+                * This is a big fat ugly hack.
+                *
+                * Some machines in UEFI boot mode provide us a VBT that has 18
+                * bpp and 1.62 GHz link bandwidth for eDP, which for reasons
+                * unknown we fail to light up. Yet the same BIOS boots up with
+                * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as
+                * max, not what it tells us to use.
+                *
+                * Note: This will still be broken if the eDP panel is not lit
+                * up by the BIOS, and thus we can't get the mode at module
+                * load.
+                */
+               DRM_DEBUG_KMS("pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n",
+                             pipe_config->pipe_bpp, dev_priv->vbt.edp_bpp);
+               dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp;
+       }
 }
 
 static bool is_edp_psr(struct drm_device *dev)
@@ -1543,7 +1576,7 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 
        /* Avoid continuous PSR exit by masking memup and hpd */
        I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-                  EDP_PSR_DEBUG_MASK_HPD);
+                  EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
 
        intel_dp->psr_setup_done = true;
 }
@@ -1583,6 +1616,7 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
        uint32_t max_sleep_time = 0x1f;
        uint32_t idle_frames = 1;
        uint32_t val = 0x0;
+       const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES;
 
        if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) {
                val |= EDP_PSR_LINK_STANDBY;
@@ -1593,7 +1627,7 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
                val |= EDP_PSR_LINK_DISABLE;
 
        I915_WRITE(EDP_PSR_CTL(dev), val |
-                  EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES |
+                  IS_BROADWELL(dev) ? 0 : link_entry_time |
                   max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
                   idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
                   EDP_PSR_ENABLE);
@@ -1930,7 +1964,7 @@ intel_dp_voltage_max(struct intel_dp *intel_dp)
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        enum port port = dp_to_dig_port(intel_dp)->port;
 
-       if (IS_VALLEYVIEW(dev))
+       if (IS_VALLEYVIEW(dev) || IS_BROADWELL(dev))
                return DP_TRAIN_VOLTAGE_SWING_1200;
        else if (IS_GEN7(dev) && port == PORT_A)
                return DP_TRAIN_VOLTAGE_SWING_800;
@@ -1946,7 +1980,18 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        enum port port = dp_to_dig_port(intel_dp)->port;
 
-       if (HAS_DDI(dev)) {
+       if (IS_BROADWELL(dev)) {
+               switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_600:
+                       return DP_TRAIN_PRE_EMPHASIS_6;
+               case DP_TRAIN_VOLTAGE_SWING_800:
+                       return DP_TRAIN_PRE_EMPHASIS_3_5;
+               case DP_TRAIN_VOLTAGE_SWING_1200:
+               default:
+                       return DP_TRAIN_PRE_EMPHASIS_0;
+               }
+       } else if (IS_HASWELL(dev)) {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
                case DP_TRAIN_VOLTAGE_SWING_400:
                        return DP_TRAIN_PRE_EMPHASIS_9_5;
@@ -2258,6 +2303,41 @@ intel_hsw_signal_levels(uint8_t train_set)
        }
 }
 
+static uint32_t
+intel_bdw_signal_levels(uint8_t train_set)
+{
+       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
+                                        DP_TRAIN_PRE_EMPHASIS_MASK);
+       switch (signal_levels) {
+       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
+               return DDI_BUF_EMP_400MV_0DB_BDW;       /* Sel0 */
+       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5:
+               return DDI_BUF_EMP_400MV_3_5DB_BDW;     /* Sel1 */
+       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
+               return DDI_BUF_EMP_400MV_6DB_BDW;       /* Sel2 */
+
+       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0:
+               return DDI_BUF_EMP_600MV_0DB_BDW;       /* Sel3 */
+       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
+               return DDI_BUF_EMP_600MV_3_5DB_BDW;     /* Sel4 */
+       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_6:
+               return DDI_BUF_EMP_600MV_6DB_BDW;       /* Sel5 */
+
+       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
+               return DDI_BUF_EMP_800MV_0DB_BDW;       /* Sel6 */
+       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5:
+               return DDI_BUF_EMP_800MV_3_5DB_BDW;     /* Sel7 */
+
+       case DP_TRAIN_VOLTAGE_SWING_1200 | DP_TRAIN_PRE_EMPHASIS_0:
+               return DDI_BUF_EMP_1200MV_0DB_BDW;      /* Sel8 */
+
+       default:
+               DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
+                             "0x%x\n", signal_levels);
+               return DDI_BUF_EMP_400MV_0DB_BDW;       /* Sel0 */
+       }
+}
+
 /* Properly updates "DP" with the correct signal levels. */
 static void
 intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
@@ -2268,7 +2348,10 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
        uint32_t signal_levels, mask;
        uint8_t train_set = intel_dp->train_set[0];
 
-       if (HAS_DDI(dev)) {
+       if (IS_BROADWELL(dev)) {
+               signal_levels = intel_bdw_signal_levels(train_set);
+               mask = DDI_BUF_EMP_MASK;
+       } else if (IS_HASWELL(dev)) {
                signal_levels = intel_hsw_signal_levels(train_set);
                mask = DDI_BUF_EMP_MASK;
        } else if (IS_VALLEYVIEW(dev)) {
@@ -3256,7 +3339,8 @@ bool intel_dpd_is_edp(struct drm_device *dev)
                p_child = dev_priv->vbt.child_dev + i;
 
                if (p_child->common.dvo_port == PORT_IDPD &&
-                   p_child->common.device_type == DEVICE_TYPE_eDP)
+                   (p_child->common.device_type & DEVICE_TYPE_eDP_BITS) ==
+                   (DEVICE_TYPE_eDP & DEVICE_TYPE_eDP_BITS))
                        return true;
        }
        return false;
@@ -3478,7 +3562,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
                                                      &power_seq);
 
-       ironlake_edp_panel_vdd_on(intel_dp);
        edid = drm_get_edid(connector, &intel_dp->adapter);
        if (edid) {
                if (drm_add_edid_modes(connector, edid)) {
@@ -3510,8 +3593,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
                        fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
        }
 
-       ironlake_edp_panel_vdd_off(intel_dp, false);
-
        intel_panel_init(&intel_connector->panel, fixed_mode);
        intel_panel_setup_backlight(connector);
 
index e33f387..1e49aa8 100644 (file)
@@ -326,6 +326,7 @@ struct intel_crtc {
         * some outputs connected to this crtc.
         */
        bool active;
+       unsigned long enabled_power_domains;
        bool eld_vld;
        bool primary_enabled; /* is the primary plane (partially) visible? */
        bool lowfreq_avail;
@@ -629,6 +630,7 @@ void intel_connector_attach_encoder(struct intel_connector *connector,
 struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
 struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
                                             struct drm_crtc *crtc);
+enum pipe intel_get_pipe_from_connector(struct intel_connector *connector);
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
@@ -691,6 +693,7 @@ bool intel_crtc_active(struct drm_crtc *crtc);
 void i915_disable_vga_mem(struct drm_device *dev);
 void hsw_enable_ips(struct intel_crtc *crtc);
 void hsw_disable_ips(struct intel_crtc *crtc);
+void intel_display_set_init_power(struct drm_device *dev, bool enable);
 
 
 /* intel_dp.c */
@@ -800,10 +803,11 @@ void intel_pch_panel_fitting(struct intel_crtc *crtc,
 void intel_gmch_panel_fitting(struct intel_crtc *crtc,
                              struct intel_crtc_config *pipe_config,
                              int fitting_mode);
-void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max);
+void intel_panel_set_backlight(struct intel_connector *connector, u32 level,
+                              u32 max);
 int intel_panel_setup_backlight(struct drm_connector *connector);
-void intel_panel_enable_backlight(struct drm_device *dev, enum pipe pipe);
-void intel_panel_disable_backlight(struct drm_device *dev);
+void intel_panel_enable_backlight(struct intel_connector *connector);
+void intel_panel_disable_backlight(struct intel_connector *connector);
 void intel_panel_destroy_backlight(struct drm_device *dev);
 enum drm_connector_status intel_panel_detect(struct drm_device *dev);
 
@@ -821,15 +825,15 @@ bool intel_fbc_enabled(struct drm_device *dev);
 void intel_update_fbc(struct drm_device *dev);
 void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
 void intel_gpu_ips_teardown(void);
-int i915_init_power_well(struct drm_device *dev);
-void i915_remove_power_well(struct drm_device *dev);
+int intel_power_domains_init(struct drm_device *dev);
+void intel_power_domains_remove(struct drm_device *dev);
 bool intel_display_power_enabled(struct drm_device *dev,
                                 enum intel_display_power_domain domain);
 void intel_display_power_get(struct drm_device *dev,
                             enum intel_display_power_domain domain);
 void intel_display_power_put(struct drm_device *dev,
                             enum intel_display_power_domain domain);
-void intel_init_power_well(struct drm_device *dev);
+void intel_power_domains_init_hw(struct drm_device *dev);
 void intel_set_power_well(struct drm_device *dev, bool enable);
 void intel_enable_gt_powersave(struct drm_device *dev);
 void intel_disable_gt_powersave(struct drm_device *dev);
index 1b64145..3c77365 100644 (file)
@@ -173,11 +173,16 @@ static void intel_enable_dvo(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
        struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
        u32 dvo_reg = intel_dvo->dev.dvo_reg;
        u32 temp = I915_READ(dvo_reg);
 
        I915_WRITE(dvo_reg, temp | DVO_ENABLE);
        I915_READ(dvo_reg);
+       intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
+                                        &crtc->config.requested_mode,
+                                        &crtc->config.adjusted_mode);
+
        intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
 }
 
@@ -186,6 +191,7 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
 {
        struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
        struct drm_crtc *crtc;
+       struct intel_crtc_config *config;
 
        /* dvo supports only 2 dpms states. */
        if (mode != DRM_MODE_DPMS_ON)
@@ -206,10 +212,16 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
        /* We call connector dpms manually below in case pipe dpms doesn't
         * change due to cloning. */
        if (mode == DRM_MODE_DPMS_ON) {
+               config = &to_intel_crtc(crtc)->config;
+
                intel_dvo->base.connectors_active = true;
 
                intel_crtc_update_dpms(crtc);
 
+               intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
+                                                &config->requested_mode,
+                                                &config->adjusted_mode);
+
                intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
        } else {
                intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
@@ -296,10 +308,6 @@ static void intel_dvo_mode_set(struct intel_encoder *encoder)
                break;
        }
 
-       intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
-                                        &crtc->config.requested_mode,
-                                        adjusted_mode);
-
        /* Save the data order, since I don't know what it should be set to. */
        dvo_val = I915_READ(dvo_reg) &
                  (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
index acc8395..895fcb4 100644 (file)
@@ -78,8 +78,8 @@ static int intelfb_create(struct drm_fb_helper *helper,
        mode_cmd.width = sizes->surface_width;
        mode_cmd.height = sizes->surface_height;
 
-       mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((sizes->surface_bpp + 7) /
-                                                     8), 64);
+       mode_cmd.pitches[0] = ALIGN(mode_cmd.width *
+                                   DIV_ROUND_UP(sizes->surface_bpp, 8), 64);
        mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
                                                          sizes->surface_depth);
 
index 51a8336..03f9ca7 100644 (file)
@@ -847,7 +847,7 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
 
        if (IS_G4X(dev))
                return 165000;
-       else if (IS_HASWELL(dev))
+       else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8)
                return 300000;
        else
                return 225000;
index ae0c843..c3b4da7 100644 (file)
@@ -206,7 +206,8 @@ static void intel_enable_lvds(struct intel_encoder *encoder)
 {
        struct drm_device *dev = encoder->base.dev;
        struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+       struct intel_connector *intel_connector =
+               &lvds_encoder->attached_connector->base;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 ctl_reg, stat_reg;
 
@@ -225,13 +226,15 @@ static void intel_enable_lvds(struct intel_encoder *encoder)
        if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000))
                DRM_ERROR("timed out waiting for panel to power on\n");
 
-       intel_panel_enable_backlight(dev, intel_crtc->pipe);
+       intel_panel_enable_backlight(intel_connector);
 }
 
 static void intel_disable_lvds(struct intel_encoder *encoder)
 {
        struct drm_device *dev = encoder->base.dev;
        struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+       struct intel_connector *intel_connector =
+               &lvds_encoder->attached_connector->base;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 ctl_reg, stat_reg;
 
@@ -243,7 +246,7 @@ static void intel_disable_lvds(struct intel_encoder *encoder)
                stat_reg = PP_STATUS;
        }
 
-       intel_panel_disable_backlight(dev);
+       intel_panel_disable_backlight(intel_connector);
 
        I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
        if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000))
@@ -705,6 +708,22 @@ static const struct dmi_system_id intel_no_lvds[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"),
                },
        },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Intel D410PT",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+                       DMI_MATCH(DMI_BOARD_NAME, "D410PT"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Intel D425KT",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "D425KT"),
+               },
+       },
        {
                .callback = intel_no_lvds_dmi_callback,
                .ident = "Intel D510MO",
index b82050c..91b68dc 100644 (file)
@@ -396,7 +396,13 @@ int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state)
 static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector = NULL;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
        struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
+       u32 ret = 0;
+       bool found = false;
 
        DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
 
@@ -407,11 +413,39 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
        if (bclp > 255)
                return ASLC_BACKLIGHT_FAILED;
 
+       mutex_lock(&dev->mode_config.mutex);
+       /*
+        * Could match the OpRegion connector here instead, but we'd also need
+        * to verify the connector could handle a backlight call.
+        */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               if (encoder->crtc == crtc) {
+                       found = true;
+                       break;
+               }
+
+       if (!found) {
+               ret = ASLC_BACKLIGHT_FAILED;
+               goto out;
+       }
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               if (connector->encoder == encoder)
+                       intel_connector = to_intel_connector(connector);
+
+       if (!intel_connector) {
+               ret = ASLC_BACKLIGHT_FAILED;
+               goto out;
+       }
+
        DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp);
-       intel_panel_set_backlight(dev, bclp, 255);
+       intel_panel_set_backlight(intel_connector, bclp, 255);
        iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv);
 
-       return 0;
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return ret;
 }
 
 static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
@@ -486,9 +520,13 @@ static u32 asle_isct_state(struct drm_device *dev)
        return ASLC_ISCT_STATE_FAILED;
 }
 
-void intel_opregion_asle_intr(struct drm_device *dev)
+static void asle_work(struct work_struct *work)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion =
+               container_of(work, struct intel_opregion, asle_work);
+       struct drm_i915_private *dev_priv =
+               container_of(opregion, struct drm_i915_private, opregion);
+       struct drm_device *dev = dev_priv->dev;
        struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
        u32 aslc_stat = 0;
        u32 aslc_req;
@@ -535,6 +573,14 @@ void intel_opregion_asle_intr(struct drm_device *dev)
        iowrite32(aslc_stat, &asle->aslc);
 }
 
+void intel_opregion_asle_intr(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->opregion.asle)
+               schedule_work(&dev_priv->opregion.asle_work);
+}
+
 #define ACPI_EV_DISPLAY_SWITCH (1<<0)
 #define ACPI_EV_LID            (1<<1)
 #define ACPI_EV_DOCK           (1<<2)
@@ -735,6 +781,8 @@ void intel_opregion_fini(struct drm_device *dev)
        if (opregion->asle)
                iowrite32(ASLE_ARDY_NOT_READY, &opregion->asle->ardy);
 
+       cancel_work_sync(&dev_priv->opregion.asle_work);
+
        if (opregion->acpi) {
                iowrite32(0, &opregion->acpi->drdy);
 
@@ -828,6 +876,8 @@ int intel_opregion_setup(struct drm_device *dev)
                return -ENOTSUPP;
        }
 
+       INIT_WORK(&opregion->asle_work, asle_work);
+
        base = acpi_os_ioremap(asls, OPREGION_SIZE);
        if (!base)
                return -ENOMEM;
index 09b2994..f161ac0 100644 (file)
@@ -341,7 +341,7 @@ static int is_backlight_combination_mode(struct drm_device *dev)
 /* XXX: query mode clock or hardware clock and program max PWM appropriately
  * when it's 0.
  */
-static u32 i915_read_blc_pwm_ctl(struct drm_device *dev)
+static u32 i915_read_blc_pwm_ctl(struct drm_device *dev, enum pipe pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 val;
@@ -358,6 +358,21 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev)
                        val = dev_priv->regfile.saveBLC_PWM_CTL2;
                        I915_WRITE(BLC_PWM_PCH_CTL2, val);
                }
+       } else if (IS_VALLEYVIEW(dev)) {
+               val = I915_READ(VLV_BLC_PWM_CTL(pipe));
+               if (dev_priv->regfile.saveBLC_PWM_CTL == 0) {
+                       dev_priv->regfile.saveBLC_PWM_CTL = val;
+                       dev_priv->regfile.saveBLC_PWM_CTL2 =
+                               I915_READ(VLV_BLC_PWM_CTL2(pipe));
+               } else if (val == 0) {
+                       val = dev_priv->regfile.saveBLC_PWM_CTL;
+                       I915_WRITE(VLV_BLC_PWM_CTL(pipe), val);
+                       I915_WRITE(VLV_BLC_PWM_CTL2(pipe),
+                                  dev_priv->regfile.saveBLC_PWM_CTL2);
+               }
+
+               if (!val)
+                       val = 0x0f42ffff;
        } else {
                val = I915_READ(BLC_PWM_CTL);
                if (dev_priv->regfile.saveBLC_PWM_CTL == 0) {
@@ -372,19 +387,17 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev)
                                I915_WRITE(BLC_PWM_CTL2,
                                           dev_priv->regfile.saveBLC_PWM_CTL2);
                }
-
-               if (IS_VALLEYVIEW(dev) && !val)
-                       val = 0x0f42ffff;
        }
 
        return val;
 }
 
-static u32 intel_panel_get_max_backlight(struct drm_device *dev)
+static u32 intel_panel_get_max_backlight(struct drm_device *dev,
+                                        enum pipe pipe)
 {
        u32 max;
 
-       max = i915_read_blc_pwm_ctl(dev);
+       max = i915_read_blc_pwm_ctl(dev, pipe);
 
        if (HAS_PCH_SPLIT(dev)) {
                max >>= 16;
@@ -410,7 +423,8 @@ MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness "
        "to dri-devel@lists.freedesktop.org, if your machine needs it. "
        "It will then be included in an upcoming module version.");
 module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600);
-static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
+static u32 intel_panel_compute_brightness(struct drm_device *dev,
+                                         enum pipe pipe, u32 val)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -419,7 +433,7 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
 
        if (i915_panel_invert_brightness > 0 ||
            dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
-               u32 max = intel_panel_get_max_backlight(dev);
+               u32 max = intel_panel_get_max_backlight(dev, pipe);
                if (max)
                        return max - val;
        }
@@ -427,18 +441,25 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
        return val;
 }
 
-static u32 intel_panel_get_backlight(struct drm_device *dev)
+static u32 intel_panel_get_backlight(struct drm_device *dev,
+                                    enum pipe pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 val;
        unsigned long flags;
+       int reg;
 
        spin_lock_irqsave(&dev_priv->backlight.lock, flags);
 
        if (HAS_PCH_SPLIT(dev)) {
                val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
        } else {
-               val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+               if (IS_VALLEYVIEW(dev))
+                       reg = VLV_BLC_PWM_CTL(pipe);
+               else
+                       reg = BLC_PWM_CTL;
+
+               val = I915_READ(reg) & BACKLIGHT_DUTY_CYCLE_MASK;
                if (INTEL_INFO(dev)->gen < 4)
                        val >>= 1;
 
@@ -450,7 +471,7 @@ static u32 intel_panel_get_backlight(struct drm_device *dev)
                }
        }
 
-       val = intel_panel_compute_brightness(dev, val);
+       val = intel_panel_compute_brightness(dev, pipe, val);
 
        spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
 
@@ -466,19 +487,20 @@ static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
 }
 
 static void intel_panel_actually_set_backlight(struct drm_device *dev,
-                                              u32 level)
+                                              enum pipe pipe, u32 level)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 tmp;
+       int reg;
 
        DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
-       level = intel_panel_compute_brightness(dev, level);
+       level = intel_panel_compute_brightness(dev, pipe, level);
 
        if (HAS_PCH_SPLIT(dev))
                return intel_pch_panel_set_backlight(dev, level);
 
        if (is_backlight_combination_mode(dev)) {
-               u32 max = intel_panel_get_max_backlight(dev);
+               u32 max = intel_panel_get_max_backlight(dev, pipe);
                u8 lbpc;
 
                /* we're screwed, but keep behaviour backwards compatible */
@@ -490,23 +512,34 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev,
                pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
        }
 
-       tmp = I915_READ(BLC_PWM_CTL);
+       if (IS_VALLEYVIEW(dev))
+               reg = VLV_BLC_PWM_CTL(pipe);
+       else
+               reg = BLC_PWM_CTL;
+
+       tmp = I915_READ(reg);
        if (INTEL_INFO(dev)->gen < 4)
                level <<= 1;
        tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
-       I915_WRITE(BLC_PWM_CTL, tmp | level);
+       I915_WRITE(reg, tmp | level);
 }
 
 /* set backlight brightness to level in range [0..max] */
-void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
+void intel_panel_set_backlight(struct intel_connector *connector, u32 level,
+                              u32 max)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe = intel_get_pipe_from_connector(connector);
        u32 freq;
        unsigned long flags;
 
+       if (pipe == INVALID_PIPE)
+               return;
+
        spin_lock_irqsave(&dev_priv->backlight.lock, flags);
 
-       freq = intel_panel_get_max_backlight(dev);
+       freq = intel_panel_get_max_backlight(dev, pipe);
        if (!freq) {
                /* we are screwed, bail out */
                goto out;
@@ -523,16 +556,21 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
                dev_priv->backlight.device->props.brightness = level;
 
        if (dev_priv->backlight.enabled)
-               intel_panel_actually_set_backlight(dev, level);
+               intel_panel_actually_set_backlight(dev, pipe, level);
 out:
        spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
 }
 
-void intel_panel_disable_backlight(struct drm_device *dev)
+void intel_panel_disable_backlight(struct intel_connector *connector)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe = intel_get_pipe_from_connector(connector);
        unsigned long flags;
 
+       if (pipe == INVALID_PIPE)
+               return;
+
        /*
         * Do not disable backlight on the vgaswitcheroo path. When switching
         * away from i915, the other client may depend on i915 to handle the
@@ -547,12 +585,17 @@ void intel_panel_disable_backlight(struct drm_device *dev)
        spin_lock_irqsave(&dev_priv->backlight.lock, flags);
 
        dev_priv->backlight.enabled = false;
-       intel_panel_actually_set_backlight(dev, 0);
+       intel_panel_actually_set_backlight(dev, pipe, 0);
 
        if (INTEL_INFO(dev)->gen >= 4) {
                uint32_t reg, tmp;
 
-               reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2;
+               if (HAS_PCH_SPLIT(dev))
+                       reg = BLC_PWM_CPU_CTL2;
+               else if (IS_VALLEYVIEW(dev))
+                       reg = VLV_BLC_PWM_CTL2(pipe);
+               else
+                       reg = BLC_PWM_CTL2;
 
                I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE);
 
@@ -566,20 +609,25 @@ void intel_panel_disable_backlight(struct drm_device *dev)
        spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
 }
 
-void intel_panel_enable_backlight(struct drm_device *dev,
-                                 enum pipe pipe)
+void intel_panel_enable_backlight(struct intel_connector *connector)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe = intel_get_pipe_from_connector(connector);
        enum transcoder cpu_transcoder =
                intel_pipe_to_cpu_transcoder(dev_priv, pipe);
        unsigned long flags;
 
+       if (pipe == INVALID_PIPE)
+               return;
+
        DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
 
        spin_lock_irqsave(&dev_priv->backlight.lock, flags);
 
        if (dev_priv->backlight.level == 0) {
-               dev_priv->backlight.level = intel_panel_get_max_backlight(dev);
+               dev_priv->backlight.level = intel_panel_get_max_backlight(dev,
+                                                                         pipe);
                if (dev_priv->backlight.device)
                        dev_priv->backlight.device->props.brightness =
                                dev_priv->backlight.level;
@@ -588,8 +636,12 @@ void intel_panel_enable_backlight(struct drm_device *dev,
        if (INTEL_INFO(dev)->gen >= 4) {
                uint32_t reg, tmp;
 
-               reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2;
-
+               if (HAS_PCH_SPLIT(dev))
+                       reg = BLC_PWM_CPU_CTL2;
+               else if (IS_VALLEYVIEW(dev))
+                       reg = VLV_BLC_PWM_CTL2(pipe);
+               else
+                       reg = BLC_PWM_CTL2;
 
                tmp = I915_READ(reg);
 
@@ -629,7 +681,8 @@ set_level:
         * registers are set.
         */
        dev_priv->backlight.enabled = true;
-       intel_panel_actually_set_backlight(dev, dev_priv->backlight.level);
+       intel_panel_actually_set_backlight(dev, pipe,
+                                          dev_priv->backlight.level);
 
        spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
 }
@@ -640,9 +693,19 @@ static void intel_panel_init_backlight_regs(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (IS_VALLEYVIEW(dev)) {
-               u32 cur_val = I915_READ(BLC_PWM_CTL) &
-                       BACKLIGHT_DUTY_CYCLE_MASK;
-               I915_WRITE(BLC_PWM_CTL, (0xf42 << 16) | cur_val);
+               enum pipe pipe;
+
+               for_each_pipe(pipe) {
+                       u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe));
+
+                       /* Skip if the modulation freq is already set */
+                       if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK)
+                               continue;
+
+                       cur_val &= BACKLIGHT_DUTY_CYCLE_MASK;
+                       I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) |
+                                  cur_val);
+               }
        }
 }
 
@@ -652,7 +715,7 @@ static void intel_panel_init_backlight(struct drm_device *dev)
 
        intel_panel_init_backlight_regs(dev);
 
-       dev_priv->backlight.level = intel_panel_get_backlight(dev);
+       dev_priv->backlight.level = intel_panel_get_backlight(dev, 0);
        dev_priv->backlight.enabled = dev_priv->backlight.level != 0;
 }
 
@@ -681,18 +744,31 @@ intel_panel_detect(struct drm_device *dev)
 #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
 static int intel_panel_update_status(struct backlight_device *bd)
 {
-       struct drm_device *dev = bl_get_data(bd);
+       struct intel_connector *connector = bl_get_data(bd);
+       struct drm_device *dev = connector->base.dev;
+
+       mutex_lock(&dev->mode_config.mutex);
        DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
                      bd->props.brightness, bd->props.max_brightness);
-       intel_panel_set_backlight(dev, bd->props.brightness,
+       intel_panel_set_backlight(connector, bd->props.brightness,
                                  bd->props.max_brightness);
+       mutex_unlock(&dev->mode_config.mutex);
        return 0;
 }
 
 static int intel_panel_get_brightness(struct backlight_device *bd)
 {
-       struct drm_device *dev = bl_get_data(bd);
-       return intel_panel_get_backlight(dev);
+       struct intel_connector *connector = bl_get_data(bd);
+       struct drm_device *dev = connector->base.dev;
+       enum pipe pipe;
+
+       mutex_lock(&dev->mode_config.mutex);
+       pipe = intel_get_pipe_from_connector(connector);
+       mutex_unlock(&dev->mode_config.mutex);
+       if (pipe == INVALID_PIPE)
+               return 0;
+
+       return intel_panel_get_backlight(connector->base.dev, pipe);
 }
 
 static const struct backlight_ops intel_panel_bl_ops = {
@@ -717,7 +793,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector)
        props.brightness = dev_priv->backlight.level;
 
        spin_lock_irqsave(&dev_priv->backlight.lock, flags);
-       props.max_brightness = intel_panel_get_max_backlight(dev);
+       props.max_brightness = intel_panel_get_max_backlight(dev, 0);
        spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
 
        if (props.max_brightness == 0) {
@@ -726,7 +802,8 @@ int intel_panel_setup_backlight(struct drm_connector *connector)
        }
        dev_priv->backlight.device =
                backlight_device_register("intel_backlight",
-                                         connector->kdev, dev,
+                                         connector->kdev,
+                                         to_intel_connector(connector),
                                          &intel_panel_bl_ops, &props);
 
        if (IS_ERR(dev_priv->backlight.device)) {
index 8064ff9..0a07d7c 100644 (file)
 #include <linux/module.h>
 #include <drm/i915_powerwell.h>
 
+/**
+ * RC6 is a special power stage which allows the GPU to enter an very
+ * low-voltage mode when idle, using down to 0V while at this stage.  This
+ * stage is entered automatically when the GPU is idle when RC6 support is
+ * enabled, and as soon as new workload arises GPU wakes up automatically as well.
+ *
+ * There are different RC6 modes available in Intel GPU, which differentiate
+ * among each other with the latency required to enter and leave RC6 and
+ * voltage consumed by the GPU in different states.
+ *
+ * The combination of the following flags define which states GPU is allowed
+ * to enter, while RC6 is the normal RC6 state, RC6p is the deep RC6, and
+ * RC6pp is deepest RC6. Their support by hardware varies according to the
+ * GPU, BIOS, chipset and platform. RC6 is usually the safest one and the one
+ * which brings the most power savings; deeper states save more power, but
+ * require higher latency to switch to and wake up.
+ */
+#define INTEL_RC6_ENABLE                       (1<<0)
+#define INTEL_RC6p_ENABLE                      (1<<1)
+#define INTEL_RC6pp_ENABLE                     (1<<2)
+
 /* FBC, or Frame Buffer Compression, is a technique employed to compress the
  * framebuffer contents in-memory, aiming at reducing the required bandwidth
  * during in-memory transfers and, therefore, reduce the power packet.
@@ -233,18 +254,6 @@ static void ironlake_disable_fbc(struct drm_device *dev)
                dpfc_ctl &= ~DPFC_CTL_EN;
                I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
 
-               if (IS_IVYBRIDGE(dev))
-                       /* WaFbcDisableDpfcClockGating:ivb */
-                       I915_WRITE(ILK_DSPCLK_GATE_D,
-                                  I915_READ(ILK_DSPCLK_GATE_D) &
-                                  ~ILK_DPFCUNIT_CLOCK_GATE_DISABLE);
-
-               if (IS_HASWELL(dev))
-                       /* WaFbcDisableDpfcClockGating:hsw */
-                       I915_WRITE(HSW_CLKGATE_DISABLE_PART_1,
-                                  I915_READ(HSW_CLKGATE_DISABLE_PART_1) &
-                                  ~HSW_DPFC_GATING_DISABLE);
-
                DRM_DEBUG_KMS("disabled FBC\n");
        }
 }
@@ -274,18 +283,10 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        if (IS_IVYBRIDGE(dev)) {
                /* WaFbcAsynchFlipDisableFbcQueue:ivb */
                I915_WRITE(ILK_DISPLAY_CHICKEN1, ILK_FBCQ_DIS);
-               /* WaFbcDisableDpfcClockGating:ivb */
-               I915_WRITE(ILK_DSPCLK_GATE_D,
-                          I915_READ(ILK_DSPCLK_GATE_D) |
-                          ILK_DPFCUNIT_CLOCK_GATE_DISABLE);
        } else {
                /* WaFbcAsynchFlipDisableFbcQueue:hsw */
                I915_WRITE(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe),
                           HSW_BYPASS_FBC_QUEUE);
-               /* WaFbcDisableDpfcClockGating:hsw */
-               I915_WRITE(HSW_CLKGATE_DISABLE_PART_1,
-                          I915_READ(HSW_CLKGATE_DISABLE_PART_1) |
-                          HSW_DPFC_GATING_DISABLE);
        }
 
        I915_WRITE(SNB_DPFC_CTL_SA,
@@ -2290,7 +2291,9 @@ static uint32_t ilk_compute_fbc_wm(const struct hsw_pipe_wm_parameters *params,
 
 static unsigned int ilk_display_fifo_size(const struct drm_device *dev)
 {
-       if (INTEL_INFO(dev)->gen >= 7)
+       if (INTEL_INFO(dev)->gen >= 8)
+               return 3072;
+       else if (INTEL_INFO(dev)->gen >= 7)
                return 768;
        else
                return 512;
@@ -2335,7 +2338,9 @@ static unsigned int ilk_plane_wm_max(const struct drm_device *dev,
        }
 
        /* clamp to max that the registers can hold */
-       if (INTEL_INFO(dev)->gen >= 7)
+       if (INTEL_INFO(dev)->gen >= 8)
+               max = level == 0 ? 255 : 2047;
+       else if (INTEL_INFO(dev)->gen >= 7)
                /* IVB/HSW primary/sprite plane watermarks */
                max = level == 0 ? 127 : 1023;
        else if (!is_sprite)
@@ -2365,10 +2370,13 @@ static unsigned int ilk_cursor_wm_max(const struct drm_device *dev,
 }
 
 /* Calculate the maximum FBC watermark */
-static unsigned int ilk_fbc_wm_max(void)
+static unsigned int ilk_fbc_wm_max(struct drm_device *dev)
 {
        /* max that registers can hold */
-       return 15;
+       if (INTEL_INFO(dev)->gen >= 8)
+               return 31;
+       else
+               return 15;
 }
 
 static void ilk_compute_wm_maximums(struct drm_device *dev,
@@ -2380,7 +2388,7 @@ static void ilk_compute_wm_maximums(struct drm_device *dev,
        max->pri = ilk_plane_wm_max(dev, level, config, ddb_partitioning, false);
        max->spr = ilk_plane_wm_max(dev, level, config, ddb_partitioning, true);
        max->cur = ilk_cursor_wm_max(dev, level, config);
-       max->fbc = ilk_fbc_wm_max();
+       max->fbc = ilk_fbc_wm_max(dev);
 }
 
 static bool ilk_validate_wm_level(int level,
@@ -2721,10 +2729,18 @@ static void hsw_compute_wm_results(struct drm_device *dev,
                if (!r->enable)
                        break;
 
-               results->wm_lp[wm_lp - 1] = HSW_WM_LP_VAL(level * 2,
-                                                         r->fbc_val,
-                                                         r->pri_val,
-                                                         r->cur_val);
+               results->wm_lp[wm_lp - 1] = WM3_LP_EN |
+                       ((level * 2) << WM1_LP_LATENCY_SHIFT) |
+                       (r->pri_val << WM1_LP_SR_SHIFT) |
+                       r->cur_val;
+
+               if (INTEL_INFO(dev)->gen >= 8)
+                       results->wm_lp[wm_lp - 1] |=
+                               r->fbc_val << WM1_LP_FBC_SHIFT_BDW;
+               else
+                       results->wm_lp[wm_lp - 1] |=
+                               r->fbc_val << WM1_LP_FBC_SHIFT;
+
                results->wm_lp_spr[wm_lp - 1] = r->spr_val;
        }
 
@@ -3685,6 +3701,20 @@ static void valleyview_disable_rps(struct drm_device *dev)
        }
 }
 
+static void intel_print_rc6_info(struct drm_device *dev, u32 mode)
+{
+       if (IS_GEN6(dev))
+               DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
+
+       if (IS_HASWELL(dev))
+               DRM_DEBUG_DRIVER("Haswell: only RC6 available\n");
+
+       DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
+                       (mode & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off",
+                       (mode & GEN6_RC_CTL_RC6p_ENABLE) ? "on" : "off",
+                       (mode & GEN6_RC_CTL_RC6pp_ENABLE) ? "on" : "off");
+}
+
 int intel_enable_rc6(const struct drm_device *dev)
 {
        /* No RC6 before Ironlake */
@@ -3699,18 +3729,13 @@ int intel_enable_rc6(const struct drm_device *dev)
        if (INTEL_INFO(dev)->gen == 5)
                return 0;
 
-       if (IS_HASWELL(dev)) {
-               DRM_DEBUG_DRIVER("Haswell: only RC6 available\n");
+       if (IS_HASWELL(dev))
                return INTEL_RC6_ENABLE;
-       }
 
        /* snb/ivb have more than one rc6 state. */
-       if (INTEL_INFO(dev)->gen == 6) {
-               DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
+       if (INTEL_INFO(dev)->gen == 6)
                return INTEL_RC6_ENABLE;
-       }
 
-       DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
        return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
 }
 
@@ -3737,6 +3762,78 @@ static void gen6_enable_rps_interrupts(struct drm_device *dev)
        I915_WRITE(GEN6_PMINTRMSK, ~enabled_intrs);
 }
 
+static void gen8_enable_rps(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       uint32_t rc6_mask = 0, rp_state_cap;
+       int unused;
+
+       /* 1a: Software RC state - RC0 */
+       I915_WRITE(GEN6_RC_STATE, 0);
+
+       /* 1c & 1d: Get forcewake during program sequence. Although the driver
+        * hasn't enabled a state yet where we need forcewake, BIOS may have.*/
+       gen6_gt_force_wake_get(dev_priv);
+
+       /* 2a: Disable RC states. */
+       I915_WRITE(GEN6_RC_CONTROL, 0);
+
+       rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+
+       /* 2b: Program RC6 thresholds.*/
+       I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16);
+       I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); /* 12500 * 1280ns */
+       I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25); /* 25 * 1280ns */
+       for_each_ring(ring, dev_priv, unused)
+               I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
+       I915_WRITE(GEN6_RC_SLEEP, 0);
+       I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */
+
+       /* 3: Enable RC6 */
+       if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
+               rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
+       DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off");
+       I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
+                       GEN6_RC_CTL_EI_MODE(1) |
+                       rc6_mask);
+
+       /* 4 Program defaults and thresholds for RPS*/
+       I915_WRITE(GEN6_RPNSWREQ, HSW_FREQUENCY(10)); /* Request 500 MHz */
+       I915_WRITE(GEN6_RC_VIDEO_FREQ, HSW_FREQUENCY(12)); /* Request 600 MHz */
+       /* NB: Docs say 1s, and 1000000 - which aren't equivalent */
+       I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 100000000 / 128); /* 1 second timeout */
+
+       /* Docs recommend 900MHz, and 300 MHz respectively */
+       I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
+                  dev_priv->rps.max_delay << 24 |
+                  dev_priv->rps.min_delay << 16);
+
+       I915_WRITE(GEN6_RP_UP_THRESHOLD, 7600000 / 128); /* 76ms busyness per EI, 90% */
+       I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 31300000 / 128); /* 313ms busyness per EI, 70%*/
+       I915_WRITE(GEN6_RP_UP_EI, 66000); /* 84.48ms, XXX: random? */
+       I915_WRITE(GEN6_RP_DOWN_EI, 350000); /* 448ms, XXX: random? */
+
+       I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
+
+       /* 5: Enable RPS */
+       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);
+
+       /* 6: Ring frequency + overclocking (our driver does this later */
+
+       gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8);
+
+       gen6_enable_rps_interrupts(dev);
+
+       gen6_gt_force_wake_put(dev_priv);
+}
+
 static void gen6_enable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3812,10 +3909,7 @@ static void gen6_enable_rps(struct drm_device *dev)
                        rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE;
        }
 
-       DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
-                       (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off",
-                       (rc6_mask & GEN6_RC_CTL_RC6p_ENABLE) ? "on" : "off",
-                       (rc6_mask & GEN6_RC_CTL_RC6pp_ENABLE) ? "on" : "off");
+       intel_print_rc6_info(dev, rc6_mask);
 
        I915_WRITE(GEN6_RC_CONTROL,
                   rc6_mask |
@@ -3888,7 +3982,7 @@ void gen6_update_ring_freq(struct drm_device *dev)
        /* Convert from kHz to MHz */
        max_ia_freq /= 1000;
 
-       min_ring_freq = I915_READ(MCHBAR_MIRROR_BASE_SNB + DCLK) & 0xf;
+       min_ring_freq = I915_READ(DCLK) & 0xf;
        /* convert DDR frequency from units of 266.6MHz to bandwidth */
        min_ring_freq = mult_frac(min_ring_freq, 8, 3);
 
@@ -3902,7 +3996,10 @@ void gen6_update_ring_freq(struct drm_device *dev)
                int diff = dev_priv->rps.max_delay - gpu_freq;
                unsigned int ia_freq = 0, ring_freq = 0;
 
-               if (IS_HASWELL(dev)) {
+               if (INTEL_INFO(dev)->gen >= 8) {
+                       /* max(2 * GT, DDR). NB: GT is 50MHz units */
+                       ring_freq = max(min_ring_freq, gpu_freq);
+               } else if (IS_HASWELL(dev)) {
                        ring_freq = mult_frac(gpu_freq, 5, 4);
                        ring_freq = max(min_ring_freq, ring_freq);
                        /* leave ia_freq as the default, chosen by cpufreq */
@@ -4051,6 +4148,9 @@ static void valleyview_enable_rps(struct drm_device *dev)
                                      VLV_RENDER_RC6_COUNT_EN));
        if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
                rc6_mode = GEN7_RC_CTL_TO_MODE;
+
+       intel_print_rc6_info(dev, rc6_mode);
+
        I915_WRITE(GEN6_RC_CONTROL, rc6_mode);
 
        val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
@@ -4222,6 +4322,8 @@ static void ironlake_enable_rc6(struct drm_device *dev)
 
        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, INTEL_RC6_ENABLE);
 }
 
 static unsigned long intel_pxfreq(u32 vidfreq)
@@ -4861,6 +4963,9 @@ static void intel_gen6_powersave_work(struct work_struct *work)
 
        if (IS_VALLEYVIEW(dev)) {
                valleyview_enable_rps(dev);
+       } else if (IS_BROADWELL(dev)) {
+               gen8_enable_rps(dev);
+               gen6_update_ring_freq(dev);
        } else {
                gen6_enable_rps(dev);
                gen6_update_ring_freq(dev);
@@ -4996,7 +5101,9 @@ static void cpt_init_clock_gating(struct drm_device *dev)
         * gating for the panel power sequencer or it will fail to
         * start up when no ports are active.
         */
-       I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE |
+                  PCH_DPLUNIT_CLOCK_GATE_DISABLE |
+                  PCH_CPUNIT_CLOCK_GATE_DISABLE);
        I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
                   DPLS_EDP_PPS_FIX_DIS);
        /* The below fixes the weird display corruption, a few pixels shifted
@@ -5167,6 +5274,50 @@ static void lpt_suspend_hw(struct drm_device *dev)
        }
 }
 
+static void gen8_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe i;
+
+       I915_WRITE(WM3_LP_ILK, 0);
+       I915_WRITE(WM2_LP_ILK, 0);
+       I915_WRITE(WM1_LP_ILK, 0);
+
+       /* FIXME(BDW): Check all the w/a, some might only apply to
+        * pre-production hw. */
+
+       WARN(!i915_preliminary_hw_support,
+            "GEN8_CENTROID_PIXEL_OPT_DIS not be needed for production\n");
+       I915_WRITE(HALF_SLICE_CHICKEN3,
+                  _MASKED_BIT_ENABLE(GEN8_CENTROID_PIXEL_OPT_DIS));
+       I915_WRITE(HALF_SLICE_CHICKEN3,
+                  _MASKED_BIT_ENABLE(GEN8_SAMPLER_POWER_BYPASS_DIS));
+       I915_WRITE(GAMTARBMODE, _MASKED_BIT_ENABLE(ARB_MODE_BWGTLB_DISABLE));
+
+       I915_WRITE(_3D_CHICKEN3,
+                  _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(2));
+
+       I915_WRITE(COMMON_SLICE_CHICKEN2,
+                  _MASKED_BIT_ENABLE(GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE));
+
+       I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
+                  _MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE));
+
+       /* WaSwitchSolVfFArbitrationPriority */
+       I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
+
+       /* WaPsrDPAMaskVBlankInSRD */
+       I915_WRITE(CHICKEN_PAR1_1,
+                  I915_READ(CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD);
+
+       /* WaPsrDPRSUnmaskVBlankInSRD */
+       for_each_pipe(i) {
+               I915_WRITE(CHICKEN_PIPESL_1(i),
+                          I915_READ(CHICKEN_PIPESL_1(i) |
+                                    DPRS_MASK_VBLANK_SRD));
+       }
+}
+
 static void haswell_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5190,6 +5341,11 @@ static void haswell_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
                        GEN7_WA_L3_CHICKEN_MODE);
 
+       /* L3 caching of data atomics doesn't work -- disable it. */
+       I915_WRITE(HSW_SCRATCH1, HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE);
+       I915_WRITE(HSW_ROW_CHICKEN3,
+                  _MASKED_BIT_ENABLE(HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE));
+
        /* This is required by WaCatErrorRejectionIssue:hsw */
        I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
                        I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
@@ -5485,6 +5641,25 @@ void intel_suspend_hw(struct drm_device *dev)
                lpt_suspend_hw(dev);
 }
 
+static bool is_always_on_power_domain(struct drm_device *dev,
+                                     enum intel_display_power_domain domain)
+{
+       unsigned long always_on_domains;
+
+       BUG_ON(BIT(domain) & ~POWER_DOMAIN_MASK);
+
+       if (IS_BROADWELL(dev)) {
+               always_on_domains = BDW_ALWAYS_ON_POWER_DOMAINS;
+       } else if (IS_HASWELL(dev)) {
+               always_on_domains = HSW_ALWAYS_ON_POWER_DOMAINS;
+       } else {
+               WARN_ON(1);
+               return true;
+       }
+
+       return BIT(domain) & always_on_domains;
+}
+
 /**
  * We should only use the power well if we explicitly asked the hardware to
  * enable it, so check if it's enabled and also check if we've requested it to
@@ -5498,24 +5673,11 @@ bool intel_display_power_enabled(struct drm_device *dev,
        if (!HAS_POWER_WELL(dev))
                return true;
 
-       switch (domain) {
-       case POWER_DOMAIN_PIPE_A:
-       case POWER_DOMAIN_TRANSCODER_EDP:
+       if (is_always_on_power_domain(dev, domain))
                return true;
-       case POWER_DOMAIN_VGA:
-       case POWER_DOMAIN_PIPE_B:
-       case POWER_DOMAIN_PIPE_C:
-       case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
-       case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
-       case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
-       case POWER_DOMAIN_TRANSCODER_A:
-       case POWER_DOMAIN_TRANSCODER_B:
-       case POWER_DOMAIN_TRANSCODER_C:
-               return I915_READ(HSW_PWR_WELL_DRIVER) ==
+
+       return I915_READ(HSW_PWR_WELL_DRIVER) ==
                     (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
-       default:
-               BUG();
-       }
 }
 
 static void __intel_set_power_well(struct drm_device *dev, bool enable)
@@ -5565,169 +5727,130 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable)
        }
 }
 
-static void __intel_power_well_get(struct i915_power_well *power_well)
+static void __intel_power_well_get(struct drm_device *dev,
+                                  struct i915_power_well *power_well)
 {
        if (!power_well->count++)
-               __intel_set_power_well(power_well->device, true);
+               __intel_set_power_well(dev, true);
 }
 
-static void __intel_power_well_put(struct i915_power_well *power_well)
+static void __intel_power_well_put(struct drm_device *dev,
+                                  struct i915_power_well *power_well)
 {
        WARN_ON(!power_well->count);
-       if (!--power_well->count)
-               __intel_set_power_well(power_well->device, false);
+       if (!--power_well->count && i915_disable_power_well)
+               __intel_set_power_well(dev, false);
 }
 
 void intel_display_power_get(struct drm_device *dev,
                             enum intel_display_power_domain domain)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_power_well *power_well = &dev_priv->power_well;
+       struct i915_power_domains *power_domains;
 
        if (!HAS_POWER_WELL(dev))
                return;
 
-       switch (domain) {
-       case POWER_DOMAIN_PIPE_A:
-       case POWER_DOMAIN_TRANSCODER_EDP:
-               return;
-       case POWER_DOMAIN_VGA:
-       case POWER_DOMAIN_PIPE_B:
-       case POWER_DOMAIN_PIPE_C:
-       case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
-       case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
-       case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
-       case POWER_DOMAIN_TRANSCODER_A:
-       case POWER_DOMAIN_TRANSCODER_B:
-       case POWER_DOMAIN_TRANSCODER_C:
-               spin_lock_irq(&power_well->lock);
-               __intel_power_well_get(power_well);
-               spin_unlock_irq(&power_well->lock);
+       if (is_always_on_power_domain(dev, domain))
                return;
-       default:
-               BUG();
-       }
+
+       power_domains = &dev_priv->power_domains;
+
+       mutex_lock(&power_domains->lock);
+       __intel_power_well_get(dev, &power_domains->power_wells[0]);
+       mutex_unlock(&power_domains->lock);
 }
 
 void intel_display_power_put(struct drm_device *dev,
                             enum intel_display_power_domain domain)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_power_well *power_well = &dev_priv->power_well;
+       struct i915_power_domains *power_domains;
 
        if (!HAS_POWER_WELL(dev))
                return;
 
-       switch (domain) {
-       case POWER_DOMAIN_PIPE_A:
-       case POWER_DOMAIN_TRANSCODER_EDP:
-               return;
-       case POWER_DOMAIN_VGA:
-       case POWER_DOMAIN_PIPE_B:
-       case POWER_DOMAIN_PIPE_C:
-       case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
-       case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
-       case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
-       case POWER_DOMAIN_TRANSCODER_A:
-       case POWER_DOMAIN_TRANSCODER_B:
-       case POWER_DOMAIN_TRANSCODER_C:
-               spin_lock_irq(&power_well->lock);
-               __intel_power_well_put(power_well);
-               spin_unlock_irq(&power_well->lock);
+       if (is_always_on_power_domain(dev, domain))
                return;
-       default:
-               BUG();
-       }
+
+       power_domains = &dev_priv->power_domains;
+
+       mutex_lock(&power_domains->lock);
+       __intel_power_well_put(dev, &power_domains->power_wells[0]);
+       mutex_unlock(&power_domains->lock);
 }
 
-static struct i915_power_well *hsw_pwr;
+static struct i915_power_domains *hsw_pwr;
 
 /* Display audio driver power well request */
 void i915_request_power_well(void)
 {
+       struct drm_i915_private *dev_priv;
+
        if (WARN_ON(!hsw_pwr))
                return;
 
-       spin_lock_irq(&hsw_pwr->lock);
-       __intel_power_well_get(hsw_pwr);
-       spin_unlock_irq(&hsw_pwr->lock);
+       dev_priv = container_of(hsw_pwr, struct drm_i915_private,
+                               power_domains);
+
+       mutex_lock(&hsw_pwr->lock);
+       __intel_power_well_get(dev_priv->dev, &hsw_pwr->power_wells[0]);
+       mutex_unlock(&hsw_pwr->lock);
 }
 EXPORT_SYMBOL_GPL(i915_request_power_well);
 
 /* Display audio driver power well release */
 void i915_release_power_well(void)
 {
+       struct drm_i915_private *dev_priv;
+
        if (WARN_ON(!hsw_pwr))
                return;
 
-       spin_lock_irq(&hsw_pwr->lock);
-       __intel_power_well_put(hsw_pwr);
-       spin_unlock_irq(&hsw_pwr->lock);
+       dev_priv = container_of(hsw_pwr, struct drm_i915_private,
+                               power_domains);
+
+       mutex_lock(&hsw_pwr->lock);
+       __intel_power_well_put(dev_priv->dev, &hsw_pwr->power_wells[0]);
+       mutex_unlock(&hsw_pwr->lock);
 }
 EXPORT_SYMBOL_GPL(i915_release_power_well);
 
-int i915_init_power_well(struct drm_device *dev)
+int intel_power_domains_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       struct i915_power_well *power_well;
 
-       hsw_pwr = &dev_priv->power_well;
+       mutex_init(&power_domains->lock);
+       hsw_pwr = power_domains;
 
-       hsw_pwr->device = dev;
-       spin_lock_init(&hsw_pwr->lock);
-       hsw_pwr->count = 0;
+       power_well = &power_domains->power_wells[0];
+       power_well->count = 0;
 
        return 0;
 }
 
-void i915_remove_power_well(struct drm_device *dev)
+void intel_power_domains_remove(struct drm_device *dev)
 {
        hsw_pwr = NULL;
 }
 
-void intel_set_power_well(struct drm_device *dev, bool enable)
+static void intel_power_domains_resume(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_power_well *power_well = &dev_priv->power_well;
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       struct i915_power_well *power_well;
 
        if (!HAS_POWER_WELL(dev))
                return;
 
-       if (!i915_disable_power_well && !enable)
-               return;
-
-       spin_lock_irq(&power_well->lock);
+       mutex_lock(&power_domains->lock);
 
-       /*
-        * This function will only ever contribute one
-        * to the power well reference count. i915_request
-        * is what tracks whether we have or have not
-        * added the one to the reference count.
-        */
-       if (power_well->i915_request == enable)
-               goto out;
-
-       power_well->i915_request = enable;
-
-       if (enable)
-               __intel_power_well_get(power_well);
-       else
-               __intel_power_well_put(power_well);
-
- out:
-       spin_unlock_irq(&power_well->lock);
-}
-
-static void intel_resume_power_well(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_power_well *power_well = &dev_priv->power_well;
-
-       if (!HAS_POWER_WELL(dev))
-               return;
-
-       spin_lock_irq(&power_well->lock);
+       power_well = &power_domains->power_wells[0];
        __intel_set_power_well(dev, power_well->count > 0);
-       spin_unlock_irq(&power_well->lock);
+
+       mutex_unlock(&power_domains->lock);
 }
 
 /*
@@ -5736,7 +5859,7 @@ static void intel_resume_power_well(struct drm_device *dev)
  * to be enabled, and it will only be disabled if none of the registers is
  * requesting it to be enabled.
  */
-void intel_init_power_well(struct drm_device *dev)
+void intel_power_domains_init_hw(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -5744,8 +5867,8 @@ void intel_init_power_well(struct drm_device *dev)
                return;
 
        /* For now, we need the power well to be always enabled. */
-       intel_set_power_well(dev, true);
-       intel_resume_power_well(dev);
+       intel_display_set_init_power(dev, true);
+       intel_power_domains_resume(dev);
 
        /* We're taking over the BIOS, so clear any requests made by it since
         * the driver is in charge now. */
@@ -5849,6 +5972,8 @@ void intel_init_pm(struct drm_device *dev)
                                dev_priv->display.update_wm = NULL;
                        }
                        dev_priv->display.init_clock_gating = haswell_init_clock_gating;
+               } else if (INTEL_INFO(dev)->gen == 8) {
+                       dev_priv->display.init_clock_gating = gen8_init_clock_gating;
                } else
                        dev_priv->display.update_wm = NULL;
        } else if (IS_VALLEYVIEW(dev)) {
@@ -6011,4 +6136,3 @@ void intel_pm_init(struct drm_device *dev)
        INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
                          intel_gen6_powersave_work);
 }
-
index 2dec134..b620337 100644 (file)
@@ -360,6 +360,47 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring,
        return 0;
 }
 
+static int
+gen8_render_ring_flush(struct intel_ring_buffer *ring,
+                      u32 invalidate_domains, u32 flush_domains)
+{
+       u32 flags = 0;
+       u32 scratch_addr = ring->scratch.gtt_offset + 128;
+       int ret;
+
+       flags |= PIPE_CONTROL_CS_STALL;
+
+       if (flush_domains) {
+               flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+       }
+       if (invalidate_domains) {
+               flags |= PIPE_CONTROL_TLB_INVALIDATE;
+               flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_QW_WRITE;
+               flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
+       }
+
+       ret = intel_ring_begin(ring, 6);
+       if (ret)
+               return ret;
+
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(6));
+       intel_ring_emit(ring, flags);
+       intel_ring_emit(ring, scratch_addr);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, 0);
+       intel_ring_advance(ring);
+
+       return 0;
+
+}
+
 static void ring_write_tail(struct intel_ring_buffer *ring,
                            u32 value)
 {
@@ -1066,6 +1107,52 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring)
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 }
 
+static bool
+gen8_ring_get_irq(struct intel_ring_buffer *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+
+       if (!dev->irq_enabled)
+               return false;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       if (ring->irq_refcount++ == 0) {
+               if (HAS_L3_DPF(dev) && ring->id == RCS) {
+                       I915_WRITE_IMR(ring,
+                                      ~(ring->irq_enable_mask |
+                                        GT_RENDER_L3_PARITY_ERROR_INTERRUPT));
+               } else {
+                       I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
+               }
+               POSTING_READ(RING_IMR(ring->mmio_base));
+       }
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+       return true;
+}
+
+static void
+gen8_ring_put_irq(struct intel_ring_buffer *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       if (--ring->irq_refcount == 0) {
+               if (HAS_L3_DPF(dev) && ring->id == RCS) {
+                       I915_WRITE_IMR(ring,
+                                      ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
+               } else {
+                       I915_WRITE_IMR(ring, ~0);
+               }
+               POSTING_READ(RING_IMR(ring->mmio_base));
+       }
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+}
+
 static int
 i965_dispatch_execbuffer(struct intel_ring_buffer *ring,
                         u32 offset, u32 length,
@@ -1624,6 +1711,8 @@ static int gen6_bsd_ring_flush(struct intel_ring_buffer *ring,
                return ret;
 
        cmd = MI_FLUSH_DW;
+       if (INTEL_INFO(ring->dev)->gen >= 8)
+               cmd += 1;
        /*
         * Bspec vol 1c.5 - video engine command streamer:
         * "If ENABLED, all TLBs will be invalidated once the flush
@@ -1635,9 +1724,38 @@ static int gen6_bsd_ring_flush(struct intel_ring_buffer *ring,
                        MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
        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) {
+               intel_ring_emit(ring, 0); /* upper addr */
+               intel_ring_emit(ring, 0); /* value */
+       } else  {
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, MI_NOOP);
+       }
+       intel_ring_advance(ring);
+       return 0;
+}
+
+static int
+gen8_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
+                             u32 offset, u32 len,
+                             unsigned flags)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       bool ppgtt = dev_priv->mm.aliasing_ppgtt != NULL &&
+               !(flags & I915_DISPATCH_SECURE);
+       int ret;
+
+       ret = intel_ring_begin(ring, 4);
+       if (ret)
+               return ret;
+
+       /* FIXME(BDW): Address space and security selectors. */
+       intel_ring_emit(ring, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8));
+       intel_ring_emit(ring, offset);
        intel_ring_emit(ring, 0);
        intel_ring_emit(ring, MI_NOOP);
        intel_ring_advance(ring);
+
        return 0;
 }
 
@@ -1697,6 +1815,8 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring,
                return ret;
 
        cmd = MI_FLUSH_DW;
+       if (INTEL_INFO(ring->dev)->gen >= 8)
+               cmd += 1;
        /*
         * Bspec vol 1c.3 - blitter engine command streamer:
         * "If ENABLED, all TLBs will be invalidated once the flush
@@ -1708,8 +1828,13 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring,
                        MI_FLUSH_DW_OP_STOREDW;
        intel_ring_emit(ring, cmd);
        intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
-       intel_ring_emit(ring, 0);
-       intel_ring_emit(ring, MI_NOOP);
+       if (INTEL_INFO(ring->dev)->gen >= 8) {
+               intel_ring_emit(ring, 0); /* upper addr */
+               intel_ring_emit(ring, 0); /* value */
+       } else  {
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, MI_NOOP);
+       }
        intel_ring_advance(ring);
 
        if (IS_GEN7(dev) && flush)
@@ -1732,8 +1857,14 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
                ring->flush = gen7_render_ring_flush;
                if (INTEL_INFO(dev)->gen == 6)
                        ring->flush = gen6_render_ring_flush;
-               ring->irq_get = gen6_ring_get_irq;
-               ring->irq_put = gen6_ring_put_irq;
+               if (INTEL_INFO(dev)->gen >= 8) {
+                       ring->flush = gen8_render_ring_flush;
+                       ring->irq_get = gen8_ring_get_irq;
+                       ring->irq_put = gen8_ring_put_irq;
+               } else {
+                       ring->irq_get = gen6_ring_get_irq;
+                       ring->irq_put = gen6_ring_put_irq;
+               }
                ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
                ring->get_seqno = gen6_ring_get_seqno;
                ring->set_seqno = ring_set_seqno;
@@ -1775,6 +1906,8 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
        ring->write_tail = ring_write_tail;
        if (IS_HASWELL(dev))
                ring->dispatch_execbuffer = hsw_ring_dispatch_execbuffer;
+       else if (IS_GEN8(dev))
+               ring->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
        else if (INTEL_INFO(dev)->gen >= 6)
                ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
        else if (INTEL_INFO(dev)->gen >= 4)
@@ -1888,7 +2021,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
        ring->id = VCS;
 
        ring->write_tail = ring_write_tail;
-       if (IS_GEN6(dev) || IS_GEN7(dev)) {
+       if (INTEL_INFO(dev)->gen >= 6) {
                ring->mmio_base = GEN6_BSD_RING_BASE;
                /* gen6 bsd needs a special wa for tail updates */
                if (IS_GEN6(dev))
@@ -1897,10 +2030,20 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
                ring->add_request = gen6_add_request;
                ring->get_seqno = gen6_ring_get_seqno;
                ring->set_seqno = ring_set_seqno;
-               ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
-               ring->irq_get = gen6_ring_get_irq;
-               ring->irq_put = gen6_ring_put_irq;
-               ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+               if (INTEL_INFO(dev)->gen >= 8) {
+                       ring->irq_enable_mask =
+                               GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
+                       ring->irq_get = gen8_ring_get_irq;
+                       ring->irq_put = gen8_ring_put_irq;
+                       ring->dispatch_execbuffer =
+                               gen8_ring_dispatch_execbuffer;
+               } else {
+                       ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
+                       ring->irq_get = gen6_ring_get_irq;
+                       ring->irq_put = gen6_ring_put_irq;
+                       ring->dispatch_execbuffer =
+                               gen6_ring_dispatch_execbuffer;
+               }
                ring->sync_to = gen6_ring_sync;
                ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR;
                ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_INVALID;
@@ -1946,10 +2089,18 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
        ring->add_request = gen6_add_request;
        ring->get_seqno = gen6_ring_get_seqno;
        ring->set_seqno = ring_set_seqno;
-       ring->irq_enable_mask = GT_BLT_USER_INTERRUPT;
-       ring->irq_get = gen6_ring_get_irq;
-       ring->irq_put = gen6_ring_put_irq;
-       ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+       if (INTEL_INFO(dev)->gen >= 8) {
+               ring->irq_enable_mask =
+                       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+               ring->irq_get = gen8_ring_get_irq;
+               ring->irq_put = gen8_ring_put_irq;
+               ring->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
+       } else {
+               ring->irq_enable_mask = GT_BLT_USER_INTERRUPT;
+               ring->irq_get = gen6_ring_get_irq;
+               ring->irq_put = gen6_ring_put_irq;
+               ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+       }
        ring->sync_to = gen6_ring_sync;
        ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR;
        ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_BV;
@@ -1978,10 +2129,19 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev)
        ring->add_request = gen6_add_request;
        ring->get_seqno = gen6_ring_get_seqno;
        ring->set_seqno = ring_set_seqno;
-       ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
-       ring->irq_get = hsw_vebox_get_irq;
-       ring->irq_put = hsw_vebox_put_irq;
-       ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+
+       if (INTEL_INFO(dev)->gen >= 8) {
+               ring->irq_enable_mask =
+                       GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
+               ring->irq_get = gen8_ring_get_irq;
+               ring->irq_put = gen8_ring_put_irq;
+               ring->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
+       } else {
+               ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
+               ring->irq_get = hsw_vebox_get_irq;
+               ring->irq_put = hsw_vebox_put_irq;
+               ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+       }
        ring->sync_to = gen6_ring_sync;
        ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER;
        ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_VEV;
index 07b13dc..b9fabf8 100644 (file)
@@ -260,14 +260,14 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        if (obj->tiling_mode != I915_TILING_NONE)
                sprctl |= SPRITE_TILED;
 
-       if (IS_HASWELL(dev))
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE;
        else
                sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
 
        sprctl |= SPRITE_ENABLE;
 
-       if (IS_HASWELL(dev))
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                sprctl |= SPRITE_PIPE_CSC_ENABLE;
 
        intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
@@ -306,7 +306,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
        /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
         * register */
-       if (IS_HASWELL(dev))
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                I915_WRITE(SPROFFSET(pipe), (y << 16) | x);
        else if (obj->tiling_mode != I915_TILING_NONE)
                I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
@@ -1092,6 +1092,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
                break;
 
        case 7:
+       case 8:
                if (IS_IVYBRIDGE(dev)) {
                        intel_plane->can_scale = true;
                        intel_plane->max_downscale = 2;
index f6fae35..f9883ce 100644 (file)
@@ -93,7 +93,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
 {
        u32 forcewake_ack;
 
-       if (IS_HASWELL(dev_priv->dev))
+       if (IS_HASWELL(dev_priv->dev) || IS_GEN8(dev_priv->dev))
                forcewake_ack = FORCEWAKE_ACK_HSW;
        else
                forcewake_ack = FORCEWAKE_MT_ACK;
@@ -112,7 +112,8 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
                DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
 
        /* WaRsForcewakeWaitTC0:ivb,hsw */
-       __gen6_gt_wait_for_thread_c0(dev_priv);
+       if (INTEL_INFO(dev_priv->dev)->gen < 8)
+               __gen6_gt_wait_for_thread_c0(dev_priv);
 }
 
 static void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
@@ -459,6 +460,46 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace)
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
 }
 
+static const u32 gen8_shadowed_regs[] = {
+       FORCEWAKE_MT,
+       GEN6_RPNSWREQ,
+       GEN6_RC_VIDEO_FREQ,
+       RING_TAIL(RENDER_RING_BASE),
+       RING_TAIL(GEN6_BSD_RING_BASE),
+       RING_TAIL(VEBOX_RING_BASE),
+       RING_TAIL(BLT_RING_BASE),
+       /* TODO: Other registers are not yet used */
+};
+
+static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(gen8_shadowed_regs); i++)
+               if (reg == gen8_shadowed_regs[i])
+                       return true;
+
+       return false;
+}
+
+#define __gen8_write(x) \
+static void \
+gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+       bool __needs_put = !is_gen8_shadowed(dev_priv, reg); \
+       REG_WRITE_HEADER; \
+       if (__needs_put) { \
+               dev_priv->uncore.funcs.force_wake_get(dev_priv); \
+       } \
+       __raw_i915_write##x(dev_priv, reg, val); \
+       if (__needs_put) { \
+               dev_priv->uncore.funcs.force_wake_put(dev_priv); \
+       } \
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+}
+
+__gen8_write(8)
+__gen8_write(16)
+__gen8_write(32)
+__gen8_write(64)
 __hsw_write(8)
 __hsw_write(16)
 __hsw_write(32)
@@ -476,6 +517,7 @@ __gen4_write(16)
 __gen4_write(32)
 __gen4_write(64)
 
+#undef __gen8_write
 #undef __hsw_write
 #undef __gen6_write
 #undef __gen5_write
@@ -492,7 +534,7 @@ void intel_uncore_init(struct drm_device *dev)
        if (IS_VALLEYVIEW(dev)) {
                dev_priv->uncore.funcs.force_wake_get = vlv_force_wake_get;
                dev_priv->uncore.funcs.force_wake_put = vlv_force_wake_put;
-       } else if (IS_HASWELL(dev)) {
+       } else if (IS_HASWELL(dev) || IS_GEN8(dev)) {
                dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get;
                dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put;
        } else if (IS_IVYBRIDGE(dev)) {
@@ -534,6 +576,16 @@ void intel_uncore_init(struct drm_device *dev)
        }
 
        switch (INTEL_INFO(dev)->gen) {
+       default:
+               dev_priv->uncore.funcs.mmio_writeb  = gen8_write8;
+               dev_priv->uncore.funcs.mmio_writew  = gen8_write16;
+               dev_priv->uncore.funcs.mmio_writel  = gen8_write32;
+               dev_priv->uncore.funcs.mmio_writeq  = gen8_write64;
+               dev_priv->uncore.funcs.mmio_readb  = gen6_read8;
+               dev_priv->uncore.funcs.mmio_readw  = gen6_read16;
+               dev_priv->uncore.funcs.mmio_readl  = gen6_read32;
+               dev_priv->uncore.funcs.mmio_readq  = gen6_read64;
+               break;
        case 7:
        case 6:
                if (IS_HASWELL(dev)) {
index 503a414..ee6ed63 100644 (file)
@@ -765,8 +765,6 @@ static int mga_crtc_do_set_base(struct drm_crtc *crtc,
        }
        mgag200_bo_unreserve(bo);
 
-       DRM_INFO("mga base %llx\n", gpu_addr);
-
        mga_set_start_address(crtc, (u32)gpu_addr);
 
        return 0;
index e179148..e5fa12b 100644 (file)
@@ -21,6 +21,7 @@ msm-y := \
        msm_drv.o \
        msm_fb.o \
        msm_gem.o \
+       msm_gem_prime.o \
        msm_gem_submit.o \
        msm_gpu.o \
        msm_ringbuffer.o
index 3546386..9588098 100644 (file)
@@ -4,16 +4,16 @@
 /* Autogenerated file, DO NOT EDIT manually!
 
 This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://0x04.net/cgit/index.cgi/rules-ng-ng
-git clone git://0x04.net/rules-ng-ng
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/adreno.xml              (    327 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  30005 bytes, from 2013-07-19 21:30:48)
+- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  31003 bytes, from 2013-09-19 18:50:16)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml       (   8983 bytes, from 2013-07-24 01:38:36)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9712 bytes, from 2013-05-26 15:22:37)
-- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51415 bytes, from 2013-08-03 14:26:05)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9759 bytes, from 2013-09-10 00:52:33)
+- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51983 bytes, from 2013-09-10 00:52:32)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -317,6 +317,38 @@ static inline uint32_t A2XX_RBBM_STATUS_CMDFIFO_AVAIL(uint32_t val)
 #define A2XX_RBBM_STATUS_RB_CNTX_BUSY                          0x40000000
 #define A2XX_RBBM_STATUS_GUI_ACTIVE                            0x80000000
 
+#define REG_A2XX_MH_ARBITER_CONFIG                             0x00000a40
+#define A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT__MASK           0x0000003f
+#define A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT__SHIFT          0
+static inline uint32_t A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(uint32_t val)
+{
+       return ((val) << A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT__SHIFT) & A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT__MASK;
+}
+#define A2XX_MH_ARBITER_CONFIG_SAME_PAGE_GRANULARITY           0x00000040
+#define A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE                   0x00000080
+#define A2XX_MH_ARBITER_CONFIG_L1_ARB_HOLD_ENABLE              0x00000100
+#define A2XX_MH_ARBITER_CONFIG_L2_ARB_CONTROL                  0x00000200
+#define A2XX_MH_ARBITER_CONFIG_PAGE_SIZE__MASK                 0x00001c00
+#define A2XX_MH_ARBITER_CONFIG_PAGE_SIZE__SHIFT                        10
+static inline uint32_t A2XX_MH_ARBITER_CONFIG_PAGE_SIZE(uint32_t val)
+{
+       return ((val) << A2XX_MH_ARBITER_CONFIG_PAGE_SIZE__SHIFT) & A2XX_MH_ARBITER_CONFIG_PAGE_SIZE__MASK;
+}
+#define A2XX_MH_ARBITER_CONFIG_TC_REORDER_ENABLE               0x00002000
+#define A2XX_MH_ARBITER_CONFIG_TC_ARB_HOLD_ENABLE              0x00004000
+#define A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT_ENABLE          0x00008000
+#define A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT__MASK           0x003f0000
+#define A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT__SHIFT          16
+static inline uint32_t A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT(uint32_t val)
+{
+       return ((val) << A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT__SHIFT) & A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT__MASK;
+}
+#define A2XX_MH_ARBITER_CONFIG_CP_CLNT_ENABLE                  0x00400000
+#define A2XX_MH_ARBITER_CONFIG_VGT_CLNT_ENABLE                 0x00800000
+#define A2XX_MH_ARBITER_CONFIG_TC_CLNT_ENABLE                  0x01000000
+#define A2XX_MH_ARBITER_CONFIG_RB_CLNT_ENABLE                  0x02000000
+#define A2XX_MH_ARBITER_CONFIG_PA_CLNT_ENABLE                  0x04000000
+
 #define REG_A2XX_A220_VSC_BIN_SIZE                             0x00000c01
 #define A2XX_A220_VSC_BIN_SIZE_WIDTH__MASK                     0x0000001f
 #define A2XX_A220_VSC_BIN_SIZE_WIDTH__SHIFT                    0
index d183516..d4afdf6 100644 (file)
@@ -4,16 +4,16 @@
 /* Autogenerated file, DO NOT EDIT manually!
 
 This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://0x04.net/cgit/index.cgi/rules-ng-ng
-git clone git://0x04.net/rules-ng-ng
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/adreno.xml              (    327 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  30005 bytes, from 2013-07-19 21:30:48)
+- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  31003 bytes, from 2013-09-19 18:50:16)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml       (   8983 bytes, from 2013-07-24 01:38:36)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9712 bytes, from 2013-05-26 15:22:37)
-- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51415 bytes, from 2013-08-03 14:26:05)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9759 bytes, from 2013-09-10 00:52:33)
+- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51983 bytes, from 2013-09-10 00:52:32)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -637,11 +637,12 @@ static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_OFFSET(float val)
 #define REG_A3XX_GRAS_SU_MODE_CONTROL                          0x00002070
 #define A3XX_GRAS_SU_MODE_CONTROL_CULL_FRONT                   0x00000001
 #define A3XX_GRAS_SU_MODE_CONTROL_CULL_BACK                    0x00000002
-#define A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK          0x000007fc
-#define A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT         2
-static inline uint32_t A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(uint32_t val)
+#define A3XX_GRAS_SU_MODE_CONTROL_FRONT_CW                     0x00000004
+#define A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK          0x000007f8
+#define A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT         3
+static inline uint32_t A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(float val)
 {
-       return ((val) << A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT) & A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK;
+       return ((((uint32_t)(val * 4.0))) << A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT) & A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK;
 }
 #define A3XX_GRAS_SU_MODE_CONTROL_POLY_OFFSET                  0x00000800
 
@@ -745,6 +746,7 @@ static inline uint32_t A3XX_RB_RENDER_CONTROL_BIN_WIDTH(uint32_t val)
 }
 #define A3XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE              0x00001000
 #define A3XX_RB_RENDER_CONTROL_ENABLE_GMEM                     0x00002000
+#define A3XX_RB_RENDER_CONTROL_ALPHA_TEST                      0x00400000
 #define A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__MASK           0x07000000
 #define A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__SHIFT          24
 static inline uint32_t A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC(enum adreno_compare_func val)
@@ -767,7 +769,19 @@ static inline uint32_t A3XX_RB_MSAA_CONTROL_SAMPLE_MASK(uint32_t val)
        return ((val) << A3XX_RB_MSAA_CONTROL_SAMPLE_MASK__SHIFT) & A3XX_RB_MSAA_CONTROL_SAMPLE_MASK__MASK;
 }
 
-#define REG_A3XX_UNKNOWN_20C3                                  0x000020c3
+#define REG_A3XX_RB_ALPHA_REF                                  0x000020c3
+#define A3XX_RB_ALPHA_REF_UINT__MASK                           0x0000ff00
+#define A3XX_RB_ALPHA_REF_UINT__SHIFT                          8
+static inline uint32_t A3XX_RB_ALPHA_REF_UINT(uint32_t val)
+{
+       return ((val) << A3XX_RB_ALPHA_REF_UINT__SHIFT) & A3XX_RB_ALPHA_REF_UINT__MASK;
+}
+#define A3XX_RB_ALPHA_REF_FLOAT__MASK                          0xffff0000
+#define A3XX_RB_ALPHA_REF_FLOAT__SHIFT                         16
+static inline uint32_t A3XX_RB_ALPHA_REF_FLOAT(float val)
+{
+       return ((util_float_to_half(val)) << A3XX_RB_ALPHA_REF_FLOAT__SHIFT) & A3XX_RB_ALPHA_REF_FLOAT__MASK;
+}
 
 static inline uint32_t REG_A3XX_RB_MRT(uint32_t i0) { return 0x000020c4 + 0x4*i0; }
 
@@ -1002,7 +1016,7 @@ static inline uint32_t A3XX_RB_COPY_DEST_INFO_ENDIAN(enum adreno_rb_surface_endi
 #define REG_A3XX_RB_DEPTH_CONTROL                              0x00002100
 #define A3XX_RB_DEPTH_CONTROL_Z_ENABLE                         0x00000002
 #define A3XX_RB_DEPTH_CONTROL_Z_WRITE_ENABLE                   0x00000004
-#define A3XX_RB_DEPTH_CONTROL_EARLY_Z_ENABLE                   0x00000008
+#define A3XX_RB_DEPTH_CONTROL_EARLY_Z_DISABLE                  0x00000008
 #define A3XX_RB_DEPTH_CONTROL_ZFUNC__MASK                      0x00000070
 #define A3XX_RB_DEPTH_CONTROL_ZFUNC__SHIFT                     4
 static inline uint32_t A3XX_RB_DEPTH_CONTROL_ZFUNC(enum adreno_compare_func val)
@@ -1038,7 +1052,8 @@ static inline uint32_t A3XX_RB_DEPTH_PITCH(uint32_t val)
 
 #define REG_A3XX_RB_STENCIL_CONTROL                            0x00002104
 #define A3XX_RB_STENCIL_CONTROL_STENCIL_ENABLE                 0x00000001
-#define A3XX_RB_STENCIL_CONTROL_STENCIL_ENABLE_BF              0x00000004
+#define A3XX_RB_STENCIL_CONTROL_STENCIL_ENABLE_BF              0x00000002
+#define A3XX_RB_STENCIL_CONTROL_STENCIL_READ                   0x00000004
 #define A3XX_RB_STENCIL_CONTROL_FUNC__MASK                     0x00000700
 #define A3XX_RB_STENCIL_CONTROL_FUNC__SHIFT                    8
 static inline uint32_t A3XX_RB_STENCIL_CONTROL_FUNC(enum adreno_compare_func val)
@@ -2074,6 +2089,7 @@ static inline uint32_t A3XX_UCHE_CACHE_INVALIDATE1_REG_OPCODE(enum a3xx_cache_op
 #define REG_A3XX_TP_PERFCOUNTER5_SELECT                                0x00000f09
 
 #define REG_A3XX_TEX_SAMP_0                                    0x00000000
+#define A3XX_TEX_SAMP_0_MIPFILTER_LINEAR                       0x00000002
 #define A3XX_TEX_SAMP_0_XY_MAG__MASK                           0x0000000c
 #define A3XX_TEX_SAMP_0_XY_MAG__SHIFT                          2
 static inline uint32_t A3XX_TEX_SAMP_0_XY_MAG(enum a3xx_tex_filter val)
@@ -2134,6 +2150,12 @@ static inline uint32_t A3XX_TEX_CONST_0_SWIZ_W(enum a3xx_tex_swiz val)
 {
        return ((val) << A3XX_TEX_CONST_0_SWIZ_W__SHIFT) & A3XX_TEX_CONST_0_SWIZ_W__MASK;
 }
+#define A3XX_TEX_CONST_0_MIPLVLS__MASK                         0x000f0000
+#define A3XX_TEX_CONST_0_MIPLVLS__SHIFT                                16
+static inline uint32_t A3XX_TEX_CONST_0_MIPLVLS(uint32_t val)
+{
+       return ((val) << A3XX_TEX_CONST_0_MIPLVLS__SHIFT) & A3XX_TEX_CONST_0_MIPLVLS__MASK;
+}
 #define A3XX_TEX_CONST_0_FMT__MASK                             0x1fc00000
 #define A3XX_TEX_CONST_0_FMT__SHIFT                            22
 static inline uint32_t A3XX_TEX_CONST_0_FMT(enum a3xx_tex_fmt val)
index 61979d4..33dcc60 100644 (file)
@@ -4,16 +4,16 @@
 /* Autogenerated file, DO NOT EDIT manually!
 
 This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://0x04.net/cgit/index.cgi/rules-ng-ng
-git clone git://0x04.net/rules-ng-ng
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/adreno.xml              (    327 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  30005 bytes, from 2013-07-19 21:30:48)
+- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  31003 bytes, from 2013-09-19 18:50:16)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml       (   8983 bytes, from 2013-07-24 01:38:36)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9712 bytes, from 2013-05-26 15:22:37)
-- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51415 bytes, from 2013-08-03 14:26:05)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9759 bytes, from 2013-09-10 00:52:33)
+- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51983 bytes, from 2013-09-10 00:52:32)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index 94c13f4..259ad70 100644 (file)
@@ -4,16 +4,16 @@
 /* Autogenerated file, DO NOT EDIT manually!
 
 This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://0x04.net/cgit/index.cgi/rules-ng-ng
-git clone git://0x04.net/rules-ng-ng
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/adreno.xml              (    327 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  30005 bytes, from 2013-07-19 21:30:48)
+- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  31003 bytes, from 2013-09-19 18:50:16)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml       (   8983 bytes, from 2013-07-24 01:38:36)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9712 bytes, from 2013-05-26 15:22:37)
-- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51415 bytes, from 2013-08-03 14:26:05)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9759 bytes, from 2013-09-10 00:52:33)
+- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51983 bytes, from 2013-09-10 00:52:32)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index 6f8396b..6d4c62b 100644 (file)
@@ -4,13 +4,13 @@
 /* Autogenerated file, DO NOT EDIT manually!
 
 This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://0x04.net/cgit/index.cgi/rules-ng-ng
-git clone git://0x04.net/rules-ng-ng
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    595 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-08-16 22:16:36)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
index aefc1b8..d1df38b 100644 (file)
@@ -4,13 +4,13 @@
 /* Autogenerated file, DO NOT EDIT manually!
 
 This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://0x04.net/cgit/index.cgi/rules-ng-ng
-git clone git://0x04.net/rules-ng-ng
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    595 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-08-16 22:16:36)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
index a225e81..0030a11 100644 (file)
@@ -4,13 +4,13 @@
 /* Autogenerated file, DO NOT EDIT manually!
 
 This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://0x04.net/cgit/index.cgi/rules-ng-ng
-git clone git://0x04.net/rules-ng-ng
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    595 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-08-16 22:16:36)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
index f5fa486..4e939f8 100644 (file)
@@ -4,13 +4,13 @@
 /* Autogenerated file, DO NOT EDIT manually!
 
 This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://0x04.net/cgit/index.cgi/rules-ng-ng
-git clone git://0x04.net/rules-ng-ng
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    595 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-08-16 22:16:36)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
index bee3636..dbde4f6 100644 (file)
@@ -4,13 +4,13 @@
 /* Autogenerated file, DO NOT EDIT manually!
 
 This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://0x04.net/cgit/index.cgi/rules-ng-ng
-git clone git://0x04.net/rules-ng-ng
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    595 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-08-16 22:16:36)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
index bbeeebe..9908ffe 100644 (file)
@@ -4,13 +4,13 @@
 /* Autogenerated file, DO NOT EDIT manually!
 
 This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://0x04.net/cgit/index.cgi/rules-ng-ng
-git clone git://0x04.net/rules-ng-ng
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    595 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-08-16 22:16:36)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
@@ -42,28 +42,28 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
 
-enum mpd4_bpc {
+enum mdp4_bpc {
        BPC1 = 0,
        BPC5 = 1,
        BPC6 = 2,
        BPC8 = 3,
 };
 
-enum mpd4_bpc_alpha {
+enum mdp4_bpc_alpha {
        BPC1A = 0,
        BPC4A = 1,
        BPC6A = 2,
        BPC8A = 3,
 };
 
-enum mpd4_alpha_type {
+enum mdp4_alpha_type {
        FG_CONST = 0,
        BG_CONST = 1,
        FG_PIXEL = 2,
        BG_PIXEL = 3,
 };
 
-enum mpd4_pipe {
+enum mdp4_pipe {
        VG1 = 0,
        VG2 = 1,
        RGB1 = 2,
@@ -73,13 +73,13 @@ enum mpd4_pipe {
        VG4 = 6,
 };
 
-enum mpd4_mixer {
+enum mdp4_mixer {
        MIXER0 = 0,
        MIXER1 = 1,
        MIXER2 = 2,
 };
 
-enum mpd4_mixer_stage_id {
+enum mdp4_mixer_stage_id {
        STAGE_UNUSED = 0,
        STAGE_BASE = 1,
        STAGE0 = 2,
@@ -194,56 +194,56 @@ static inline uint32_t MDP4_DISP_INTF_SEL_EXT(enum mdp4_intf val)
 #define REG_MDP4_LAYERMIXER2_IN_CFG                            0x000100f0
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK                    0x00000007
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT                   0
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE0(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE0(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE0_MIXER1                   0x00000008
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK                    0x00000070
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT                   4
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE1(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE1(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE1_MIXER1                   0x00000080
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK                    0x00000700
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT                   8
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE2(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE2(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE2_MIXER1                   0x00000800
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK                    0x00007000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT                   12
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE3(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE3(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE3_MIXER1                   0x00008000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK                    0x00070000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT                   16
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE4(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE4(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE4_MIXER1                   0x00080000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK                    0x00700000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT                   20
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE5(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE5(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE5_MIXER1                   0x00800000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK                    0x07000000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT                   24
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE6(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE6(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE6_MIXER1                   0x08000000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK                    0x70000000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT                   28
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK;
 }
@@ -254,56 +254,56 @@ static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mpd4_mixer_stage_id va
 #define REG_MDP4_LAYERMIXER_IN_CFG                             0x00010100
 #define MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK                     0x00000007
 #define MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT                    0
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE0(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE0(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1                    0x00000008
 #define MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK                     0x00000070
 #define MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT                    4
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE1(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE1(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1                    0x00000080
 #define MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK                     0x00000700
 #define MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT                    8
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE2(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE2(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1                    0x00000800
 #define MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK                     0x00007000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT                    12
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE3(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE3(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1                    0x00008000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK                     0x00070000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT                    16
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE4(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE4(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1                    0x00080000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK                     0x00700000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT                    20
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE5(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE5(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1                    0x00800000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK                     0x07000000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT                    24
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE6(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE6(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1                    0x08000000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK                     0x70000000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT                    28
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE7(enum mpd4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE7(enum mdp4_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK;
 }
@@ -369,7 +369,7 @@ static inline uint32_t REG_MDP4_OVLP_STAGE(uint32_t i0, uint32_t i1) { return 0x
 static inline uint32_t REG_MDP4_OVLP_STAGE_OP(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE(i1); }
 #define MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK                      0x00000003
 #define MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT                     0
-static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mpd4_alpha_type val)
+static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mdp4_alpha_type val)
 {
        return ((val) << MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK;
 }
@@ -377,7 +377,7 @@ static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mpd4_alpha_type val)
 #define MDP4_OVLP_STAGE_OP_FG_MOD_ALPHA                                0x00000008
 #define MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK                      0x00000030
 #define MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT                     4
-static inline uint32_t MDP4_OVLP_STAGE_OP_BG_ALPHA(enum mpd4_alpha_type val)
+static inline uint32_t MDP4_OVLP_STAGE_OP_BG_ALPHA(enum mdp4_alpha_type val)
 {
        return ((val) << MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK;
 }
@@ -472,19 +472,19 @@ static inline uint32_t REG_MDP4_DMA(enum mdp4_dma i0) { return 0x00000000 + __of
 static inline uint32_t REG_MDP4_DMA_CONFIG(enum mdp4_dma i0) { return 0x00000000 + __offset_DMA(i0); }
 #define MDP4_DMA_CONFIG_G_BPC__MASK                            0x00000003
 #define MDP4_DMA_CONFIG_G_BPC__SHIFT                           0
-static inline uint32_t MDP4_DMA_CONFIG_G_BPC(enum mpd4_bpc val)
+static inline uint32_t MDP4_DMA_CONFIG_G_BPC(enum mdp4_bpc val)
 {
        return ((val) << MDP4_DMA_CONFIG_G_BPC__SHIFT) & MDP4_DMA_CONFIG_G_BPC__MASK;
 }
 #define MDP4_DMA_CONFIG_B_BPC__MASK                            0x0000000c
 #define MDP4_DMA_CONFIG_B_BPC__SHIFT                           2
-static inline uint32_t MDP4_DMA_CONFIG_B_BPC(enum mpd4_bpc val)
+static inline uint32_t MDP4_DMA_CONFIG_B_BPC(enum mdp4_bpc val)
 {
        return ((val) << MDP4_DMA_CONFIG_B_BPC__SHIFT) & MDP4_DMA_CONFIG_B_BPC__MASK;
 }
 #define MDP4_DMA_CONFIG_R_BPC__MASK                            0x00000030
 #define MDP4_DMA_CONFIG_R_BPC__SHIFT                           4
-static inline uint32_t MDP4_DMA_CONFIG_R_BPC(enum mpd4_bpc val)
+static inline uint32_t MDP4_DMA_CONFIG_R_BPC(enum mdp4_bpc val)
 {
        return ((val) << MDP4_DMA_CONFIG_R_BPC__SHIFT) & MDP4_DMA_CONFIG_R_BPC__MASK;
 }
@@ -601,9 +601,9 @@ static inline uint32_t REG_MDP4_DMA_CSC_POST_LV(enum mdp4_dma i0, uint32_t i1) {
 
 static inline uint32_t REG_MDP4_DMA_CSC_POST_LV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003680 + __offset_DMA(i0) + 0x4*i1; }
 
-static inline uint32_t REG_MDP4_PIPE(enum mpd4_pipe i0) { return 0x00020000 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE(enum mdp4_pipe i0) { return 0x00020000 + 0x10000*i0; }
 
-static inline uint32_t REG_MDP4_PIPE_SRC_SIZE(enum mpd4_pipe i0) { return 0x00020000 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SRC_SIZE(enum mdp4_pipe i0) { return 0x00020000 + 0x10000*i0; }
 #define MDP4_PIPE_SRC_SIZE_HEIGHT__MASK                                0xffff0000
 #define MDP4_PIPE_SRC_SIZE_HEIGHT__SHIFT                       16
 static inline uint32_t MDP4_PIPE_SRC_SIZE_HEIGHT(uint32_t val)
@@ -617,7 +617,7 @@ static inline uint32_t MDP4_PIPE_SRC_SIZE_WIDTH(uint32_t val)
        return ((val) << MDP4_PIPE_SRC_SIZE_WIDTH__SHIFT) & MDP4_PIPE_SRC_SIZE_WIDTH__MASK;
 }
 
-static inline uint32_t REG_MDP4_PIPE_SRC_XY(enum mpd4_pipe i0) { return 0x00020004 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SRC_XY(enum mdp4_pipe i0) { return 0x00020004 + 0x10000*i0; }
 #define MDP4_PIPE_SRC_XY_Y__MASK                               0xffff0000
 #define MDP4_PIPE_SRC_XY_Y__SHIFT                              16
 static inline uint32_t MDP4_PIPE_SRC_XY_Y(uint32_t val)
@@ -631,7 +631,7 @@ static inline uint32_t MDP4_PIPE_SRC_XY_X(uint32_t val)
        return ((val) << MDP4_PIPE_SRC_XY_X__SHIFT) & MDP4_PIPE_SRC_XY_X__MASK;
 }
 
-static inline uint32_t REG_MDP4_PIPE_DST_SIZE(enum mpd4_pipe i0) { return 0x00020008 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_DST_SIZE(enum mdp4_pipe i0) { return 0x00020008 + 0x10000*i0; }
 #define MDP4_PIPE_DST_SIZE_HEIGHT__MASK                                0xffff0000
 #define MDP4_PIPE_DST_SIZE_HEIGHT__SHIFT                       16
 static inline uint32_t MDP4_PIPE_DST_SIZE_HEIGHT(uint32_t val)
@@ -645,7 +645,7 @@ static inline uint32_t MDP4_PIPE_DST_SIZE_WIDTH(uint32_t val)
        return ((val) << MDP4_PIPE_DST_SIZE_WIDTH__SHIFT) & MDP4_PIPE_DST_SIZE_WIDTH__MASK;
 }
 
-static inline uint32_t REG_MDP4_PIPE_DST_XY(enum mpd4_pipe i0) { return 0x0002000c + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_DST_XY(enum mdp4_pipe i0) { return 0x0002000c + 0x10000*i0; }
 #define MDP4_PIPE_DST_XY_Y__MASK                               0xffff0000
 #define MDP4_PIPE_DST_XY_Y__SHIFT                              16
 static inline uint32_t MDP4_PIPE_DST_XY_Y(uint32_t val)
@@ -659,13 +659,13 @@ static inline uint32_t MDP4_PIPE_DST_XY_X(uint32_t val)
        return ((val) << MDP4_PIPE_DST_XY_X__SHIFT) & MDP4_PIPE_DST_XY_X__MASK;
 }
 
-static inline uint32_t REG_MDP4_PIPE_SRCP0_BASE(enum mpd4_pipe i0) { return 0x00020010 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SRCP0_BASE(enum mdp4_pipe i0) { return 0x00020010 + 0x10000*i0; }
 
-static inline uint32_t REG_MDP4_PIPE_SRCP1_BASE(enum mpd4_pipe i0) { return 0x00020014 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SRCP1_BASE(enum mdp4_pipe i0) { return 0x00020014 + 0x10000*i0; }
 
-static inline uint32_t REG_MDP4_PIPE_SRCP2_BASE(enum mpd4_pipe i0) { return 0x00020018 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SRCP2_BASE(enum mdp4_pipe i0) { return 0x00020018 + 0x10000*i0; }
 
-static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_A(enum mpd4_pipe i0) { return 0x00020040 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_A(enum mdp4_pipe i0) { return 0x00020040 + 0x10000*i0; }
 #define MDP4_PIPE_SRC_STRIDE_A_P0__MASK                                0x0000ffff
 #define MDP4_PIPE_SRC_STRIDE_A_P0__SHIFT                       0
 static inline uint32_t MDP4_PIPE_SRC_STRIDE_A_P0(uint32_t val)
@@ -679,7 +679,7 @@ static inline uint32_t MDP4_PIPE_SRC_STRIDE_A_P1(uint32_t val)
        return ((val) << MDP4_PIPE_SRC_STRIDE_A_P1__SHIFT) & MDP4_PIPE_SRC_STRIDE_A_P1__MASK;
 }
 
-static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_B(enum mpd4_pipe i0) { return 0x00020044 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_B(enum mdp4_pipe i0) { return 0x00020044 + 0x10000*i0; }
 #define MDP4_PIPE_SRC_STRIDE_B_P2__MASK                                0x0000ffff
 #define MDP4_PIPE_SRC_STRIDE_B_P2__SHIFT                       0
 static inline uint32_t MDP4_PIPE_SRC_STRIDE_B_P2(uint32_t val)
@@ -693,7 +693,7 @@ static inline uint32_t MDP4_PIPE_SRC_STRIDE_B_P3(uint32_t val)
        return ((val) << MDP4_PIPE_SRC_STRIDE_B_P3__SHIFT) & MDP4_PIPE_SRC_STRIDE_B_P3__MASK;
 }
 
-static inline uint32_t REG_MDP4_PIPE_FRAME_SIZE(enum mpd4_pipe i0) { return 0x00020048 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_FRAME_SIZE(enum mdp4_pipe i0) { return 0x00020048 + 0x10000*i0; }
 #define MDP4_PIPE_FRAME_SIZE_HEIGHT__MASK                      0xffff0000
 #define MDP4_PIPE_FRAME_SIZE_HEIGHT__SHIFT                     16
 static inline uint32_t MDP4_PIPE_FRAME_SIZE_HEIGHT(uint32_t val)
@@ -707,28 +707,28 @@ static inline uint32_t MDP4_PIPE_FRAME_SIZE_WIDTH(uint32_t val)
        return ((val) << MDP4_PIPE_FRAME_SIZE_WIDTH__SHIFT) & MDP4_PIPE_FRAME_SIZE_WIDTH__MASK;
 }
 
-static inline uint32_t REG_MDP4_PIPE_SRC_FORMAT(enum mpd4_pipe i0) { return 0x00020050 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SRC_FORMAT(enum mdp4_pipe i0) { return 0x00020050 + 0x10000*i0; }
 #define MDP4_PIPE_SRC_FORMAT_G_BPC__MASK                       0x00000003
 #define MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT                      0
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_G_BPC(enum mpd4_bpc val)
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_G_BPC(enum mdp4_bpc val)
 {
        return ((val) << MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_G_BPC__MASK;
 }
 #define MDP4_PIPE_SRC_FORMAT_B_BPC__MASK                       0x0000000c
 #define MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT                      2
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_B_BPC(enum mpd4_bpc val)
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_B_BPC(enum mdp4_bpc val)
 {
        return ((val) << MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_B_BPC__MASK;
 }
 #define MDP4_PIPE_SRC_FORMAT_R_BPC__MASK                       0x00000030
 #define MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT                      4
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_R_BPC(enum mpd4_bpc val)
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_R_BPC(enum mdp4_bpc val)
 {
        return ((val) << MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_R_BPC__MASK;
 }
 #define MDP4_PIPE_SRC_FORMAT_A_BPC__MASK                       0x000000c0
 #define MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT                      6
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_A_BPC(enum mpd4_bpc_alpha val)
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_A_BPC(enum mdp4_bpc_alpha val)
 {
        return ((val) << MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_A_BPC__MASK;
 }
@@ -750,7 +750,7 @@ static inline uint32_t MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val)
 #define MDP4_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB                  0x00040000
 #define MDP4_PIPE_SRC_FORMAT_SOLID_FILL                                0x00400000
 
-static inline uint32_t REG_MDP4_PIPE_SRC_UNPACK(enum mpd4_pipe i0) { return 0x00020054 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SRC_UNPACK(enum mdp4_pipe i0) { return 0x00020054 + 0x10000*i0; }
 #define MDP4_PIPE_SRC_UNPACK_ELEM0__MASK                       0x000000ff
 #define MDP4_PIPE_SRC_UNPACK_ELEM0__SHIFT                      0
 static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM0(uint32_t val)
@@ -776,7 +776,7 @@ static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM3(uint32_t val)
        return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM3__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM3__MASK;
 }
 
-static inline uint32_t REG_MDP4_PIPE_OP_MODE(enum mpd4_pipe i0) { return 0x00020058 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_OP_MODE(enum mdp4_pipe i0) { return 0x00020058 + 0x10000*i0; }
 #define MDP4_PIPE_OP_MODE_SCALEX_EN                            0x00000001
 #define MDP4_PIPE_OP_MODE_SCALEY_EN                            0x00000002
 #define MDP4_PIPE_OP_MODE_SRC_YCBCR                            0x00000200
@@ -789,36 +789,36 @@ static inline uint32_t REG_MDP4_PIPE_OP_MODE(enum mpd4_pipe i0) { return 0x00020
 #define MDP4_PIPE_OP_MODE_DEINT_EN                             0x00040000
 #define MDP4_PIPE_OP_MODE_DEINT_ODD_REF                                0x00080000
 
-static inline uint32_t REG_MDP4_PIPE_PHASEX_STEP(enum mpd4_pipe i0) { return 0x0002005c + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_PHASEX_STEP(enum mdp4_pipe i0) { return 0x0002005c + 0x10000*i0; }
 
-static inline uint32_t REG_MDP4_PIPE_PHASEY_STEP(enum mpd4_pipe i0) { return 0x00020060 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_PHASEY_STEP(enum mdp4_pipe i0) { return 0x00020060 + 0x10000*i0; }
 
-static inline uint32_t REG_MDP4_PIPE_FETCH_CONFIG(enum mpd4_pipe i0) { return 0x00021004 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_FETCH_CONFIG(enum mdp4_pipe i0) { return 0x00021004 + 0x10000*i0; }
 
-static inline uint32_t REG_MDP4_PIPE_SOLID_COLOR(enum mpd4_pipe i0) { return 0x00021008 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SOLID_COLOR(enum mdp4_pipe i0) { return 0x00021008 + 0x10000*i0; }
 
-static inline uint32_t REG_MDP4_PIPE_CSC(enum mpd4_pipe i0) { return 0x00024000 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_CSC(enum mdp4_pipe i0) { return 0x00024000 + 0x10000*i0; }
 
 
-static inline uint32_t REG_MDP4_PIPE_CSC_MV(enum mpd4_pipe i0, uint32_t i1) { return 0x00024400 + 0x10000*i0 + 0x4*i1; }
+static inline uint32_t REG_MDP4_PIPE_CSC_MV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024400 + 0x10000*i0 + 0x4*i1; }
 
-static inline uint32_t REG_MDP4_PIPE_CSC_MV_VAL(enum mpd4_pipe i0, uint32_t i1) { return 0x00024400 + 0x10000*i0 + 0x4*i1; }
+static inline uint32_t REG_MDP4_PIPE_CSC_MV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024400 + 0x10000*i0 + 0x4*i1; }
 
-static inline uint32_t REG_MDP4_PIPE_CSC_PRE_BV(enum mpd4_pipe i0, uint32_t i1) { return 0x00024500 + 0x10000*i0 + 0x4*i1; }
+static inline uint32_t REG_MDP4_PIPE_CSC_PRE_BV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024500 + 0x10000*i0 + 0x4*i1; }
 
-static inline uint32_t REG_MDP4_PIPE_CSC_PRE_BV_VAL(enum mpd4_pipe i0, uint32_t i1) { return 0x00024500 + 0x10000*i0 + 0x4*i1; }
+static inline uint32_t REG_MDP4_PIPE_CSC_PRE_BV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024500 + 0x10000*i0 + 0x4*i1; }
 
-static inline uint32_t REG_MDP4_PIPE_CSC_POST_BV(enum mpd4_pipe i0, uint32_t i1) { return 0x00024580 + 0x10000*i0 + 0x4*i1; }
+static inline uint32_t REG_MDP4_PIPE_CSC_POST_BV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024580 + 0x10000*i0 + 0x4*i1; }
 
-static inline uint32_t REG_MDP4_PIPE_CSC_POST_BV_VAL(enum mpd4_pipe i0, uint32_t i1) { return 0x00024580 + 0x10000*i0 + 0x4*i1; }
+static inline uint32_t REG_MDP4_PIPE_CSC_POST_BV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024580 + 0x10000*i0 + 0x4*i1; }
 
-static inline uint32_t REG_MDP4_PIPE_CSC_PRE_LV(enum mpd4_pipe i0, uint32_t i1) { return 0x00024600 + 0x10000*i0 + 0x4*i1; }
+static inline uint32_t REG_MDP4_PIPE_CSC_PRE_LV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024600 + 0x10000*i0 + 0x4*i1; }
 
-static inline uint32_t REG_MDP4_PIPE_CSC_PRE_LV_VAL(enum mpd4_pipe i0, uint32_t i1) { return 0x00024600 + 0x10000*i0 + 0x4*i1; }
+static inline uint32_t REG_MDP4_PIPE_CSC_PRE_LV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024600 + 0x10000*i0 + 0x4*i1; }
 
-static inline uint32_t REG_MDP4_PIPE_CSC_POST_LV(enum mpd4_pipe i0, uint32_t i1) { return 0x00024680 + 0x10000*i0 + 0x4*i1; }
+static inline uint32_t REG_MDP4_PIPE_CSC_POST_LV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024680 + 0x10000*i0 + 0x4*i1; }
 
-static inline uint32_t REG_MDP4_PIPE_CSC_POST_LV_VAL(enum mpd4_pipe i0, uint32_t i1) { return 0x00024680 + 0x10000*i0 + 0x4*i1; }
+static inline uint32_t REG_MDP4_PIPE_CSC_POST_LV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024680 + 0x10000*i0 + 0x4*i1; }
 
 #define REG_MDP4_LCDC                                          0x000c0000
 
index de6bea2..019d530 100644 (file)
@@ -26,6 +26,7 @@ struct mdp4_crtc {
        struct drm_crtc base;
        char name[8];
        struct drm_plane *plane;
+       struct drm_plane *planes[8];
        int id;
        int ovlp;
        enum mdp4_dma dma;
@@ -50,7 +51,11 @@ struct mdp4_crtc {
 
        /* if there is a pending flip, these will be non-null: */
        struct drm_pending_vblank_event *event;
-       struct work_struct pageflip_work;
+       struct msm_fence_cb pageflip_cb;
+
+#define PENDING_CURSOR 0x1
+#define PENDING_FLIP   0x2
+       atomic_t pending;
 
        /* the fb that we currently hold a scanout ref to: */
        struct drm_framebuffer *fb;
@@ -92,7 +97,8 @@ static void update_fb(struct drm_crtc *crtc, bool async,
        }
 }
 
-static void complete_flip(struct drm_crtc *crtc, bool canceled)
+/* if file!=NULL, this is preclose potential cancel-flip path */
+static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        struct drm_device *dev = crtc->dev;
@@ -102,11 +108,14 @@ static void complete_flip(struct drm_crtc *crtc, bool canceled)
        spin_lock_irqsave(&dev->event_lock, flags);
        event = mdp4_crtc->event;
        if (event) {
-               mdp4_crtc->event = NULL;
-               if (canceled)
-                       event->base.destroy(&event->base);
-               else
+               /* if regular vblank case (!file) or if cancel-flip from
+                * preclose on file that requested flip, then send the
+                * event:
+                */
+               if (!file || (event->base.file_priv == file)) {
+                       mdp4_crtc->event = NULL;
                        drm_send_vblank_event(dev, mdp4_crtc->id, event);
+               }
        }
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
@@ -115,9 +124,15 @@ static void crtc_flush(struct drm_crtc *crtc)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        struct mdp4_kms *mdp4_kms = get_kms(crtc);
-       uint32_t flush = 0;
+       uint32_t i, flush = 0;
 
-       flush |= pipe2flush(mdp4_plane_pipe(mdp4_crtc->plane));
+       for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
+               struct drm_plane *plane = mdp4_crtc->planes[i];
+               if (plane) {
+                       enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+                       flush |= pipe2flush(pipe_id);
+               }
+       }
        flush |= ovlp2flush(mdp4_crtc->ovlp);
 
        DBG("%s: flush=%08x", mdp4_crtc->name, flush);
@@ -125,17 +140,29 @@ static void crtc_flush(struct drm_crtc *crtc)
        mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush);
 }
 
-static void pageflip_worker(struct work_struct *work)
+static void request_pending(struct drm_crtc *crtc, uint32_t pending)
+{
+       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+
+       atomic_or(pending, &mdp4_crtc->pending);
+       mdp4_irq_register(get_kms(crtc), &mdp4_crtc->vblank);
+}
+
+static void pageflip_cb(struct msm_fence_cb *cb)
 {
        struct mdp4_crtc *mdp4_crtc =
-               container_of(work, struct mdp4_crtc, pageflip_work);
+               container_of(cb, struct mdp4_crtc, pageflip_cb);
        struct drm_crtc *crtc = &mdp4_crtc->base;
+       struct drm_framebuffer *fb = crtc->fb;
 
-       mdp4_plane_set_scanout(mdp4_crtc->plane, crtc->fb);
+       if (!fb)
+               return;
+
+       mdp4_plane_set_scanout(mdp4_crtc->plane, fb);
        crtc_flush(crtc);
 
        /* enable vblank to complete flip: */
-       mdp4_irq_register(get_kms(crtc), &mdp4_crtc->vblank);
+       request_pending(crtc, PENDING_FLIP);
 }
 
 static void unref_fb_worker(struct drm_flip_work *work, void *val)
@@ -205,67 +232,69 @@ static void blend_setup(struct drm_crtc *crtc)
        struct mdp4_kms *mdp4_kms = get_kms(crtc);
        int i, ovlp = mdp4_crtc->ovlp;
        uint32_t mixer_cfg = 0;
-
-       /*
-        * This probably would also need to be triggered by any attached
-        * plane when it changes.. for now since we are only using a single
-        * private plane, the configuration is hard-coded:
-        */
+       static const enum mdp4_mixer_stage_id stages[] = {
+                       STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3,
+       };
+       /* statically (for now) map planes to mixer stage (z-order): */
+       static const int idxs[] = {
+                       [VG1]  = 1,
+                       [VG2]  = 2,
+                       [RGB1] = 0,
+                       [RGB2] = 0,
+                       [RGB3] = 0,
+                       [VG3]  = 3,
+                       [VG4]  = 4,
+
+       };
+       bool alpha[4]= { false, false, false, false };
 
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0);
 
+       /* TODO single register for all CRTCs, so this won't work properly
+        * when multiple CRTCs are active..
+        */
+       for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
+               struct drm_plane *plane = mdp4_crtc->planes[i];
+               if (plane) {
+                       enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+                       int idx = idxs[pipe_id];
+                       if (idx > 0) {
+                               const struct mdp4_format *format =
+                                       to_mdp4_format(msm_framebuffer_format(plane->fb));
+                               alpha[idx-1] = format->alpha_enable;
+                       }
+                       mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]);
+               }
+       }
+
+       /* this shouldn't happen.. and seems to cause underflow: */
+       WARN_ON(!mixer_cfg);
+
        for (i = 0; i < 4; i++) {
-               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_FG_ALPHA(ovlp, i), 0);
-               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_BG_ALPHA(ovlp, i), 0);
-               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_OP(ovlp, i),
-                               MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_CONST) |
-                               MDP4_OVLP_STAGE_OP_BG_ALPHA(BG_CONST));
-               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_CO3(ovlp, i), 0);
+               uint32_t op;
+
+               if (alpha[i]) {
+                       op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_PIXEL) |
+                                       MDP4_OVLP_STAGE_OP_BG_ALPHA(FG_PIXEL) |
+                                       MDP4_OVLP_STAGE_OP_BG_INV_ALPHA;
+               } else {
+                       op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_CONST) |
+                                       MDP4_OVLP_STAGE_OP_BG_ALPHA(BG_CONST);
+               }
+
+               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_FG_ALPHA(ovlp, i), 0xff);
+               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_BG_ALPHA(ovlp, i), 0x00);
+               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_OP(ovlp, i), op);
+               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_CO3(ovlp, i), 1);
                mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW0(ovlp, i), 0);
                mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW1(ovlp, i), 0);
                mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH0(ovlp, i), 0);
                mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0);
        }
 
-       /* TODO single register for all CRTCs, so this won't work properly
-        * when multiple CRTCs are active..
-        */
-       switch (mdp4_plane_pipe(mdp4_crtc->plane)) {
-       case VG1:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE0(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
-               break;
-       case VG2:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE1(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
-               break;
-       case RGB1:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE2(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
-               break;
-       case RGB2:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE3(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
-               break;
-       case RGB3:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE4(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
-               break;
-       case VG3:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE5(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
-               break;
-       case VG4:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE6(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
-               break;
-       default:
-               WARN_ON("invalid pipe");
-               break;
-       }
        mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
 }
 
@@ -377,6 +406,7 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct drm_gem_object *obj;
+       unsigned long flags;
 
        if (mdp4_crtc->event) {
                dev_err(dev->dev, "already pending flip!\n");
@@ -385,11 +415,13 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
 
        obj = msm_framebuffer_bo(new_fb, 0);
 
+       spin_lock_irqsave(&dev->event_lock, flags);
        mdp4_crtc->event = event;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
        update_fb(crtc, true, new_fb);
 
-       return msm_gem_queue_inactive_work(obj,
-                       &mdp4_crtc->pageflip_work);
+       return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb);
 }
 
 static int mdp4_crtc_set_property(struct drm_crtc *crtc,
@@ -498,6 +530,8 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc,
                drm_gem_object_unreference_unlocked(old_bo);
        }
 
+       request_pending(crtc, PENDING_CURSOR);
+
        return 0;
 
 fail:
@@ -542,13 +576,21 @@ static void mdp4_crtc_vblank_irq(struct mdp4_irq *irq, uint32_t irqstatus)
        struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank);
        struct drm_crtc *crtc = &mdp4_crtc->base;
        struct msm_drm_private *priv = crtc->dev->dev_private;
+       unsigned pending;
 
-       update_cursor(crtc);
-       complete_flip(crtc, false);
        mdp4_irq_unregister(get_kms(crtc), &mdp4_crtc->vblank);
 
-       drm_flip_work_commit(&mdp4_crtc->unref_fb_work, priv->wq);
-       drm_flip_work_commit(&mdp4_crtc->unref_cursor_work, priv->wq);
+       pending = atomic_xchg(&mdp4_crtc->pending, 0);
+
+       if (pending & PENDING_FLIP) {
+               complete_flip(crtc, NULL);
+               drm_flip_work_commit(&mdp4_crtc->unref_fb_work, priv->wq);
+       }
+
+       if (pending & PENDING_CURSOR) {
+               update_cursor(crtc);
+               drm_flip_work_commit(&mdp4_crtc->unref_cursor_work, priv->wq);
+       }
 }
 
 static void mdp4_crtc_err_irq(struct mdp4_irq *irq, uint32_t irqstatus)
@@ -565,9 +607,10 @@ uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc)
        return mdp4_crtc->vblank.irqmask;
 }
 
-void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc)
+void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
 {
-       complete_flip(crtc, true);
+       DBG("cancel: %p", file);
+       complete_flip(crtc, file);
 }
 
 /* set dma config, ie. the format the encoder wants. */
@@ -622,6 +665,32 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf)
        mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel);
 }
 
+static void set_attach(struct drm_crtc *crtc, enum mdp4_pipe pipe_id,
+               struct drm_plane *plane)
+{
+       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+
+       BUG_ON(pipe_id >= ARRAY_SIZE(mdp4_crtc->planes));
+
+       if (mdp4_crtc->planes[pipe_id] == plane)
+               return;
+
+       mdp4_crtc->planes[pipe_id] = plane;
+       blend_setup(crtc);
+       if (mdp4_crtc->enabled && (plane != mdp4_crtc->plane))
+               crtc_flush(crtc);
+}
+
+void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
+{
+       set_attach(crtc, mdp4_plane_pipe(plane), plane);
+}
+
+void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
+{
+       set_attach(crtc, mdp4_plane_pipe(plane), NULL);
+}
+
 static const char *dma_names[] = {
                "DMA_P", "DMA_S", "DMA_E",
 };
@@ -644,7 +713,6 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
        crtc = &mdp4_crtc->base;
 
        mdp4_crtc->plane = plane;
-       mdp4_crtc->plane->crtc = crtc;
 
        mdp4_crtc->ovlp = ovlp_id;
        mdp4_crtc->dma = dma_id;
@@ -668,7 +736,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
        ret = drm_flip_work_init(&mdp4_crtc->unref_cursor_work, 64,
                        "unref cursor", unref_cursor_worker);
 
-       INIT_WORK(&mdp4_crtc->pageflip_work, pageflip_worker);
+       INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb);
 
        drm_crtc_init(dev, crtc, &mdp4_crtc_funcs);
        drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
index 7b645f2..17330b0 100644 (file)
@@ -44,6 +44,22 @@ static const struct mdp4_format formats[] = {
        FMT(BGR565,   0, 5, 6, 5,  2, 0, 1, 0,  false,  true,  2,  3),
 };
 
+uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats,
+               uint32_t max_formats)
+{
+       uint32_t i;
+       for (i = 0; i < ARRAY_SIZE(formats); i++) {
+               const struct mdp4_format *f = &formats[i];
+
+               if (i == max_formats)
+                       break;
+
+               pixel_formats[i] = f->base.pixel_format;
+       }
+
+       return i;
+}
+
 const struct msm_format *mdp4_get_format(struct msm_kms *kms, uint32_t format)
 {
        int i;
index bc7fd11..8972ac3 100644 (file)
@@ -135,7 +135,7 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)
        unsigned i;
 
        for (i = 0; i < priv->num_crtcs; i++)
-               mdp4_crtc_cancel_pending_flip(priv->crtcs[i]);
+               mdp4_crtc_cancel_pending_flip(priv->crtcs[i], file);
 }
 
 static void mdp4_destroy(struct msm_kms *kms)
@@ -196,6 +196,23 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
         * for more than just RGB1->DMA_E->DTV->HDMI
         */
 
+       /* construct non-private planes: */
+       plane = mdp4_plane_init(dev, VG1, false);
+       if (IS_ERR(plane)) {
+               dev_err(dev->dev, "failed to construct plane for VG1\n");
+               ret = PTR_ERR(plane);
+               goto fail;
+       }
+       priv->planes[priv->num_planes++] = plane;
+
+       plane = mdp4_plane_init(dev, VG2, false);
+       if (IS_ERR(plane)) {
+               dev_err(dev->dev, "failed to construct plane for VG2\n");
+               ret = PTR_ERR(plane);
+               goto fail;
+       }
+       priv->planes[priv->num_planes++] = plane;
+
        /* the CRTCs get constructed with a private plane: */
        plane = mdp4_plane_init(dev, RGB1, true);
        if (IS_ERR(plane)) {
index 1e83554..eb015c8 100644 (file)
@@ -75,8 +75,8 @@ struct mdp4_platform_config {
 
 struct mdp4_format {
        struct msm_format base;
-       enum mpd4_bpc bpc_r, bpc_g, bpc_b;
-       enum mpd4_bpc_alpha bpc_a;
+       enum mdp4_bpc bpc_r, bpc_g, bpc_b;
+       enum mdp4_bpc_alpha bpc_a;
        uint8_t unpack[4];
        bool alpha_enable, unpack_tight;
        uint8_t cpp, unpack_count;
@@ -93,7 +93,7 @@ static inline u32 mdp4_read(struct mdp4_kms *mdp4_kms, u32 reg)
        return msm_readl(mdp4_kms->mmio + reg);
 }
 
-static inline uint32_t pipe2flush(enum mpd4_pipe pipe)
+static inline uint32_t pipe2flush(enum mdp4_pipe pipe)
 {
        switch (pipe) {
        case VG1:      return MDP4_OVERLAY_FLUSH_VG1;
@@ -133,6 +133,48 @@ static inline uint32_t dma2err(enum mdp4_dma dma)
        }
 }
 
+static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe,
+               enum mdp4_mixer_stage_id stage)
+{
+       uint32_t mixer_cfg = 0;
+
+       switch (pipe) {
+       case VG1:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
+               break;
+       case VG2:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
+               break;
+       case RGB1:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
+               break;
+       case RGB2:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
+               break;
+       case RGB3:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
+               break;
+       case VG3:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
+               break;
+       case VG4:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
+               break;
+       default:
+               WARN_ON("invalid pipe");
+               break;
+       }
+
+       return mixer_cfg;
+}
+
 int mdp4_disable(struct mdp4_kms *mdp4_kms);
 int mdp4_enable(struct mdp4_kms *mdp4_kms);
 
@@ -146,6 +188,8 @@ void mdp4_irq_unregister(struct mdp4_kms *mdp4_kms, struct mdp4_irq *irq);
 int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 
+uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *formats,
+               uint32_t max_formats);
 const struct msm_format *mdp4_get_format(struct msm_kms *kms, uint32_t format);
 
 void mdp4_plane_install_properties(struct drm_plane *plane,
@@ -158,14 +202,16 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
                unsigned int crtc_w, unsigned int crtc_h,
                uint32_t src_x, uint32_t src_y,
                uint32_t src_w, uint32_t src_h);
-enum mpd4_pipe mdp4_plane_pipe(struct drm_plane *plane);
+enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane);
 struct drm_plane *mdp4_plane_init(struct drm_device *dev,
-               enum mpd4_pipe pipe_id, bool private_plane);
+               enum mdp4_pipe pipe_id, bool private_plane);
 
 uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc);
-void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc);
+void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
 void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config);
 void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf);
+void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane);
+void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane);
 struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
                struct drm_plane *plane, int id, int ovlp_id,
                enum mdp4_dma dma_id);
index 3468229..0f0af24 100644 (file)
@@ -22,7 +22,7 @@ struct mdp4_plane {
        struct drm_plane base;
        const char *name;
 
-       enum mpd4_pipe pipe;
+       enum mdp4_pipe pipe;
 
        uint32_t nformats;
        uint32_t formats[32];
@@ -61,7 +61,9 @@ static int mdp4_plane_update(struct drm_plane *plane,
 static int mdp4_plane_disable(struct drm_plane *plane)
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
-       DBG("%s: TODO", mdp4_plane->name); // XXX
+       DBG("%s: disable", mdp4_plane->name);
+       if (plane->crtc)
+               mdp4_crtc_detach(plane->crtc, plane);
        return 0;
 }
 
@@ -101,7 +103,7 @@ void mdp4_plane_set_scanout(struct drm_plane *plane,
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
        struct mdp4_kms *mdp4_kms = get_kms(plane);
-       enum mpd4_pipe pipe = mdp4_plane->pipe;
+       enum mdp4_pipe pipe = mdp4_plane->pipe;
        uint32_t iova;
 
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_A(pipe),
@@ -129,7 +131,7 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
        struct mdp4_kms *mdp4_kms = get_kms(plane);
-       enum mpd4_pipe pipe = mdp4_plane->pipe;
+       enum mdp4_pipe pipe = mdp4_plane->pipe;
        const struct mdp4_format *format;
        uint32_t op_mode = 0;
        uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT;
@@ -141,6 +143,10 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
        src_w = src_w >> 16;
        src_h = src_h >> 16;
 
+       DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane->name,
+                       fb->base.id, src_x, src_y, src_w, src_h,
+                       crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
+
        if (src_w != crtc_w) {
                op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN;
                /* TODO calc phasex_step */
@@ -191,7 +197,8 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step);
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step);
 
-       plane->crtc = crtc;
+       /* TODO detach from old crtc (if we had more than one) */
+       mdp4_crtc_attach(crtc, plane);
 
        return 0;
 }
@@ -202,7 +209,7 @@ static const char *pipe_names[] = {
                "VG3", "VG4",
 };
 
-enum mpd4_pipe mdp4_plane_pipe(struct drm_plane *plane)
+enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane)
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
        return mdp4_plane->pipe;
@@ -210,9 +217,8 @@ enum mpd4_pipe mdp4_plane_pipe(struct drm_plane *plane)
 
 /* initialize plane */
 struct drm_plane *mdp4_plane_init(struct drm_device *dev,
-               enum mpd4_pipe pipe_id, bool private_plane)
+               enum mdp4_pipe pipe_id, bool private_plane)
 {
-       struct msm_drm_private *priv = dev->dev_private;
        struct drm_plane *plane = NULL;
        struct mdp4_plane *mdp4_plane;
        int ret;
@@ -228,8 +234,12 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
        mdp4_plane->pipe = pipe_id;
        mdp4_plane->name = pipe_names[pipe_id];
 
-       drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &mdp4_plane_funcs,
-                       mdp4_plane->formats, mdp4_plane->nformats, private_plane);
+       mdp4_plane->nformats = mdp4_get_formats(pipe_id, mdp4_plane->formats,
+                       ARRAY_SIZE(mdp4_plane->formats));
+
+       drm_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
+                       mdp4_plane->formats, mdp4_plane->nformats,
+                       private_plane);
 
        mdp4_plane_install_properties(plane, &plane->base);
 
index b3a2f16..8653769 100644 (file)
@@ -187,6 +187,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
        init_waitqueue_head(&priv->fence_event);
 
        INIT_LIST_HEAD(&priv->inactive_list);
+       INIT_LIST_HEAD(&priv->fence_cbs);
 
        drm_mode_config_init(dev);
 
@@ -539,15 +540,36 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
        return ret;
 }
 
-/* call under struct_mutex */
+/* called from workqueue */
 void msm_update_fence(struct drm_device *dev, uint32_t fence)
 {
        struct msm_drm_private *priv = dev->dev_private;
 
-       if (fence > priv->completed_fence) {
-               priv->completed_fence = fence;
-               wake_up_all(&priv->fence_event);
+       mutex_lock(&dev->struct_mutex);
+       priv->completed_fence = max(fence, priv->completed_fence);
+
+       while (!list_empty(&priv->fence_cbs)) {
+               struct msm_fence_cb *cb;
+
+               cb = list_first_entry(&priv->fence_cbs,
+                               struct msm_fence_cb, work.entry);
+
+               if (cb->fence > priv->completed_fence)
+                       break;
+
+               list_del_init(&cb->work.entry);
+               queue_work(priv->wq, &cb->work);
        }
+
+       mutex_unlock(&dev->struct_mutex);
+
+       wake_up_all(&priv->fence_event);
+}
+
+void __msm_fence_worker(struct work_struct *work)
+{
+       struct msm_fence_cb *cb = container_of(work, struct msm_fence_cb, work);
+       cb->func(cb);
 }
 
 /*
@@ -650,13 +672,13 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
 }
 
 static const struct drm_ioctl_desc msm_ioctls[] = {
-       DRM_IOCTL_DEF_DRV(MSM_GET_PARAM,    msm_ioctl_get_param,    DRM_UNLOCKED|DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(MSM_GEM_NEW,      msm_ioctl_gem_new,      DRM_UNLOCKED|DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(MSM_GEM_INFO,     msm_ioctl_gem_info,     DRM_UNLOCKED|DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT,   msm_ioctl_gem_submit,   DRM_UNLOCKED|DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE,   msm_ioctl_wait_fence,   DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(MSM_GET_PARAM,    msm_ioctl_get_param,    DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(MSM_GEM_NEW,      msm_ioctl_gem_new,      DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(MSM_GEM_INFO,     msm_ioctl_gem_info,     DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT,   msm_ioctl_gem_submit,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE,   msm_ioctl_wait_fence,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
 };
 
 static const struct vm_operations_struct vm_ops = {
@@ -680,7 +702,11 @@ static const struct file_operations fops = {
 };
 
 static struct drm_driver msm_driver = {
-       .driver_features    = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
+       .driver_features    = DRIVER_HAVE_IRQ |
+                               DRIVER_GEM |
+                               DRIVER_PRIME |
+                               DRIVER_RENDER |
+                               DRIVER_MODESET,
        .load               = msm_load,
        .unload             = msm_unload,
        .open               = msm_open,
@@ -698,6 +724,16 @@ static struct drm_driver msm_driver = {
        .dumb_create        = msm_gem_dumb_create,
        .dumb_map_offset    = msm_gem_dumb_map_offset,
        .dumb_destroy       = drm_gem_dumb_destroy,
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export   = drm_gem_prime_export,
+       .gem_prime_import   = drm_gem_prime_import,
+       .gem_prime_pin      = msm_gem_prime_pin,
+       .gem_prime_unpin    = msm_gem_prime_unpin,
+       .gem_prime_get_sg_table = msm_gem_prime_get_sg_table,
+       .gem_prime_import_sg_table = msm_gem_prime_import_sg_table,
+       .gem_prime_vmap     = msm_gem_prime_vmap,
+       .gem_prime_vunmap   = msm_gem_prime_vunmap,
 #ifdef CONFIG_DEBUG_FS
        .debugfs_init       = msm_debugfs_init,
        .debugfs_cleanup    = msm_debugfs_cleanup,
index df8f1d0..d39f086 100644 (file)
@@ -73,10 +73,16 @@ struct msm_drm_private {
 
        struct workqueue_struct *wq;
 
+       /* callbacks deferred until bo is inactive: */
+       struct list_head fence_cbs;
+
        /* registered IOMMU domains: */
        unsigned int num_iommus;
        struct iommu_domain *iommus[NUM_DOMAINS];
 
+       unsigned int num_planes;
+       struct drm_plane *planes[8];
+
        unsigned int num_crtcs;
        struct drm_crtc *crtcs[8];
 
@@ -94,6 +100,20 @@ struct msm_format {
        uint32_t pixel_format;
 };
 
+/* callback from wq once fence has passed: */
+struct msm_fence_cb {
+       struct work_struct work;
+       uint32_t fence;
+       void (*func)(struct msm_fence_cb *cb);
+};
+
+void __msm_fence_worker(struct work_struct *work);
+
+#define INIT_FENCE_CB(_cb, _func)  do {                     \
+               INIT_WORK(&(_cb)->work, __msm_fence_worker); \
+               (_cb)->func = _func;                         \
+       } while (0)
+
 /* As there are different display controller blocks depending on the
  * snapdragon version, the kms support is split out and the appropriate
  * implementation is loaded at runtime.  The kms module is responsible
@@ -141,17 +161,24 @@ uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj);
 int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
                uint32_t *iova);
 int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova);
+struct page **msm_gem_get_pages(struct drm_gem_object *obj);
+void msm_gem_put_pages(struct drm_gem_object *obj);
 void msm_gem_put_iova(struct drm_gem_object *obj, int id);
 int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
                struct drm_mode_create_dumb *args);
-int msm_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev,
-               uint32_t handle);
 int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
                uint32_t handle, uint64_t *offset);
+struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj);
+void *msm_gem_prime_vmap(struct drm_gem_object *obj);
+void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
+               size_t size, struct sg_table *sg);
+int msm_gem_prime_pin(struct drm_gem_object *obj);
+void msm_gem_prime_unpin(struct drm_gem_object *obj);
 void *msm_gem_vaddr_locked(struct drm_gem_object *obj);
 void *msm_gem_vaddr(struct drm_gem_object *obj);
-int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
-               struct work_struct *work);
+int msm_gem_queue_inactive_cb(struct drm_gem_object *obj,
+               struct msm_fence_cb *cb);
 void msm_gem_move_to_active(struct drm_gem_object *obj,
                struct msm_gpu *gpu, bool write, uint32_t fence);
 void msm_gem_move_to_inactive(struct drm_gem_object *obj);
@@ -163,6 +190,8 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
                uint32_t size, uint32_t flags, uint32_t *handle);
 struct drm_gem_object *msm_gem_new(struct drm_device *dev,
                uint32_t size, uint32_t flags);
+struct drm_gem_object *msm_gem_import(struct drm_device *dev,
+               uint32_t size, struct sg_table *sgt);
 
 struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane);
 const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
index 2bae46c..e587d25 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/spinlock.h>
 #include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
 
 #include "msm_drv.h"
 #include "msm_gem.h"
@@ -77,6 +78,21 @@ static void put_pages(struct drm_gem_object *obj)
        }
 }
 
+struct page **msm_gem_get_pages(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct page **p;
+       mutex_lock(&dev->struct_mutex);
+       p = get_pages(obj);
+       mutex_unlock(&dev->struct_mutex);
+       return p;
+}
+
+void msm_gem_put_pages(struct drm_gem_object *obj)
+{
+       /* when we start tracking the pin count, then do something here */
+}
+
 int msm_gem_mmap_obj(struct drm_gem_object *obj,
                struct vm_area_struct *vma)
 {
@@ -162,6 +178,11 @@ out:
        case 0:
        case -ERESTARTSYS:
        case -EINTR:
+       case -EBUSY:
+               /*
+                * EBUSY is ok: this just means that another thread
+                * already did the job.
+                */
                return VM_FAULT_NOPAGE;
        case -ENOMEM:
                return VM_FAULT_OOM;
@@ -293,7 +314,17 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
 
 int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova)
 {
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
        int ret;
+
+       /* this is safe right now because we don't unmap until the
+        * bo is deleted:
+        */
+       if (msm_obj->domain[id].iova) {
+               *iova = msm_obj->domain[id].iova;
+               return 0;
+       }
+
        mutex_lock(&obj->dev->struct_mutex);
        ret = msm_gem_get_iova_locked(obj, id, iova);
        mutex_unlock(&obj->dev->struct_mutex);
@@ -363,8 +394,11 @@ void *msm_gem_vaddr(struct drm_gem_object *obj)
        return ret;
 }
 
-int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
-               struct work_struct *work)
+/* setup callback for when bo is no longer busy..
+ * TODO probably want to differentiate read vs write..
+ */
+int msm_gem_queue_inactive_cb(struct drm_gem_object *obj,
+               struct msm_fence_cb *cb)
 {
        struct drm_device *dev = obj->dev;
        struct msm_drm_private *priv = dev->dev_private;
@@ -372,12 +406,13 @@ int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
        int ret = 0;
 
        mutex_lock(&dev->struct_mutex);
-       if (!list_empty(&work->entry)) {
+       if (!list_empty(&cb->work.entry)) {
                ret = -EINVAL;
        } else if (is_active(msm_obj)) {
-               list_add_tail(&work->entry, &msm_obj->inactive_work);
+               cb->fence = max(msm_obj->read_fence, msm_obj->write_fence);
+               list_add_tail(&cb->work.entry, &priv->fence_cbs);
        } else {
-               queue_work(priv->wq, work);
+               queue_work(priv->wq, &cb->work);
        }
        mutex_unlock(&dev->struct_mutex);
 
@@ -410,16 +445,6 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj)
        msm_obj->write_fence = 0;
        list_del_init(&msm_obj->mm_list);
        list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
-
-       while (!list_empty(&msm_obj->inactive_work)) {
-               struct work_struct *work;
-
-               work = list_first_entry(&msm_obj->inactive_work,
-                               struct work_struct, entry);
-
-               list_del_init(&work->entry);
-               queue_work(priv->wq, work);
-       }
 }
 
 int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
@@ -510,10 +535,21 @@ void msm_gem_free_object(struct drm_gem_object *obj)
 
        drm_gem_free_mmap_offset(obj);
 
-       if (msm_obj->vaddr)
-               vunmap(msm_obj->vaddr);
+       if (obj->import_attach) {
+               if (msm_obj->vaddr)
+                       dma_buf_vunmap(obj->import_attach->dmabuf, msm_obj->vaddr);
 
-       put_pages(obj);
+               /* Don't drop the pages for imported dmabuf, as they are not
+                * ours, just free the array we allocated:
+                */
+               if (msm_obj->pages)
+                       drm_free_large(msm_obj->pages);
+
+       } else {
+               if (msm_obj->vaddr)
+                       vunmap(msm_obj->vaddr);
+               put_pages(obj);
+       }
 
        if (msm_obj->resv == &msm_obj->_resv)
                reservation_object_fini(msm_obj->resv);
@@ -549,17 +585,12 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
        return ret;
 }
 
-struct drm_gem_object *msm_gem_new(struct drm_device *dev,
-               uint32_t size, uint32_t flags)
+static int msm_gem_new_impl(struct drm_device *dev,
+               uint32_t size, uint32_t flags,
+               struct drm_gem_object **obj)
 {
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_gem_object *msm_obj;
-       struct drm_gem_object *obj = NULL;
-       int ret;
-
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
-       size = PAGE_ALIGN(size);
 
        switch (flags & MSM_BO_CACHE_MASK) {
        case MSM_BO_UNCACHED:
@@ -569,21 +600,12 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
        default:
                dev_err(dev->dev, "invalid cache flag: %x\n",
                                (flags & MSM_BO_CACHE_MASK));
-               ret = -EINVAL;
-               goto fail;
+               return -EINVAL;
        }
 
        msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL);
-       if (!msm_obj) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       obj = &msm_obj->base;
-
-       ret = drm_gem_object_init(dev, obj, size);
-       if (ret)
-               goto fail;
+       if (!msm_obj)
+               return -ENOMEM;
 
        msm_obj->flags = flags;
 
@@ -591,9 +613,69 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
        reservation_object_init(msm_obj->resv);
 
        INIT_LIST_HEAD(&msm_obj->submit_entry);
-       INIT_LIST_HEAD(&msm_obj->inactive_work);
        list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
 
+       *obj = &msm_obj->base;
+
+       return 0;
+}
+
+struct drm_gem_object *msm_gem_new(struct drm_device *dev,
+               uint32_t size, uint32_t flags)
+{
+       struct drm_gem_object *obj;
+       int ret;
+
+       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+       size = PAGE_ALIGN(size);
+
+       ret = msm_gem_new_impl(dev, size, flags, &obj);
+       if (ret)
+               goto fail;
+
+       ret = drm_gem_object_init(dev, obj, size);
+       if (ret)
+               goto fail;
+
+       return obj;
+
+fail:
+       if (obj)
+               drm_gem_object_unreference_unlocked(obj);
+
+       return ERR_PTR(ret);
+}
+
+struct drm_gem_object *msm_gem_import(struct drm_device *dev,
+               uint32_t size, struct sg_table *sgt)
+{
+       struct msm_gem_object *msm_obj;
+       struct drm_gem_object *obj;
+       int ret, npages;
+
+       size = PAGE_ALIGN(size);
+
+       ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj);
+       if (ret)
+               goto fail;
+
+       drm_gem_private_object_init(dev, obj, size);
+
+       npages = size / PAGE_SIZE;
+
+       msm_obj = to_msm_bo(obj);
+       msm_obj->sgt = sgt;
+       msm_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
+       if (!msm_obj->pages) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages, NULL, npages);
+       if (ret)
+               goto fail;
+
        return obj;
 
 fail:
index 0676f32..f4f23a5 100644 (file)
@@ -45,9 +45,6 @@ struct msm_gem_object {
         */
        struct list_head submit_entry;
 
-       /* work defered until bo is inactive: */
-       struct list_head inactive_work;
-
        struct page **pages;
        struct sg_table *sgt;
        void *vaddr;
diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c
new file mode 100644 (file)
index 0000000..d48f9fc
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "msm_drv.h"
+#include "msm_gem.h"
+
+
+struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       BUG_ON(!msm_obj->sgt);  /* should have already pinned! */
+       return msm_obj->sgt;
+}
+
+void *msm_gem_prime_vmap(struct drm_gem_object *obj)
+{
+       return msm_gem_vaddr(obj);
+}
+
+void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+       /* TODO msm_gem_vunmap() */
+}
+
+struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
+               size_t size, struct sg_table *sg)
+{
+       return msm_gem_import(dev, size, sg);
+}
+
+int msm_gem_prime_pin(struct drm_gem_object *obj)
+{
+       if (!obj->import_attach)
+               msm_gem_get_pages(obj);
+       return 0;
+}
+
+void msm_gem_prime_unpin(struct drm_gem_object *obj)
+{
+       if (!obj->import_attach)
+               msm_gem_put_pages(obj);
+}
index 3bab937..4583d61 100644 (file)
@@ -268,6 +268,8 @@ static void retire_worker(struct work_struct *work)
        struct drm_device *dev = gpu->dev;
        uint32_t fence = gpu->funcs->last_fence(gpu);
 
+       msm_update_fence(gpu->dev, fence);
+
        mutex_lock(&dev->struct_mutex);
 
        while (!list_empty(&gpu->active_list)) {
@@ -287,8 +289,6 @@ static void retire_worker(struct work_struct *work)
                }
        }
 
-       msm_update_fence(gpu->dev, fence);
-
        mutex_unlock(&dev->struct_mutex);
 }
 
index d939a1d..edcf801 100644 (file)
@@ -28,7 +28,9 @@ nouveau-y += core/subdev/bar/nv50.o
 nouveau-y += core/subdev/bar/nvc0.o
 nouveau-y += core/subdev/bios/base.o
 nouveau-y += core/subdev/bios/bit.o
+nouveau-y += core/subdev/bios/boost.o
 nouveau-y += core/subdev/bios/conn.o
+nouveau-y += core/subdev/bios/cstep.o
 nouveau-y += core/subdev/bios/dcb.o
 nouveau-y += core/subdev/bios/disp.o
 nouveau-y += core/subdev/bios/dp.o
@@ -39,17 +41,26 @@ nouveau-y += core/subdev/bios/init.o
 nouveau-y += core/subdev/bios/mxm.o
 nouveau-y += core/subdev/bios/perf.o
 nouveau-y += core/subdev/bios/pll.o
+nouveau-y += core/subdev/bios/rammap.o
+nouveau-y += core/subdev/bios/timing.o
 nouveau-y += core/subdev/bios/therm.o
+nouveau-y += core/subdev/bios/vmap.o
+nouveau-y += core/subdev/bios/volt.o
 nouveau-y += core/subdev/bios/xpio.o
+nouveau-y += core/subdev/bus/hwsq.o
 nouveau-y += core/subdev/bus/nv04.o
 nouveau-y += core/subdev/bus/nv31.o
 nouveau-y += core/subdev/bus/nv50.o
+nouveau-y += core/subdev/bus/nv94.o
 nouveau-y += core/subdev/bus/nvc0.o
+nouveau-y += core/subdev/clock/base.o
 nouveau-y += core/subdev/clock/nv04.o
 nouveau-y += core/subdev/clock/nv40.o
 nouveau-y += core/subdev/clock/nv50.o
+nouveau-y += core/subdev/clock/nv84.o
 nouveau-y += core/subdev/clock/nva3.o
 nouveau-y += core/subdev/clock/nvc0.o
+nouveau-y += core/subdev/clock/nve0.o
 nouveau-y += core/subdev/clock/pllnv04.o
 nouveau-y += core/subdev/clock/pllnva3.o
 nouveau-y += core/subdev/devinit/base.o
@@ -78,7 +89,12 @@ nouveau-y += core/subdev/fb/nv47.o
 nouveau-y += core/subdev/fb/nv49.o
 nouveau-y += core/subdev/fb/nv4e.o
 nouveau-y += core/subdev/fb/nv50.o
+nouveau-y += core/subdev/fb/nv84.o
+nouveau-y += core/subdev/fb/nva3.o
+nouveau-y += core/subdev/fb/nvaa.o
+nouveau-y += core/subdev/fb/nvaf.o
 nouveau-y += core/subdev/fb/nvc0.o
+nouveau-y += core/subdev/fb/nve0.o
 nouveau-y += core/subdev/fb/ramnv04.o
 nouveau-y += core/subdev/fb/ramnv10.o
 nouveau-y += core/subdev/fb/ramnv1a.o
@@ -89,7 +105,12 @@ nouveau-y += core/subdev/fb/ramnv44.o
 nouveau-y += core/subdev/fb/ramnv49.o
 nouveau-y += core/subdev/fb/ramnv4e.o
 nouveau-y += core/subdev/fb/ramnv50.o
+nouveau-y += core/subdev/fb/ramnva3.o
+nouveau-y += core/subdev/fb/ramnvaa.o
 nouveau-y += core/subdev/fb/ramnvc0.o
+nouveau-y += core/subdev/fb/ramnve0.o
+nouveau-y += core/subdev/fb/sddr3.o
+nouveau-y += core/subdev/fb/gddr5.o
 nouveau-y += core/subdev/gpio/base.o
 nouveau-y += core/subdev/gpio/nv10.o
 nouveau-y += core/subdev/gpio/nv50.o
@@ -113,13 +134,22 @@ nouveau-y += core/subdev/instmem/nv50.o
 nouveau-y += core/subdev/ltcg/nvc0.o
 nouveau-y += core/subdev/mc/base.o
 nouveau-y += core/subdev/mc/nv04.o
+nouveau-y += core/subdev/mc/nv40.o
 nouveau-y += core/subdev/mc/nv44.o
 nouveau-y += core/subdev/mc/nv50.o
+nouveau-y += core/subdev/mc/nv94.o
 nouveau-y += core/subdev/mc/nv98.o
 nouveau-y += core/subdev/mc/nvc0.o
+nouveau-y += core/subdev/mc/nvc3.o
 nouveau-y += core/subdev/mxm/base.o
 nouveau-y += core/subdev/mxm/mxms.o
 nouveau-y += core/subdev/mxm/nv50.o
+nouveau-y += core/subdev/pwr/base.o
+nouveau-y += core/subdev/pwr/memx.o
+nouveau-y += core/subdev/pwr/nva3.o
+nouveau-y += core/subdev/pwr/nvc0.o
+nouveau-y += core/subdev/pwr/nvd0.o
+nouveau-y += core/subdev/pwr/nv108.o
 nouveau-y += core/subdev/therm/base.o
 nouveau-y += core/subdev/therm/fan.o
 nouveau-y += core/subdev/therm/fannil.o
@@ -140,6 +170,9 @@ nouveau-y += core/subdev/vm/nv41.o
 nouveau-y += core/subdev/vm/nv44.o
 nouveau-y += core/subdev/vm/nv50.o
 nouveau-y += core/subdev/vm/nvc0.o
+nouveau-y += core/subdev/volt/base.o
+nouveau-y += core/subdev/volt/gpio.o
+nouveau-y += core/subdev/volt/nv40.o
 
 nouveau-y += core/engine/falcon.o
 nouveau-y += core/engine/xtensa.o
@@ -158,6 +191,7 @@ nouveau-y += core/engine/copy/nve0.o
 nouveau-y += core/engine/crypt/nv84.o
 nouveau-y += core/engine/crypt/nv98.o
 nouveau-y += core/engine/device/base.o
+nouveau-y += core/engine/device/ctrl.o
 nouveau-y += core/engine/device/nv04.o
 nouveau-y += core/engine/device/nv10.o
 nouveau-y += core/engine/device/nv20.o
@@ -227,8 +261,18 @@ nouveau-y += core/engine/graph/nve4.o
 nouveau-y += core/engine/graph/nvf0.o
 nouveau-y += core/engine/mpeg/nv31.o
 nouveau-y += core/engine/mpeg/nv40.o
+nouveau-y += core/engine/mpeg/nv44.o
 nouveau-y += core/engine/mpeg/nv50.o
 nouveau-y += core/engine/mpeg/nv84.o
+nouveau-y += core/engine/perfmon/base.o
+nouveau-y += core/engine/perfmon/daemon.o
+nouveau-y += core/engine/perfmon/nv40.o
+nouveau-y += core/engine/perfmon/nv50.o
+nouveau-y += core/engine/perfmon/nv84.o
+nouveau-y += core/engine/perfmon/nva3.o
+nouveau-y += core/engine/perfmon/nvc0.o
+nouveau-y += core/engine/perfmon/nve0.o
+nouveau-y += core/engine/perfmon/nvf0.o
 nouveau-y += core/engine/ppp/nv98.o
 nouveau-y += core/engine/ppp/nvc0.o
 nouveau-y += core/engine/software/nv04.o
@@ -260,9 +304,7 @@ include $(src)/dispnv04/Makefile
 nouveau-y += nv50_display.o
 
 # drm/pm
-nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o
-nouveau-y += nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o
-nouveau-y += nouveau_mem.o
+nouveau-y += nouveau_hwmon.o nouveau_sysfs.o
 
 # other random bits
 nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
index 7eb81c1..3f3c765 100644 (file)
 #include <core/os.h>
 #include <core/event.h>
 
-static void
-nouveau_event_put_locked(struct nouveau_event *event, int index,
-                        struct nouveau_eventh *handler)
+void
+nouveau_event_put(struct nouveau_eventh *handler)
 {
-       if (!--event->index[index].refs) {
-               if (event->disable)
-                       event->disable(event, index);
+       struct nouveau_event *event = handler->event;
+       unsigned long flags;
+       if (__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags)) {
+               spin_lock_irqsave(&event->refs_lock, flags);
+               if (!--event->index[handler->index].refs) {
+                       if (event->disable)
+                               event->disable(event, handler->index);
+               }
+               spin_unlock_irqrestore(&event->refs_lock, flags);
        }
-       list_del(&handler->head);
 }
 
 void
-nouveau_event_put(struct nouveau_event *event, int index,
-                 struct nouveau_eventh *handler)
+nouveau_event_get(struct nouveau_eventh *handler)
 {
+       struct nouveau_event *event = handler->event;
        unsigned long flags;
+       if (!__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) {
+               spin_lock_irqsave(&event->refs_lock, flags);
+               if (!event->index[handler->index].refs++) {
+                       if (event->enable)
+                               event->enable(event, handler->index);
+               }
+               spin_unlock_irqrestore(&event->refs_lock, flags);
+       }
+}
 
-       spin_lock_irqsave(&event->lock, flags);
-       if (index < event->index_nr)
-               nouveau_event_put_locked(event, index, handler);
-       spin_unlock_irqrestore(&event->lock, flags);
+static void
+nouveau_event_fini(struct nouveau_eventh *handler)
+{
+       struct nouveau_event *event = handler->event;
+       unsigned long flags;
+       nouveau_event_put(handler);
+       spin_lock_irqsave(&event->list_lock, flags);
+       list_del(&handler->head);
+       spin_unlock_irqrestore(&event->list_lock, flags);
 }
 
-void
-nouveau_event_get(struct nouveau_event *event, int index,
-                 struct nouveau_eventh *handler)
+static int
+nouveau_event_init(struct nouveau_event *event, int index,
+                  int (*func)(void *, int), void *priv,
+                  struct nouveau_eventh *handler)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&event->lock, flags);
-       if (index < event->index_nr) {
-               list_add(&handler->head, &event->index[index].list);
-               if (!event->index[index].refs++) {
-                       if (event->enable)
-                               event->enable(event, index);
-               }
+       if (index >= event->index_nr)
+               return -EINVAL;
+
+       handler->event = event;
+       handler->flags = 0;
+       handler->index = index;
+       handler->func = func;
+       handler->priv = priv;
+
+       spin_lock_irqsave(&event->list_lock, flags);
+       list_add_tail(&handler->head, &event->index[index].list);
+       spin_unlock_irqrestore(&event->list_lock, flags);
+       return 0;
+}
+
+int
+nouveau_event_new(struct nouveau_event *event, int index,
+                 int (*func)(void *, int), void *priv,
+                 struct nouveau_eventh **phandler)
+{
+       struct nouveau_eventh *handler;
+       int ret = -ENOMEM;
+
+       handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL);
+       if (handler) {
+               ret = nouveau_event_init(event, index, func, priv, handler);
+               if (ret)
+                       kfree(handler);
        }
-       spin_unlock_irqrestore(&event->lock, flags);
+
+       return ret;
+}
+
+void
+nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref)
+{
+       BUG_ON(handler != NULL);
+       if (*ref) {
+               nouveau_event_fini(*ref);
+               kfree(*ref);
+       }
+       *ref = handler;
 }
 
 void
 nouveau_event_trigger(struct nouveau_event *event, int index)
 {
-       struct nouveau_eventh *handler, *temp;
+       struct nouveau_eventh *handler;
        unsigned long flags;
 
-       if (index >= event->index_nr)
+       if (WARN_ON(index >= event->index_nr))
                return;
 
-       spin_lock_irqsave(&event->lock, flags);
-       list_for_each_entry_safe(handler, temp, &event->index[index].list, head) {
-               if (handler->func(handler, index) == NVKM_EVENT_DROP) {
-                       nouveau_event_put_locked(event, index, handler);
-               }
+       spin_lock_irqsave(&event->list_lock, flags);
+       list_for_each_entry(handler, &event->index[index].list, head) {
+               if (test_bit(NVKM_EVENT_ENABLE, &handler->flags) &&
+                   handler->func(handler->priv, index) == NVKM_EVENT_DROP)
+                       nouveau_event_put(handler);
        }
-       spin_unlock_irqrestore(&event->lock, flags);
+       spin_unlock_irqrestore(&event->list_lock, flags);
 }
 
 void
@@ -102,7 +154,8 @@ nouveau_event_create(int index_nr, struct nouveau_event **pevent)
        if (!event)
                return -ENOMEM;
 
-       spin_lock_init(&event->lock);
+       spin_lock_init(&event->list_lock);
+       spin_lock_init(&event->refs_lock);
        for (i = 0; i < index_nr; i++)
                INIT_LIST_HEAD(&event->index[i].list);
        event->index_nr = index_nr;
index 62a432e..9f6fcc5 100644 (file)
 #include <core/option.h>
 #include <core/debug.h>
 
-/* compares unterminated string 'str' with zero-terminated string 'cmp' */
-static inline int
-strncasecmpz(const char *str, const char *cmp, size_t len)
-{
-       if (strlen(cmp) != len)
-               return len;
-       return strncasecmp(str, cmp, len);
-}
-
 const char *
 nouveau_stropt(const char *optstr, const char *opt, int *arglen)
 {
@@ -105,7 +96,7 @@ nouveau_dbgopt(const char *optstr, const char *sub)
                                else if (!strncasecmpz(optstr, "warn", len))
                                        level = NV_DBG_WARN;
                                else if (!strncasecmpz(optstr, "info", len))
-                                       level = NV_DBG_INFO;
+                                       level = NV_DBG_INFO_NORMAL;
                                else if (!strncasecmpz(optstr, "debug", len))
                                        level = NV_DBG_DEBUG;
                                else if (!strncasecmpz(optstr, "trace", len))
index 52fb2aa..03e0060 100644 (file)
 #include <core/subdev.h>
 #include <core/printk.h>
 
-int nv_printk_suspend_level = NV_DBG_DEBUG;
+int nv_info_debug_level = NV_DBG_INFO_NORMAL;
 
 void
-nv_printk_(struct nouveau_object *object, const char *pfx, int level,
-          const char *fmt, ...)
+nv_printk_(struct nouveau_object *object, int level, const char *fmt, ...)
 {
        static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' };
+       const char *pfx;
        char mfmt[256];
        va_list args;
 
+       switch (level) {
+       case NV_DBG_FATAL:
+               pfx = KERN_CRIT;
+               break;
+       case NV_DBG_ERROR:
+               pfx = KERN_ERR;
+               break;
+       case NV_DBG_WARN:
+               pfx = KERN_WARNING;
+               break;
+       case NV_DBG_INFO_NORMAL:
+               pfx = KERN_INFO;
+               break;
+       case NV_DBG_DEBUG:
+       case NV_DBG_PARANOIA:
+       case NV_DBG_TRACE:
+       case NV_DBG_SPAM:
+       default:
+               pfx = KERN_DEBUG;
+               break;
+       }
+
        if (object && !nv_iclass(object, NV_CLIENT_CLASS)) {
                struct nouveau_object *device = object;
                struct nouveau_object *subdev = object;
@@ -74,20 +96,3 @@ nv_printk_(struct nouveau_object *object, const char *pfx, int level,
        vprintk(mfmt, args);
        va_end(args);
 }
-
-#define CONV_LEVEL(x) case NV_DBG_##x: return NV_PRINTK_##x
-
-const char *nv_printk_level_to_pfx(int level)
-{
-       switch (level) {
-       CONV_LEVEL(FATAL);
-       CONV_LEVEL(ERROR);
-       CONV_LEVEL(WARN);
-       CONV_LEVEL(INFO);
-       CONV_LEVEL(DEBUG);
-       CONV_LEVEL(PARANOIA);
-       CONV_LEVEL(TRACE);
-       CONV_LEVEL(SPAM);
-       }
-       return NV_PRINTK_DEBUG;
-}
index 4c72571..9135b25 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <core/class.h>
 
-#include <engine/device.h>
+#include "priv.h"
 
 static DEFINE_MUTEX(nv_devices_mutex);
 static LIST_HEAD(nv_devices);
@@ -75,7 +75,9 @@ static const u64 disable_map[] = {
        [NVDEV_SUBDEV_BAR]      = NV_DEVICE_DISABLE_CORE,
        [NVDEV_SUBDEV_VOLT]     = NV_DEVICE_DISABLE_CORE,
        [NVDEV_SUBDEV_THERM]    = NV_DEVICE_DISABLE_CORE,
+       [NVDEV_SUBDEV_PWR]      = NV_DEVICE_DISABLE_CORE,
        [NVDEV_ENGINE_DMAOBJ]   = NV_DEVICE_DISABLE_CORE,
+       [NVDEV_ENGINE_PERFMON]  = NV_DEVICE_DISABLE_CORE,
        [NVDEV_ENGINE_FIFO]     = NV_DEVICE_DISABLE_FIFO,
        [NVDEV_ENGINE_SW]       = NV_DEVICE_DISABLE_FIFO,
        [NVDEV_ENGINE_GR]       = NV_DEVICE_DISABLE_GRAPH,
@@ -87,7 +89,7 @@ static const u64 disable_map[] = {
        [NVDEV_ENGINE_PPP]      = NV_DEVICE_DISABLE_PPP,
        [NVDEV_ENGINE_COPY0]    = NV_DEVICE_DISABLE_COPY0,
        [NVDEV_ENGINE_COPY1]    = NV_DEVICE_DISABLE_COPY1,
-       [NVDEV_ENGINE_UNK1C1]   = NV_DEVICE_DISABLE_UNK1C1,
+       [NVDEV_ENGINE_VIC]      = NV_DEVICE_DISABLE_VIC,
        [NVDEV_ENGINE_VENC]     = NV_DEVICE_DISABLE_VENC,
        [NVDEV_ENGINE_DISP]     = NV_DEVICE_DISABLE_DISP,
        [NVDEV_SUBDEV_NR]       = 0,
@@ -119,10 +121,12 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
                        return -ENODEV;
        }
 
-       ret = nouveau_parent_create(parent, nv_object(device), oclass, 0, NULL,
+       ret = nouveau_parent_create(parent, nv_object(device), oclass, 0,
+                                   nouveau_control_oclass,
                                    (1ULL << NVDEV_ENGINE_DMAOBJ) |
                                    (1ULL << NVDEV_ENGINE_FIFO) |
-                                   (1ULL << NVDEV_ENGINE_DISP), &devobj);
+                                   (1ULL << NVDEV_ENGINE_DISP) |
+                                   (1ULL << NVDEV_ENGINE_PERFMON), &devobj);
        *pobject = nv_object(devobj);
        if (ret)
                return ret;
@@ -158,22 +162,29 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
                iounmap(map);
 
                /* determine chipset and derive architecture from it */
-               if ((boot0 & 0x0f000000) > 0) {
-                       device->chipset = (boot0 & 0xff00000) >> 20;
-                       switch (device->chipset & 0xf0) {
-                       case 0x10: device->card_type = NV_10; break;
-                       case 0x20: device->card_type = NV_20; break;
-                       case 0x30: device->card_type = NV_30; break;
-                       case 0x40:
-                       case 0x60: device->card_type = NV_40; break;
-                       case 0x50:
-                       case 0x80:
-                       case 0x90:
-                       case 0xa0: device->card_type = NV_50; break;
-                       case 0xc0: device->card_type = NV_C0; break;
-                       case 0xd0: device->card_type = NV_D0; break;
-                       case 0xe0:
-                       case 0xf0: device->card_type = NV_E0; break;
+               if ((boot0 & 0x1f000000) > 0) {
+                       device->chipset = (boot0 & 0x1ff00000) >> 20;
+                       switch (device->chipset & 0x1f0) {
+                       case 0x010: {
+                               if (0x461 & (1 << (device->chipset & 0xf)))
+                                       device->card_type = NV_10;
+                               else
+                                       device->card_type = NV_11;
+                               break;
+                       }
+                       case 0x020: device->card_type = NV_20; break;
+                       case 0x030: device->card_type = NV_30; break;
+                       case 0x040:
+                       case 0x060: device->card_type = NV_40; break;
+                       case 0x050:
+                       case 0x080:
+                       case 0x090:
+                       case 0x0a0: device->card_type = NV_50; break;
+                       case 0x0c0: device->card_type = NV_C0; break;
+                       case 0x0d0: device->card_type = NV_D0; break;
+                       case 0x0e0:
+                       case 0x0f0:
+                       case 0x100: device->card_type = NV_E0; break;
                        default:
                                break;
                        }
@@ -188,7 +199,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
 
                switch (device->card_type) {
                case NV_04: ret = nv04_identify(device); break;
-               case NV_10: ret = nv10_identify(device); break;
+               case NV_10:
+               case NV_11: ret = nv10_identify(device); break;
                case NV_20: ret = nv20_identify(device); break;
                case NV_30: ret = nv30_identify(device); break;
                case NV_40: ret = nv40_identify(device); break;
@@ -212,7 +224,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
                nv_info(device, "Family : NV%02X\n", device->card_type);
 
                /* determine frequency of timing crystal */
-               if ( device->chipset < 0x17 ||
+               if ( device->card_type <= NV_10 || device->chipset < 0x17 ||
                    (device->chipset >= 0x20 && device->chipset < 0x25))
                        strap &= 0x00000040;
                else
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c
new file mode 100644 (file)
index 0000000..4b69bf5
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include <core/object.h>
+#include <core/class.h>
+
+#include <subdev/clock.h>
+
+#include "priv.h"
+
+static int
+nouveau_control_mthd_pstate_info(struct nouveau_object *object, u32 mthd,
+                               void *data, u32 size)
+{
+       struct nouveau_clock *clk = nouveau_clock(object);
+       struct nv_control_pstate_info *args = data;
+
+       if (size < sizeof(*args))
+               return -EINVAL;
+
+       if (clk) {
+               args->count  = clk->state_nr;
+               args->ustate = clk->ustate;
+               args->pstate = clk->pstate;
+       } else {
+               args->count  = 0;
+               args->ustate = NV_CONTROL_PSTATE_INFO_USTATE_DISABLE;
+               args->pstate = NV_CONTROL_PSTATE_INFO_PSTATE_UNKNOWN;
+       }
+
+       return 0;
+}
+
+static int
+nouveau_control_mthd_pstate_attr(struct nouveau_object *object, u32 mthd,
+                               void *data, u32 size)
+{
+       struct nouveau_clock *clk = nouveau_clock(object);
+       struct nv_control_pstate_attr *args = data;
+       struct nouveau_clocks *domain;
+       struct nouveau_pstate *pstate;
+       struct nouveau_cstate *cstate;
+       int i = 0, j = -1;
+       u32 lo, hi;
+
+       if ((size < sizeof(*args)) || !clk ||
+           (args->state >= 0 && args->state >= clk->state_nr))
+               return -EINVAL;
+       domain = clk->domains;
+
+       while (domain->name != nv_clk_src_max) {
+               if (domain->mname && ++j == args->index)
+                       break;
+               domain++;
+       }
+
+       if (domain->name == nv_clk_src_max)
+               return -EINVAL;
+
+       if (args->state != NV_CONTROL_PSTATE_ATTR_STATE_CURRENT) {
+               list_for_each_entry(pstate, &clk->states, head) {
+                       if (i++ == args->state)
+                               break;
+               }
+
+               lo = pstate->base.domain[domain->name];
+               hi = lo;
+               list_for_each_entry(cstate, &pstate->list, head) {
+                       lo = min(lo, cstate->domain[domain->name]);
+                       hi = max(hi, cstate->domain[domain->name]);
+               }
+
+               args->state = pstate->pstate;
+       } else {
+               lo = max(clk->read(clk, domain->name), 0);
+               hi = lo;
+       }
+
+       snprintf(args->name, sizeof(args->name), "%s", domain->mname);
+       snprintf(args->unit, sizeof(args->unit), "MHz");
+       args->min = lo / domain->mdiv;
+       args->max = hi / domain->mdiv;
+
+       args->index = 0;
+       while ((++domain)->name != nv_clk_src_max) {
+               if (domain->mname) {
+                       args->index = ++j;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int
+nouveau_control_mthd_pstate_user(struct nouveau_object *object, u32 mthd,
+                               void *data, u32 size)
+{
+       struct nouveau_clock *clk = nouveau_clock(object);
+       struct nv_control_pstate_user *args = data;
+
+       if (size < sizeof(*args) || !clk)
+               return -EINVAL;
+
+       return nouveau_clock_ustate(clk, args->state);
+}
+
+struct nouveau_oclass
+nouveau_control_oclass[] = {
+       { .handle = NV_CONTROL_CLASS,
+         .ofuncs = &nouveau_object_ofuncs,
+         .omthds = (struct nouveau_omthds[]) {
+                 { NV_CONTROL_PSTATE_INFO,
+                   NV_CONTROL_PSTATE_INFO, nouveau_control_mthd_pstate_info },
+                 { NV_CONTROL_PSTATE_ATTR,
+                   NV_CONTROL_PSTATE_ATTR, nouveau_control_mthd_pstate_attr },
+                 { NV_CONTROL_PSTATE_USER,
+                   NV_CONTROL_PSTATE_USER, nouveau_control_mthd_pstate_user },
+                 {},
+         },
+       },
+       {}
+};
index a0284cf..dbd2dde 100644 (file)
@@ -50,15 +50,15 @@ nv04_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv04_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv04_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv04_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv04_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv04_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv04_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv04_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv04_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -68,15 +68,15 @@ nv04_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv05_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv04_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv04_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv04_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv04_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv04_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv04_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv04_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
index 1b7809a..6e03dd6 100644 (file)
@@ -52,10 +52,10 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -69,15 +69,15 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv10_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -88,15 +88,15 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv10_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -107,15 +107,15 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv1a_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv1a_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv10_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -126,15 +126,15 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv10_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -145,15 +145,15 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -164,15 +164,15 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv1a_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv1a_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -183,15 +183,15 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
index 12a4005..dcde53b 100644 (file)
@@ -53,15 +53,15 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv20_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv20_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv20_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -72,15 +72,15 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv25_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv25_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -91,15 +91,15 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv25_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv25_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -110,15 +110,15 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv25_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv2a_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
index cef0f1e..7b8662e 100644 (file)
@@ -53,15 +53,15 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv30_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv30_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv30_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -72,15 +72,15 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv04_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv35_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv35_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv35_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
                break;
@@ -91,15 +91,15 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv30_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv30_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv30_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
@@ -111,15 +111,15 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv36_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv36_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv35_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
@@ -131,15 +131,15 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv34_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
index 1719cb0..c8c41e9 100644 (file)
@@ -35,6 +35,7 @@
 #include <subdev/fb.h>
 #include <subdev/instmem.h>
 #include <subdev/vm.h>
+#include <subdev/volt.h>
 
 #include <engine/device.h>
 #include <engine/dmaobj.h>
@@ -43,6 +44,7 @@
 #include <engine/graph.h>
 #include <engine/mpeg.h>
 #include <engine/disp.h>
+#include <engine/perfmon.h>
 
 int
 nv40_identify(struct nouveau_device *device)
@@ -56,18 +58,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv40_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x41:
                device->cname = "NV41";
@@ -77,18 +81,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv41_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x42:
                device->cname = "NV42";
@@ -98,18 +104,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv41_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x43:
                device->cname = "NV43";
@@ -119,18 +127,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv41_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x45:
                device->cname = "NV45";
@@ -140,18 +150,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv40_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x47:
                device->cname = "G70";
@@ -161,18 +173,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv47_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv47_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x49:
                device->cname = "G71";
@@ -182,18 +196,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv49_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv49_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x4b:
                device->cname = "G73";
@@ -203,18 +219,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv04_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv49_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv49_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x44:
                device->cname = "NV44";
@@ -224,18 +242,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv44_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv44_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv44_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x46:
                device->cname = "G72";
@@ -245,18 +265,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv44_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv46_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x4a:
                device->cname = "NV44A";
@@ -266,18 +288,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv44_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv44_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv44_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x4c:
                device->cname = "C61";
@@ -287,18 +311,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv44_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv46_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x4e:
                device->cname = "C51";
@@ -308,18 +334,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv44_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv4e_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv4e_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x63:
                device->cname = "C73";
@@ -329,18 +357,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv44_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv46_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x67:
                device->cname = "C67";
@@ -350,18 +380,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv44_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv46_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x68:
                device->cname = "C68";
@@ -371,18 +403,20 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv44_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv31_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv46_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+               device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        default:
                nv_fatal(device, "unknown Curie chipset\n");
index ffc18b8..db13982 100644 (file)
@@ -36,6 +36,8 @@
 #include <subdev/instmem.h>
 #include <subdev/vm.h>
 #include <subdev/bar.h>
+#include <subdev/pwr.h>
+#include <subdev/volt.h>
 
 #include <engine/device.h>
 #include <engine/dmaobj.h>
@@ -49,6 +51,7 @@
 #include <engine/ppp.h>
 #include <engine/copy.h>
 #include <engine/disp.h>
+#include <engine/perfmon.h>
 
 int
 nv50_identify(struct nouveau_device *device)
@@ -59,257 +62,277 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv50_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv50_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv50_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv50_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv50_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv50_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv50_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv50_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv50_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv50_perfmon_oclass;
                break;
        case 0x84:
                device->cname = "G84";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv50_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv50_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv50_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv84_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0x86:
                device->cname = "G86";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv50_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv50_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv50_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv84_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0x92:
                device->cname = "G92";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv50_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv50_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv50_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv84_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0x94:
                device->cname = "G94";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv94_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv50_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv50_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv94_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0x96:
                device->cname = "G96";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv94_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv50_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv50_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv94_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0x98:
                device->cname = "G98";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv94_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv50_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0xa0:
                device->cname = "G200";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv50_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv50_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0xaa:
                device->cname = "MCP77/MCP78";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv94_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv50_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvaa_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0xac:
                device->cname = "MCP79/MCP7A";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv94_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv50_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvaa_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0xa3:
                device->cname = "GT215";
@@ -320,16 +343,18 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nva3_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
@@ -337,6 +362,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
                break;
        case 0xa5:
                device->cname = "GT216";
@@ -347,22 +373,25 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nva3_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
                break;
        case 0xa8:
                device->cname = "GT218";
@@ -373,22 +402,25 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nva3_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
                break;
        case 0xaf:
                device->cname = "MCP89";
@@ -399,22 +431,25 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nv50_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvaf_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
                break;
        default:
                nv_fatal(device, "unknown Tesla chipset\n");
index 418f51f..606598f 100644 (file)
@@ -38,6 +38,8 @@
 #include <subdev/instmem.h>
 #include <subdev/vm.h>
 #include <subdev/bar.h>
+#include <subdev/pwr.h>
+#include <subdev/volt.h>
 
 #include <engine/device.h>
 #include <engine/dmaobj.h>
@@ -49,6 +51,7 @@
 #include <engine/ppp.h>
 #include <engine/copy.h>
 #include <engine/disp.h>
+#include <engine/perfmon.h>
 
 int
 nvc0_identify(struct nouveau_device *device)
@@ -63,18 +66,20 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvc0_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
@@ -82,6 +87,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xc4:
                device->cname = "GF104";
@@ -92,18 +98,20 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
@@ -111,6 +119,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xc3:
                device->cname = "GF106";
@@ -121,24 +130,27 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xce:
                device->cname = "GF114";
@@ -149,18 +161,20 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
@@ -168,6 +182,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xcf:
                device->cname = "GF116";
@@ -178,18 +193,20 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
@@ -197,6 +214,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xc1:
                device->cname = "GF108";
@@ -207,24 +225,27 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvc1_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xc8:
                device->cname = "GF110";
@@ -235,18 +256,20 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvc8_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
@@ -254,6 +277,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xd9:
                device->cname = "GF119";
@@ -264,24 +288,27 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvd9_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nvd0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xd7:
                device->cname = "GF117";
@@ -292,24 +319,25 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvd7_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nvd0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        default:
                nv_fatal(device, "unknown Fermi chipset\n");
index 7aca187..3900104 100644 (file)
@@ -38,6 +38,8 @@
 #include <subdev/instmem.h>
 #include <subdev/vm.h>
 #include <subdev/bar.h>
+#include <subdev/pwr.h>
+#include <subdev/volt.h>
 
 #include <engine/device.h>
 #include <engine/dmaobj.h>
@@ -49,6 +51,7 @@
 #include <engine/bsp.h>
 #include <engine/vp.h>
 #include <engine/ppp.h>
+#include <engine/perfmon.h>
 
 int
 nve0_identify(struct nouveau_device *device)
@@ -59,22 +62,24 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nvd0_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nve0_disp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
@@ -83,28 +88,31 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
                break;
        case 0xe7:
                device->cname = "GK107";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nvd0_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nve0_disp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
@@ -113,28 +121,31 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
                break;
        case 0xe6:
                device->cname = "GK106";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nvd0_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nve0_disp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
@@ -143,28 +154,31 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
                break;
        case 0xf0:
                device->cname = "GK110";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nvd0_i2c_oclass;
-               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
-               device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
-               device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
-               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvf0_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nvf0_disp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
@@ -174,6 +188,43 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_PERFMON] = &nvf0_perfmon_oclass;
+               break;
+       case 0x108:
+               device->cname = "GK208";
+               device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] = &nve0_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nvd0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
+               device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nv108_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+               device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  nvf0_graph_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DISP   ] = &nvf0_disp_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
+               device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
+               device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
+               device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
+               device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
+               device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
 #endif
                break;
        default:
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/priv.h b/drivers/gpu/drm/nouveau/core/engine/device/priv.h
new file mode 100644 (file)
index 0000000..035fd5b
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __NVKM_DEVICE_PRIV_H__
+#define __NVKM_DEVICE_PRIV_H__
+
+#include <engine/device.h>
+
+extern struct nouveau_oclass nouveau_control_oclass[];
+
+#endif
index 054d9cf..1bd4c63 100644 (file)
@@ -70,17 +70,10 @@ dp_set_link_config(struct dp_state *dp)
        };
        u32 lnkcmp;
        u8 sink[2];
+       int ret;
 
        DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
 
-       /* set desired link configuration on the sink */
-       sink[0] = dp->link_bw / 27000;
-       sink[1] = dp->link_nr;
-       if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
-               sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
-
-       nv_wraux(dp->aux, DPCD_LC00, sink, 2);
-
        /* set desired link configuration on the source */
        if ((lnkcmp = dp->info.lnkcmp)) {
                if (dp->version < 0x30) {
@@ -96,10 +89,22 @@ dp_set_link_config(struct dp_state *dp)
                nvbios_exec(&init);
        }
 
-       return dp->func->lnk_ctl(dp->disp, dp->outp, dp->head,
-                                dp->link_nr, dp->link_bw / 27000,
-                                dp->dpcd[DPCD_RC02] &
-                                         DPCD_RC02_ENHANCED_FRAME_CAP);
+       ret = dp->func->lnk_ctl(dp->disp, dp->outp, dp->head,
+                               dp->link_nr, dp->link_bw / 27000,
+                               dp->dpcd[DPCD_RC02] &
+                                        DPCD_RC02_ENHANCED_FRAME_CAP);
+       if (ret) {
+               ERR("lnk_ctl failed with %d\n", ret);
+               return ret;
+       }
+
+       /* set desired link configuration on the sink */
+       sink[0] = dp->link_bw / 27000;
+       sink[1] = dp->link_nr;
+       if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
+               sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
+
+       return nv_wraux(dp->aux, DPCD_LC00, sink, 2);
 }
 
 static void
@@ -294,8 +299,17 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
 
        ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd));
        if (ret) {
+               /* it's possible the display has been unplugged before we
+                * get here.  we still need to execute the full set of
+                * vbios scripts, and program the OR at a high enough
+                * frequency to satisfy the target mode.  failure to do
+                * so results at best in an UPDATE hanging, and at worst
+                * with PDISP running away to join the circus.
+                */
+               dp->dpcd[1] = link_bw[0] / 27000;
+               dp->dpcd[2] = 4;
+               dp->dpcd[3] = 0x00;
                ERR("failed to read DPCD\n");
-               return ret;
        }
 
        /* adjust required bandwidth for 8B/10B coding overhead */
@@ -308,7 +322,7 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
        while (*link_bw > (dp->dpcd[1] * 27000))
                link_bw++;
 
-       while (link_bw[0]) {
+       while ((ret = -EIO) && link_bw[0]) {
                /* find minimum required lane count at this link rate */
                dp->link_nr = dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT;
                while ((dp->link_nr >> 1) * link_bw[0] > datarate)
@@ -328,8 +342,10 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
                            !dp_link_train_eq(dp))
                                break;
                } else
-               if (ret >= 1) {
-                       /* dp_set_link_config() handled training */
+               if (ret) {
+                       /* dp_set_link_config() handled training, or
+                        * we failed to communicate with the sink.
+                        */
                        break;
                }
 
@@ -339,8 +355,10 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
 
        /* finish link training */
        dp_set_training_pattern(dp, 0);
+       if (ret < 0)
+               ERR("link training failed\n");
 
        /* execute post-train script from vbios */
        dp_link_train_fini(dp);
-       return true;
+       return (ret < 0) ? false : true;
 }
index 05e903f..a0bc8a8 100644 (file)
@@ -59,6 +59,7 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
        struct nv04_disp_priv *priv = (void *)subdev;
        u32 crtc0 = nv_rd32(priv, 0x600100);
        u32 crtc1 = nv_rd32(priv, 0x602100);
+       u32 pvideo;
 
        if (crtc0 & 0x00000001) {
                nouveau_event_trigger(priv->base.vblank, 0);
@@ -69,6 +70,14 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
                nouveau_event_trigger(priv->base.vblank, 1);
                nv_wr32(priv, 0x602100, 0x00000001);
        }
+
+       if (nv_device(priv)->chipset >= 0x10 &&
+           nv_device(priv)->chipset <= 0x40) {
+               pvideo = nv_rd32(priv, 0x8100);
+               if (pvideo & ~0x11)
+                       nv_info(priv, "PVIDEO intr: %08x\n", pvideo);
+               nv_wr32(priv, 0x8100, pvideo);
+       }
 }
 
 static int
index 52dd7a1..378a015 100644 (file)
@@ -541,6 +541,15 @@ nvd0_disp_base_init(struct nouveau_object *object)
        nv_wr32(priv, 0x6100a0, 0x00000000);
        nv_wr32(priv, 0x6100b0, 0x00000307);
 
+       /* disable underflow reporting, preventing an intermittent issue
+        * on some nve4 boards where the production vbios left this
+        * setting enabled by default.
+        *
+        * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt
+        */
+       for (i = 0; i < priv->head.nr; i++)
+               nv_mask(priv, 0x616308 + (i * 0x800), 0x00000111, 0x00000010);
+
        return 0;
 }
 
index 7ec4ee8..eea3ef5 100644 (file)
@@ -97,8 +97,9 @@ nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
 {
        struct nouveau_bios *bios = nouveau_bios(disp);
        struct nv50_disp_priv *priv = (void *)disp;
+       const u32 shift = nv94_sor_dp_lane_map(priv, lane);
        const u32 loff = nv94_sor_loff(outp);
-       u32 addr, shift = nv94_sor_dp_lane_map(priv, lane);
+       u32 addr, data[3];
        u8  ver, hdr, cnt, len;
        struct nvbios_dpout info;
        struct nvbios_dpcfg ocfg;
@@ -113,9 +114,12 @@ nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
        if (!addr)
                return -EINVAL;
 
-       nv_mask(priv, 0x61c118 + loff, 0x000000ff << shift, ocfg.drv << shift);
-       nv_mask(priv, 0x61c120 + loff, 0x000000ff << shift, ocfg.pre << shift);
-       nv_mask(priv, 0x61c130 + loff, 0x0000ff00, ocfg.unk << 8);
+       data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
+       data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
+       data[2] = nv_rd32(priv, 0x61c130 + loff) & ~(0x0000ff00);
+       nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.drv << shift));
+       nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pre << shift));
+       nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.unk << 8));
        return 0;
 }
 
index 9e1d435..d2df572 100644 (file)
@@ -93,8 +93,9 @@ nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
 {
        struct nouveau_bios *bios = nouveau_bios(disp);
        struct nv50_disp_priv *priv = (void *)disp;
+       const u32 shift = nvd0_sor_dp_lane_map(priv, lane);
        const u32 loff = nvd0_sor_loff(outp);
-       u32 addr, shift = nvd0_sor_dp_lane_map(priv, lane);
+       u32 addr, data[3];
        u8  ver, hdr, cnt, len;
        struct nvbios_dpout info;
        struct nvbios_dpcfg ocfg;
@@ -109,9 +110,12 @@ nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
        if (!addr)
                return -EINVAL;
 
-       nv_mask(priv, 0x61c118 + loff, 0x000000ff << shift, ocfg.drv << shift);
-       nv_mask(priv, 0x61c120 + loff, 0x000000ff << shift, ocfg.pre << shift);
-       nv_mask(priv, 0x61c130 + loff, 0x0000ff00, ocfg.unk << 8);
+       data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
+       data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
+       data[2] = nv_rd32(priv, 0x61c130 + loff) & ~(0x0000ff00);
+       nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.drv << shift));
+       nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pre << shift));
+       nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.unk << 8));
        nv_mask(priv, 0x61c13c + loff, 0x00000000, 0x00000000);
        return 0;
 }
index f877bd5..54f26cc 100644 (file)
@@ -632,8 +632,8 @@ nv04_fifo_init(struct nouveau_object *object)
        return 0;
 }
 
-struct nouveau_oclass
-nv04_fifo_oclass = {
+struct nouveau_oclass *
+nv04_fifo_oclass = &(struct nouveau_oclass) {
        .handle = NV_ENGINE(FIFO, 0x04),
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv04_fifo_ctor,
index 2c927c1..571a22a 100644 (file)
@@ -159,8 +159,8 @@ nv10_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nv10_fifo_oclass = {
+struct nouveau_oclass *
+nv10_fifo_oclass = &(struct nouveau_oclass) {
        .handle = NV_ENGINE(FIFO, 0x10),
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv10_fifo_ctor,
index a9cb51d..f257602 100644 (file)
@@ -196,8 +196,8 @@ nv17_fifo_init(struct nouveau_object *object)
        return 0;
 }
 
-struct nouveau_oclass
-nv17_fifo_oclass = {
+struct nouveau_oclass *
+nv17_fifo_oclass = &(struct nouveau_oclass) {
        .handle = NV_ENGINE(FIFO, 0x17),
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv17_fifo_ctor,
index 5c7433d..343487e 100644 (file)
@@ -337,8 +337,8 @@ nv40_fifo_init(struct nouveau_object *object)
        return 0;
 }
 
-struct nouveau_oclass
-nv40_fifo_oclass = {
+struct nouveau_oclass *
+nv40_fifo_oclass = &(struct nouveau_oclass) {
        .handle = NV_ENGINE(FIFO, 0x40),
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv40_fifo_ctor,
index 7e5dff5..5f55578 100644 (file)
@@ -502,8 +502,8 @@ nv50_fifo_init(struct nouveau_object *object)
        return 0;
 }
 
-struct nouveau_oclass
-nv50_fifo_oclass = {
+struct nouveau_oclass *
+nv50_fifo_oclass = &(struct nouveau_oclass) {
        .handle = NV_ENGINE(FIFO, 0x50),
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv50_fifo_ctor,
index 91a87cd..0908dc8 100644 (file)
@@ -144,7 +144,7 @@ nv84_fifo_object_attach(struct nouveau_object *parent,
        case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break;
        case NVDEV_ENGINE_VP    : context |= 0x00400000; break;
        case NVDEV_ENGINE_CRYPT :
-       case NVDEV_ENGINE_UNK1C1: context |= 0x00500000; break;
+       case NVDEV_ENGINE_VIC   : context |= 0x00500000; break;
        case NVDEV_ENGINE_BSP   : context |= 0x00600000; break;
        default:
                return -EINVAL;
@@ -180,7 +180,7 @@ nv84_fifo_chan_ctor_dma(struct nouveau_object *parent,
                                          (1ULL << NVDEV_ENGINE_BSP) |
                                          (1ULL << NVDEV_ENGINE_PPP) |
                                          (1ULL << NVDEV_ENGINE_COPY0) |
-                                         (1ULL << NVDEV_ENGINE_UNK1C1), &chan);
+                                         (1ULL << NVDEV_ENGINE_VIC), &chan);
        *pobject = nv_object(chan);
        if (ret)
                return ret;
@@ -243,7 +243,7 @@ nv84_fifo_chan_ctor_ind(struct nouveau_object *parent,
                                          (1ULL << NVDEV_ENGINE_BSP) |
                                          (1ULL << NVDEV_ENGINE_PPP) |
                                          (1ULL << NVDEV_ENGINE_COPY0) |
-                                         (1ULL << NVDEV_ENGINE_UNK1C1), &chan);
+                                         (1ULL << NVDEV_ENGINE_VIC), &chan);
        *pobject = nv_object(chan);
        if (ret)
                return ret;
@@ -435,8 +435,8 @@ nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nv84_fifo_oclass = {
+struct nouveau_oclass *
+nv84_fifo_oclass = &(struct nouveau_oclass) {
        .handle = NV_ENGINE(FIFO, 0x84),
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv84_fifo_ctor,
index ce92f28..e21453a 100644 (file)
@@ -720,8 +720,8 @@ nvc0_fifo_init(struct nouveau_object *object)
        return 0;
 }
 
-struct nouveau_oclass
-nvc0_fifo_oclass = {
+struct nouveau_oclass *
+nvc0_fifo_oclass = &(struct nouveau_oclass) {
        .handle = NV_ENGINE(FIFO, 0xc0),
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nvc0_fifo_ctor,
index 8e8121a..fcd449e 100644 (file)
@@ -675,8 +675,8 @@ nve0_fifo_init(struct nouveau_object *object)
        return 0;
 }
 
-struct nouveau_oclass
-nve0_fifo_oclass = {
+struct nouveau_oclass *
+nve0_fifo_oclass = &(struct nouveau_oclass) {
        .handle = NV_ENGINE(FIFO, 0xe0),
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nve0_fifo_ctor,
index e5be3ee..71b4283 100644 (file)
@@ -587,6 +587,7 @@ nvc1_grctx_init_unk58xx[] = {
        { 0x405870,   4, 0x04, 0x00000001 },
        { 0x405a00,   2, 0x04, 0x00000000 },
        { 0x405a18,   1, 0x04, 0x00000000 },
+       {}
 };
 
 static struct nvc0_graph_init
@@ -598,6 +599,7 @@ nvc1_grctx_init_rop[] = {
        { 0x408904,   1, 0x04, 0x62000001 },
        { 0x408908,   1, 0x04, 0x00c80929 },
        { 0x408980,   1, 0x04, 0x0000011d },
+       {}
 };
 
 static struct nvc0_graph_init
@@ -671,6 +673,7 @@ nvc1_grctx_init_gpc_0[] = {
        { 0x419000,   1, 0x04, 0x00000780 },
        { 0x419004,   2, 0x04, 0x00000000 },
        { 0x419014,   1, 0x04, 0x00000004 },
+       {}
 };
 
 static struct nvc0_graph_init
@@ -717,6 +720,7 @@ nvc1_grctx_init_tpc[] = {
        { 0x419e98,   1, 0x04, 0x00000000 },
        { 0x419ee0,   1, 0x04, 0x00011110 },
        { 0x419f30,  11, 0x04, 0x00000000 },
+       {}
 };
 
 void
index 438e784..c4740d5 100644 (file)
@@ -258,6 +258,7 @@ nvd7_grctx_init_hub[] = {
        nvc0_grctx_init_unk78xx,
        nvc0_grctx_init_unk80xx,
        nvd9_grctx_init_rop,
+       NULL
 };
 
 struct nvc0_graph_init *
index 818a475..a1102cb 100644 (file)
@@ -466,6 +466,7 @@ nvd9_grctx_init_hub[] = {
        nvc0_grctx_init_unk78xx,
        nvc0_grctx_init_unk80xx,
        nvd9_grctx_init_rop,
+       NULL
 };
 
 struct nvc0_graph_init *
index 23c143a..4532f7e 100644 (file)
@@ -945,7 +945,8 @@ nv10_graph_load_context(struct nv10_graph_chan *chan, int chid)
        for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
                nv_wr32(priv, nv10_graph_ctx_regs[i], chan->nv10[i]);
 
-       if (nv_device(priv)->chipset >= 0x17) {
+       if (nv_device(priv)->card_type >= NV_11 &&
+           nv_device(priv)->chipset >= 0x17) {
                for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
                        nv_wr32(priv, nv17_graph_ctx_regs[i], chan->nv17[i]);
        }
@@ -970,7 +971,8 @@ nv10_graph_unload_context(struct nv10_graph_chan *chan)
        for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
                chan->nv10[i] = nv_rd32(priv, nv10_graph_ctx_regs[i]);
 
-       if (nv_device(priv)->chipset >= 0x17) {
+       if (nv_device(priv)->card_type >= NV_11 &&
+           nv_device(priv)->chipset >= 0x17) {
                for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
                        chan->nv17[i] = nv_rd32(priv, nv17_graph_ctx_regs[i]);
        }
@@ -1052,7 +1054,8 @@ nv10_graph_context_ctor(struct nouveau_object *parent,
        NV_WRITE_CTX(0x00400e14, 0x00001000);
        NV_WRITE_CTX(0x00400e30, 0x00080008);
        NV_WRITE_CTX(0x00400e34, 0x00080008);
-       if (nv_device(priv)->chipset >= 0x17) {
+       if (nv_device(priv)->card_type >= NV_11 &&
+           nv_device(priv)->chipset >= 0x17) {
                /* is it really needed ??? */
                NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4,
                                        nv_rd32(priv, NV10_PGRAPH_DEBUG_4));
@@ -1231,7 +1234,7 @@ nv10_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                nv_engine(priv)->sclass = nv10_graph_sclass;
        else
        if (nv_device(priv)->chipset <  0x17 ||
-           nv_device(priv)->chipset == 0x1a)
+           nv_device(priv)->card_type < NV_11)
                nv_engine(priv)->sclass = nv15_graph_sclass;
        else
                nv_engine(priv)->sclass = nv17_graph_sclass;
@@ -1270,7 +1273,8 @@ nv10_graph_init(struct nouveau_object *object)
        nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
        nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31));
 
-       if (nv_device(priv)->chipset >= 0x17) {
+       if (nv_device(priv)->card_type >= NV_11 &&
+           nv_device(priv)->chipset >= 0x17) {
                nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000);
                nv_wr32(priv, 0x400a10, 0x03ff3fb6);
                nv_wr32(priv, 0x400838, 0x002f8684);
index 3f4f35c..434bb4b 100644 (file)
@@ -1138,7 +1138,7 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_subdev(priv)->unit = 0x18001000;
+       nv_subdev(priv)->unit = 0x08001000;
        nv_subdev(priv)->intr = nvc0_graph_intr;
 
        priv->base.units = nvc0_graph_units;
index c190043..7eb6d94 100644 (file)
 
 #include <engine/fifo.h>
 #include <engine/mpeg.h>
-#include <engine/graph/nv40.h>
-
-struct nv31_mpeg_priv {
-       struct nouveau_mpeg base;
-       atomic_t refcount;
-};
-
-struct nv31_mpeg_chan {
-       struct nouveau_object base;
-};
+#include <engine/mpeg/nv31.h>
 
 /*******************************************************************************
  * MPEG object classes
@@ -89,18 +80,18 @@ nv31_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len)
 
        if (mthd == 0x0190) {
                /* DMA_CMD */
-               nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+               nv_mask(priv, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0);
                nv_wr32(priv, 0x00b334, base);
                nv_wr32(priv, 0x00b324, size);
        } else
        if (mthd == 0x01a0) {
                /* DMA_DATA */
-               nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+               nv_mask(priv, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0);
                nv_wr32(priv, 0x00b360, base);
                nv_wr32(priv, 0x00b364, size);
        } else {
                /* DMA_IMAGE, VRAM only */
-               if (dma0 & 0x000c0000)
+               if (dma0 & 0x00030000)
                        return -EINVAL;
 
                nv_wr32(priv, 0x00b370, base);
@@ -110,7 +101,7 @@ nv31_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len)
        return 0;
 }
 
-static struct nouveau_ofuncs
+struct nouveau_ofuncs
 nv31_mpeg_ofuncs = {
        .ctor = nv31_mpeg_object_ctor,
        .dtor = _nouveau_gpuobj_dtor,
@@ -146,16 +137,23 @@ nv31_mpeg_context_ctor(struct nouveau_object *parent,
 {
        struct nv31_mpeg_priv *priv = (void *)engine;
        struct nv31_mpeg_chan *chan;
+       unsigned long flags;
        int ret;
 
-       if (!atomic_add_unless(&priv->refcount, 1, 1))
-               return -EBUSY;
-
        ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
        *pobject = nv_object(chan);
        if (ret)
                return ret;
 
+       spin_lock_irqsave(&nv_engine(priv)->lock, flags);
+       if (priv->chan) {
+               spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
+               nouveau_object_destroy(&chan->base);
+               *pobject = NULL;
+               return -EBUSY;
+       }
+       priv->chan = chan;
+       spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
        return 0;
 }
 
@@ -164,11 +162,15 @@ nv31_mpeg_context_dtor(struct nouveau_object *object)
 {
        struct nv31_mpeg_priv *priv = (void *)object->engine;
        struct nv31_mpeg_chan *chan = (void *)object;
-       atomic_dec(&priv->refcount);
+       unsigned long flags;
+
+       spin_lock_irqsave(&nv_engine(priv)->lock, flags);
+       priv->chan = NULL;
+       spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
        nouveau_object_destroy(&chan->base);
 }
 
-static struct nouveau_oclass
+struct nouveau_oclass
 nv31_mpeg_cclass = {
        .handle = NV_ENGCTX(MPEG, 0x31),
        .ofuncs = &(struct nouveau_ofuncs) {
@@ -197,21 +199,19 @@ nv31_mpeg_tile_prog(struct nouveau_engine *engine, int i)
 void
 nv31_mpeg_intr(struct nouveau_subdev *subdev)
 {
+       struct nv31_mpeg_priv *priv = (void *)subdev;
        struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
-       struct nouveau_engine *engine = nv_engine(subdev);
-       struct nouveau_object *engctx;
        struct nouveau_handle *handle;
-       struct nv31_mpeg_priv *priv = (void *)subdev;
-       u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff;
+       struct nouveau_object *engctx;
        u32 stat = nv_rd32(priv, 0x00b100);
        u32 type = nv_rd32(priv, 0x00b230);
        u32 mthd = nv_rd32(priv, 0x00b234);
        u32 data = nv_rd32(priv, 0x00b238);
        u32 show = stat;
-       int chid;
+       unsigned long flags;
 
-       engctx = nouveau_engctx_get(engine, inst);
-       chid   = pfifo->chid(pfifo, engctx);
+       spin_lock_irqsave(&nv_engine(priv)->lock, flags);
+       engctx = nv_object(priv->chan);
 
        if (stat & 0x01000000) {
                /* happens on initial binding of the object */
@@ -220,7 +220,7 @@ nv31_mpeg_intr(struct nouveau_subdev *subdev)
                        show &= ~0x01000000;
                }
 
-               if (type == 0x00000010) {
+               if (type == 0x00000010 && engctx) {
                        handle = nouveau_handle_get_class(engctx, 0x3174);
                        if (handle && !nv_call(handle->object, mthd, data))
                                show &= ~0x01000000;
@@ -232,13 +232,12 @@ nv31_mpeg_intr(struct nouveau_subdev *subdev)
        nv_wr32(priv, 0x00b230, 0x00000001);
 
        if (show) {
-               nv_error(priv,
-                        "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                        chid, inst << 4, nouveau_client_name(engctx), stat,
-                        type, mthd, data);
+               nv_error(priv, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                        pfifo->chid(pfifo, engctx),
+                        nouveau_client_name(engctx), stat, type, mthd, data);
        }
 
-       nouveau_engctx_put(engctx);
+       spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
 }
 
 static int
@@ -284,10 +283,7 @@ nv31_mpeg_init(struct nouveau_object *object)
        /* PMPEG init */
        nv_wr32(priv, 0x00b32c, 0x00000000);
        nv_wr32(priv, 0x00b314, 0x00000100);
-       if (nv_device(priv)->chipset >= 0x40 && nv44_graph_class(priv))
-               nv_wr32(priv, 0x00b220, 0x00000044);
-       else
-               nv_wr32(priv, 0x00b220, 0x00000031);
+       nv_wr32(priv, 0x00b220, 0x00000031);
        nv_wr32(priv, 0x00b300, 0x02001ec1);
        nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h
new file mode 100644 (file)
index 0000000..d08629d
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __NV31_MPEG_H__
+#define __NV31_MPEG_H__
+
+#include <engine/mpeg.h>
+
+struct nv31_mpeg_chan {
+       struct nouveau_object base;
+};
+
+struct nv31_mpeg_priv {
+       struct nouveau_mpeg base;
+       struct nv31_mpeg_chan *chan;
+};
+
+#endif
index dd61960..d4e7ec0 100644 (file)
 #include <subdev/instmem.h>
 
 #include <engine/mpeg.h>
-#include <engine/graph/nv40.h>
-
-struct nv40_mpeg_priv {
-       struct nouveau_mpeg base;
-};
-
-struct nv40_mpeg_chan {
-       struct nouveau_mpeg_chan base;
-};
+#include <engine/mpeg/nv31.h>
 
 /*******************************************************************************
- * PMPEG context
+ * MPEG object classes
  ******************************************************************************/
 
 static int
-nv40_mpeg_context_ctor(struct nouveau_object *parent,
-                      struct nouveau_object *engine,
-                      struct nouveau_oclass *oclass, void *data, u32 size,
-                      struct nouveau_object **pobject)
+nv40_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len)
 {
-       struct nv40_mpeg_chan *chan;
-       int ret;
-
-       ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL,
-                                         264 * 4, 16,
-                                         NVOBJ_FLAG_ZERO_ALLOC, &chan);
-       *pobject = nv_object(chan);
-       if (ret)
-               return ret;
+       struct nouveau_instmem *imem = nouveau_instmem(object);
+       struct nv31_mpeg_priv *priv = (void *)object->engine;
+       u32 inst = *(u32 *)arg << 4;
+       u32 dma0 = nv_ro32(imem, inst + 0);
+       u32 dma1 = nv_ro32(imem, inst + 4);
+       u32 dma2 = nv_ro32(imem, inst + 8);
+       u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+       u32 size = dma1 + 1;
+
+       /* only allow linear DMA objects */
+       if (!(dma0 & 0x00002000))
+               return -EINVAL;
+
+       if (mthd == 0x0190) {
+               /* DMA_CMD */
+               nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+               nv_wr32(priv, 0x00b334, base);
+               nv_wr32(priv, 0x00b324, size);
+       } else
+       if (mthd == 0x01a0) {
+               /* DMA_DATA */
+               nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+               nv_wr32(priv, 0x00b360, base);
+               nv_wr32(priv, 0x00b364, size);
+       } else {
+               /* DMA_IMAGE, VRAM only */
+               if (dma0 & 0x00030000)
+                       return -EINVAL;
+
+               nv_wr32(priv, 0x00b370, base);
+               nv_wr32(priv, 0x00b374, size);
+       }
 
-       nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
        return 0;
 }
 
-static int
-nv40_mpeg_context_fini(struct nouveau_object *object, bool suspend)
-{
-
-       struct nv40_mpeg_priv *priv = (void *)object->engine;
-       struct nv40_mpeg_chan *chan = (void *)object;
-       u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4;
-
-       nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000);
-       if (nv_rd32(priv, 0x00b318) == inst)
-               nv_mask(priv, 0x00b318, 0x80000000, 0x00000000);
-       nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
-       return 0;
-}
+static struct nouveau_omthds
+nv40_mpeg_omthds[] = {
+       { 0x0190, 0x0190, nv40_mpeg_mthd_dma },
+       { 0x01a0, 0x01a0, nv40_mpeg_mthd_dma },
+       { 0x01b0, 0x01b0, nv40_mpeg_mthd_dma },
+       {}
+};
 
-static struct nouveau_oclass
-nv40_mpeg_cclass = {
-       .handle = NV_ENGCTX(MPEG, 0x40),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv40_mpeg_context_ctor,
-               .dtor = _nouveau_mpeg_context_dtor,
-               .init = _nouveau_mpeg_context_init,
-               .fini = nv40_mpeg_context_fini,
-               .rd32 = _nouveau_mpeg_context_rd32,
-               .wr32 = _nouveau_mpeg_context_wr32,
-       },
+struct nouveau_oclass
+nv40_mpeg_sclass[] = {
+       { 0x3174, &nv31_mpeg_ofuncs, nv40_mpeg_omthds },
+       {}
 };
 
 /*******************************************************************************
@@ -100,7 +97,7 @@ nv40_mpeg_cclass = {
 static void
 nv40_mpeg_intr(struct nouveau_subdev *subdev)
 {
-       struct nv40_mpeg_priv *priv = (void *)subdev;
+       struct nv31_mpeg_priv *priv = (void *)subdev;
        u32 stat;
 
        if ((stat = nv_rd32(priv, 0x00b100)))
@@ -117,7 +114,7 @@ nv40_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
               struct nouveau_object **pobject)
 {
-       struct nv40_mpeg_priv *priv;
+       struct nv31_mpeg_priv *priv;
        int ret;
 
        ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
@@ -127,8 +124,8 @@ nv40_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        nv_subdev(priv)->unit = 0x00000002;
        nv_subdev(priv)->intr = nv40_mpeg_intr;
-       nv_engine(priv)->cclass = &nv40_mpeg_cclass;
-       nv_engine(priv)->sclass = nv31_mpeg_sclass;
+       nv_engine(priv)->cclass = &nv31_mpeg_cclass;
+       nv_engine(priv)->sclass = nv40_mpeg_sclass;
        nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
        return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c
new file mode 100644 (file)
index 0000000..3d8c213
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <core/os.h>
+#include <core/class.h>
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/handle.h>
+
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+#include <subdev/instmem.h>
+
+#include <engine/fifo.h>
+#include <engine/mpeg.h>
+
+struct nv44_mpeg_priv {
+       struct nouveau_mpeg base;
+};
+
+struct nv44_mpeg_chan {
+       struct nouveau_mpeg_chan base;
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+static int
+nv44_mpeg_context_ctor(struct nouveau_object *parent,
+                      struct nouveau_object *engine,
+                      struct nouveau_oclass *oclass, void *data, u32 size,
+                      struct nouveau_object **pobject)
+{
+       struct nv44_mpeg_chan *chan;
+       int ret;
+
+       ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL,
+                                         264 * 4, 16,
+                                         NVOBJ_FLAG_ZERO_ALLOC, &chan);
+       *pobject = nv_object(chan);
+       if (ret)
+               return ret;
+
+       nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
+       return 0;
+}
+
+static int
+nv44_mpeg_context_fini(struct nouveau_object *object, bool suspend)
+{
+
+       struct nv44_mpeg_priv *priv = (void *)object->engine;
+       struct nv44_mpeg_chan *chan = (void *)object;
+       u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4;
+
+       nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000);
+       if (nv_rd32(priv, 0x00b318) == inst)
+               nv_mask(priv, 0x00b318, 0x80000000, 0x00000000);
+       nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
+       return 0;
+}
+
+static struct nouveau_oclass
+nv44_mpeg_cclass = {
+       .handle = NV_ENGCTX(MPEG, 0x44),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv44_mpeg_context_ctor,
+               .dtor = _nouveau_mpeg_context_dtor,
+               .init = _nouveau_mpeg_context_init,
+               .fini = nv44_mpeg_context_fini,
+               .rd32 = _nouveau_mpeg_context_rd32,
+               .wr32 = _nouveau_mpeg_context_wr32,
+       },
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv44_mpeg_intr(struct nouveau_subdev *subdev)
+{
+       struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
+       struct nouveau_engine *engine = nv_engine(subdev);
+       struct nouveau_object *engctx;
+       struct nouveau_handle *handle;
+       struct nv44_mpeg_priv *priv = (void *)subdev;
+       u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff;
+       u32 stat = nv_rd32(priv, 0x00b100);
+       u32 type = nv_rd32(priv, 0x00b230);
+       u32 mthd = nv_rd32(priv, 0x00b234);
+       u32 data = nv_rd32(priv, 0x00b238);
+       u32 show = stat;
+       int chid;
+
+       engctx = nouveau_engctx_get(engine, inst);
+       chid   = pfifo->chid(pfifo, engctx);
+
+       if (stat & 0x01000000) {
+               /* happens on initial binding of the object */
+               if (type == 0x00000020 && mthd == 0x0000) {
+                       nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
+                       show &= ~0x01000000;
+               }
+
+               if (type == 0x00000010) {
+                       handle = nouveau_handle_get_class(engctx, 0x3174);
+                       if (handle && !nv_call(handle->object, mthd, data))
+                               show &= ~0x01000000;
+                       nouveau_handle_put(handle);
+               }
+       }
+
+       nv_wr32(priv, 0x00b100, stat);
+       nv_wr32(priv, 0x00b230, 0x00000001);
+
+       if (show) {
+               nv_error(priv,
+                        "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                        chid, inst << 4, nouveau_client_name(engctx), stat,
+                        type, mthd, data);
+       }
+
+       nouveau_engctx_put(engctx);
+}
+
+static void
+nv44_mpeg_me_intr(struct nouveau_subdev *subdev)
+{
+       struct nv44_mpeg_priv *priv = (void *)subdev;
+       u32 stat;
+
+       if ((stat = nv_rd32(priv, 0x00b100)))
+               nv44_mpeg_intr(subdev);
+
+       if ((stat = nv_rd32(priv, 0x00b800))) {
+               nv_error(priv, "PMSRCH 0x%08x\n", stat);
+               nv_wr32(priv, 0x00b800, stat);
+       }
+}
+
+static int
+nv44_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct nv44_mpeg_priv *priv;
+       int ret;
+
+       ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       nv_subdev(priv)->unit = 0x00000002;
+       nv_subdev(priv)->intr = nv44_mpeg_me_intr;
+       nv_engine(priv)->cclass = &nv44_mpeg_cclass;
+       nv_engine(priv)->sclass = nv40_mpeg_sclass;
+       nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
+       return 0;
+}
+
+struct nouveau_oclass
+nv44_mpeg_oclass = {
+       .handle = NV_ENGINE(MPEG, 0x44),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv44_mpeg_ctor,
+               .dtor = _nouveau_mpeg_dtor,
+               .init = nv31_mpeg_init,
+               .fini = _nouveau_mpeg_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c
new file mode 100644 (file)
index 0000000..e9c5e51
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <core/option.h>
+#include <core/class.h>
+
+#include <subdev/clock.h>
+
+#include "priv.h"
+
+#define QUAD_MASK 0x0f
+#define QUAD_FREE 0x01
+
+static struct nouveau_perfsig *
+nouveau_perfsig_find_(struct nouveau_perfdom *dom, const char *name, u32 size)
+{
+       char path[64];
+       int i;
+
+       if (name[0] != '/') {
+               for (i = 0; i < dom->signal_nr; i++) {
+                       if ( dom->signal[i].name &&
+                           !strncmp(name, dom->signal[i].name, size))
+                               return &dom->signal[i];
+               }
+       } else {
+               for (i = 0; i < dom->signal_nr; i++) {
+                       snprintf(path, sizeof(path), "/%s/%02x", dom->name, i);
+                       if (!strncmp(name, path, size))
+                               return &dom->signal[i];
+               }
+       }
+
+       return NULL;
+}
+
+struct nouveau_perfsig *
+nouveau_perfsig_find(struct nouveau_perfmon *ppm, const char *name, u32 size,
+                    struct nouveau_perfdom **pdom)
+{
+       struct nouveau_perfdom *dom = *pdom;
+       struct nouveau_perfsig *sig;
+
+       if (dom == NULL) {
+               list_for_each_entry(dom, &ppm->domains, head) {
+                       sig = nouveau_perfsig_find_(dom, name, size);
+                       if (sig) {
+                               *pdom = dom;
+                               return sig;
+                       }
+               }
+
+               return NULL;
+       }
+
+       return nouveau_perfsig_find_(dom, name, size);
+}
+
+struct nouveau_perfctr *
+nouveau_perfsig_wrap(struct nouveau_perfmon *ppm, const char *name,
+                    struct nouveau_perfdom **pdom)
+{
+       struct nouveau_perfsig *sig;
+       struct nouveau_perfctr *ctr;
+
+       sig = nouveau_perfsig_find(ppm, name, strlen(name), pdom);
+       if (!sig)
+               return NULL;
+
+       ctr = kzalloc(sizeof(*ctr), GFP_KERNEL);
+       if (ctr) {
+               ctr->signal[0] = sig;
+               ctr->logic_op = 0xaaaa;
+       }
+
+       return ctr;
+}
+
+/*******************************************************************************
+ * Perfmon object classes
+ ******************************************************************************/
+static int
+nouveau_perfctr_query(struct nouveau_object *object, u32 mthd,
+                     void *data, u32 size)
+{
+       struct nouveau_device *device = nv_device(object);
+       struct nouveau_perfmon *ppm = (void *)object->engine;
+       struct nouveau_perfdom *dom = NULL, *chk;
+       struct nv_perfctr_query *args = data;
+       const bool all = nouveau_boolopt(device->cfgopt, "NvPmShowAll", false);
+       const bool raw = nouveau_boolopt(device->cfgopt, "NvPmUnnamed", all);
+       const char *name;
+       int tmp = 0, di, si;
+       char path[64];
+
+       if (size < sizeof(*args))
+               return -EINVAL;
+
+       di = (args->iter & 0xff000000) >> 24;
+       si = (args->iter & 0x00ffffff) - 1;
+
+       list_for_each_entry(chk, &ppm->domains, head) {
+               if (tmp++ == di) {
+                       dom = chk;
+                       break;
+               }
+       }
+
+       if (dom == NULL || si >= (int)dom->signal_nr)
+               return -EINVAL;
+
+       if (si >= 0) {
+               if (raw || !(name = dom->signal[si].name)) {
+                       snprintf(path, sizeof(path), "/%s/%02x", dom->name, si);
+                       name = path;
+               }
+
+               if (args->name)
+                       strncpy(args->name, name, args->size);
+               args->size = strlen(name) + 1;
+       }
+
+       do {
+               while (++si < dom->signal_nr) {
+                       if (all || dom->signal[si].name) {
+                               args->iter = (di << 24) | ++si;
+                               return 0;
+                       }
+               }
+               si = -1;
+               di = di + 1;
+               dom = list_entry(dom->head.next, typeof(*dom), head);
+       } while (&dom->head != &ppm->domains);
+
+       args->iter = 0xffffffff;
+       return 0;
+}
+
+static int
+nouveau_perfctr_sample(struct nouveau_object *object, u32 mthd,
+                      void *data, u32 size)
+{
+       struct nouveau_perfmon *ppm = (void *)object->engine;
+       struct nouveau_perfctr *ctr, *tmp;
+       struct nouveau_perfdom *dom;
+       struct nv_perfctr_sample *args = data;
+
+       if (size < sizeof(*args))
+               return -EINVAL;
+       ppm->sequence++;
+
+       list_for_each_entry(dom, &ppm->domains, head) {
+               /* sample previous batch of counters */
+               if (dom->quad != QUAD_MASK) {
+                       dom->func->next(ppm, dom);
+                       tmp = NULL;
+                       while (!list_empty(&dom->list)) {
+                               ctr = list_first_entry(&dom->list,
+                                                       typeof(*ctr), head);
+                               if (ctr->slot < 0) break;
+                               if ( tmp && tmp == ctr) break;
+                               if (!tmp) tmp = ctr;
+                               dom->func->read(ppm, dom, ctr);
+                               ctr->slot  = -1;
+                               list_move_tail(&ctr->head, &dom->list);
+                       }
+               }
+
+               dom->quad = QUAD_MASK;
+
+               /* setup next batch of counters for sampling */
+               list_for_each_entry(ctr, &dom->list, head) {
+                       ctr->slot = ffs(dom->quad) - 1;
+                       if (ctr->slot < 0)
+                               break;
+                       dom->quad &= ~(QUAD_FREE << ctr->slot);
+                       dom->func->init(ppm, dom, ctr);
+               }
+
+               if (dom->quad != QUAD_MASK)
+                       dom->func->next(ppm, dom);
+       }
+
+       return 0;
+}
+
+static int
+nouveau_perfctr_read(struct nouveau_object *object, u32 mthd,
+                    void *data, u32 size)
+{
+       struct nouveau_perfctr *ctr = (void *)object;
+       struct nv_perfctr_read *args = data;
+
+       if (size < sizeof(*args))
+               return -EINVAL;
+       if (!ctr->clk)
+               return -EAGAIN;
+
+       args->clk = ctr->clk;
+       args->ctr = ctr->ctr;
+       return 0;
+}
+
+static void
+nouveau_perfctr_dtor(struct nouveau_object *object)
+{
+       struct nouveau_perfctr *ctr = (void *)object;
+       if (ctr->head.next)
+               list_del(&ctr->head);
+       nouveau_object_destroy(&ctr->base);
+}
+
+static int
+nouveau_perfctr_ctor(struct nouveau_object *parent,
+                    struct nouveau_object *engine,
+                    struct nouveau_oclass *oclass, void *data, u32 size,
+                    struct nouveau_object **pobject)
+{
+       struct nouveau_perfmon *ppm = (void *)engine;
+       struct nouveau_perfdom *dom = NULL;
+       struct nouveau_perfsig *sig[4] = {};
+       struct nouveau_perfctr *ctr;
+       struct nv_perfctr_class *args = data;
+       int ret, i;
+
+       if (size < sizeof(*args))
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(args->signal) && args->signal[i].name; i++) {
+               sig[i] = nouveau_perfsig_find(ppm, args->signal[i].name,
+                                             args->signal[i].size, &dom);
+               if (!sig[i])
+                       return -EINVAL;
+       }
+
+       ret = nouveau_object_create(parent, engine, oclass, 0, &ctr);
+       *pobject = nv_object(ctr);
+       if (ret)
+               return ret;
+
+       ctr->slot = -1;
+       ctr->logic_op = args->logic_op;
+       ctr->signal[0] = sig[0];
+       ctr->signal[1] = sig[1];
+       ctr->signal[2] = sig[2];
+       ctr->signal[3] = sig[3];
+       if (dom)
+               list_add_tail(&ctr->head, &dom->list);
+       return 0;
+}
+
+static struct nouveau_ofuncs
+nouveau_perfctr_ofuncs = {
+       .ctor = nouveau_perfctr_ctor,
+       .dtor = nouveau_perfctr_dtor,
+       .init = nouveau_object_init,
+       .fini = nouveau_object_fini,
+};
+
+static struct nouveau_omthds
+nouveau_perfctr_omthds[] = {
+       { NV_PERFCTR_QUERY, NV_PERFCTR_QUERY, nouveau_perfctr_query },
+       { NV_PERFCTR_SAMPLE, NV_PERFCTR_SAMPLE, nouveau_perfctr_sample },
+       { NV_PERFCTR_READ, NV_PERFCTR_READ, nouveau_perfctr_read },
+       {}
+};
+
+struct nouveau_oclass
+nouveau_perfmon_sclass[] = {
+       { .handle = NV_PERFCTR_CLASS,
+         .ofuncs = &nouveau_perfctr_ofuncs,
+         .omthds =  nouveau_perfctr_omthds,
+       },
+       {},
+};
+
+/*******************************************************************************
+ * PPM context
+ ******************************************************************************/
+static void
+nouveau_perfctx_dtor(struct nouveau_object *object)
+{
+       struct nouveau_perfmon *ppm = (void *)object->engine;
+       mutex_lock(&nv_subdev(ppm)->mutex);
+       ppm->context = NULL;
+       mutex_unlock(&nv_subdev(ppm)->mutex);
+}
+
+static int
+nouveau_perfctx_ctor(struct nouveau_object *parent,
+                    struct nouveau_object *engine,
+                    struct nouveau_oclass *oclass, void *data, u32 size,
+                    struct nouveau_object **pobject)
+{
+       struct nouveau_perfmon *ppm = (void *)engine;
+       struct nouveau_perfctx *ctx;
+       int ret;
+
+       ret = nouveau_engctx_create(parent, engine, oclass, NULL,
+                                   0, 0, 0, &ctx);
+       *pobject = nv_object(ctx);
+       if (ret)
+               return ret;
+
+       mutex_lock(&nv_subdev(ppm)->mutex);
+       if (ppm->context == NULL)
+               ppm->context = ctx;
+       mutex_unlock(&nv_subdev(ppm)->mutex);
+
+       if (ctx != ppm->context)
+               return -EBUSY;
+
+       return 0;
+}
+
+struct nouveau_oclass
+nouveau_perfmon_cclass = {
+       .handle = NV_ENGCTX(PERFMON, 0x00),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nouveau_perfctx_ctor,
+               .dtor = nouveau_perfctx_dtor,
+               .init = _nouveau_engctx_init,
+               .fini = _nouveau_engctx_fini,
+       },
+};
+
+/*******************************************************************************
+ * PPM engine/subdev functions
+ ******************************************************************************/
+int
+nouveau_perfdom_new(struct nouveau_perfmon *ppm, const char *name, u32 mask,
+                   u32 base, u32 size_unit, u32 size_domain,
+                   const struct nouveau_specdom *spec)
+{
+       const struct nouveau_specdom *sdom;
+       const struct nouveau_specsig *ssig;
+       struct nouveau_perfdom *dom;
+       int i;
+
+       for (i = 0; i == 0 || mask; i++) {
+               u32 addr = base + (i * size_unit);
+               if (i && !(mask & (1 << i)))
+                       continue;
+
+               sdom = spec;
+               while (sdom->signal_nr) {
+                       dom = kzalloc(sizeof(*dom) + sdom->signal_nr *
+                                     sizeof(*dom->signal), GFP_KERNEL);
+                       if (!dom)
+                               return -ENOMEM;
+
+                       if (mask) {
+                               snprintf(dom->name, sizeof(dom->name),
+                                        "%s/%02x/%02x", name, i,
+                                        (int)(sdom - spec));
+                       } else {
+                               snprintf(dom->name, sizeof(dom->name),
+                                        "%s/%02x", name, (int)(sdom - spec));
+                       }
+
+                       list_add_tail(&dom->head, &ppm->domains);
+                       INIT_LIST_HEAD(&dom->list);
+                       dom->func = sdom->func;
+                       dom->addr = addr;
+                       dom->quad = QUAD_MASK;
+                       dom->signal_nr = sdom->signal_nr;
+
+                       ssig = (sdom++)->signal;
+                       while (ssig->name) {
+                               dom->signal[ssig->signal].name = ssig->name;
+                               ssig++;
+                       }
+
+                       addr += size_domain;
+               }
+
+               mask &= ~(1 << i);
+       }
+
+       return 0;
+}
+
+int
+_nouveau_perfmon_fini(struct nouveau_object *object, bool suspend)
+{
+       struct nouveau_perfmon *ppm = (void *)object;
+       return nouveau_engine_fini(&ppm->base, suspend);
+}
+
+int
+_nouveau_perfmon_init(struct nouveau_object *object)
+{
+       struct nouveau_perfmon *ppm = (void *)object;
+       return nouveau_engine_init(&ppm->base);
+}
+
+void
+_nouveau_perfmon_dtor(struct nouveau_object *object)
+{
+       struct nouveau_perfmon *ppm = (void *)object;
+       struct nouveau_perfdom *dom, *tmp;
+
+       list_for_each_entry_safe(dom, tmp, &ppm->domains, head) {
+               list_del(&dom->head);
+               kfree(dom);
+       }
+
+       nouveau_engine_destroy(&ppm->base);
+}
+
+int
+nouveau_perfmon_create_(struct nouveau_object *parent,
+                       struct nouveau_object *engine,
+                       struct nouveau_oclass *oclass,
+                       int length, void **pobject)
+{
+       struct nouveau_perfmon *ppm;
+       int ret;
+
+       ret = nouveau_engine_create_(parent, engine, oclass, true, "PPM",
+                                    "perfmon", length, pobject);
+       ppm = *pobject;
+       if (ret)
+               return ret;
+
+       INIT_LIST_HEAD(&ppm->domains);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c
new file mode 100644 (file)
index 0000000..50696cc
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static void
+pwr_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
+                struct nouveau_perfctr *ctr)
+{
+       u32 mask = 0x00000000;
+       u32 ctrl = 0x00000001;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ctr->signal) && ctr->signal[i]; i++)
+               mask |= 1 << (ctr->signal[i] - dom->signal);
+
+       nv_wr32(ppm, 0x10a504 + (ctr->slot * 0x10), mask);
+       nv_wr32(ppm, 0x10a50c + (ctr->slot * 0x10), ctrl);
+       nv_wr32(ppm, 0x10a50c + (ppm->last * 0x10), 0x00000003);
+}
+
+static void
+pwr_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
+                struct nouveau_perfctr *ctr)
+{
+       ctr->ctr = ppm->pwr[ctr->slot];
+       ctr->clk = ppm->pwr[ppm->last];
+}
+
+static void
+pwr_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom)
+{
+       int i;
+
+       for (i = 0; i <= ppm->last; i++) {
+               ppm->pwr[i] = nv_rd32(ppm, 0x10a508 + (i * 0x10));
+               nv_wr32(ppm, 0x10a508 + (i * 0x10), 0x80000000);
+       }
+}
+
+static const struct nouveau_funcdom
+pwr_perfctr_func = {
+       .init = pwr_perfctr_init,
+       .read = pwr_perfctr_read,
+       .next = pwr_perfctr_next,
+};
+
+const struct nouveau_specdom
+nva3_perfmon_pwr[] = {
+       { 0x20, (const struct nouveau_specsig[]) {
+                       { 0x00, "pwr_gr_idle" },
+                       { 0x04, "pwr_bsp_idle" },
+                       { 0x05, "pwr_vp_idle" },
+                       { 0x06, "pwr_ppp_idle" },
+                       { 0x13, "pwr_ce0_idle" },
+                       {}
+               }, &pwr_perfctr_func },
+       {}
+};
+
+const struct nouveau_specdom
+nvc0_perfmon_pwr[] = {
+       { 0x20, (const struct nouveau_specsig[]) {
+                       { 0x00, "pwr_gr_idle" },
+                       { 0x04, "pwr_bsp_idle" },
+                       { 0x05, "pwr_vp_idle" },
+                       { 0x06, "pwr_ppp_idle" },
+                       { 0x13, "pwr_ce0_idle" },
+                       { 0x14, "pwr_ce1_idle" },
+                       {}
+               }, &pwr_perfctr_func },
+       {}
+};
+
+const struct nouveau_specdom
+nve0_perfmon_pwr[] = {
+       { 0x20, (const struct nouveau_specsig[]) {
+                       { 0x00, "pwr_gr_idle" },
+                       { 0x04, "pwr_bsp_idle" },
+                       { 0x05, "pwr_vp_idle" },
+                       { 0x06, "pwr_ppp_idle" },
+                       { 0x13, "pwr_ce0_idle" },
+                       { 0x14, "pwr_ce1_idle" },
+                       { 0x15, "pwr_ce2_idle" },
+                       {}
+               }, &pwr_perfctr_func },
+       {}
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c
new file mode 100644 (file)
index 0000000..b2a1078
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv40.h"
+
+/*******************************************************************************
+ * Perfmon object classes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM context
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv40_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
+                 struct nouveau_perfctr *ctr)
+{
+       struct nv40_perfmon_priv *priv = (void *)ppm;
+       struct nv40_perfmon_cntr *cntr = (void *)ctr;
+       u32 log = ctr->logic_op;
+       u32 src = 0x00000000;
+       int i;
+
+       for (i = 0; i < 4 && ctr->signal[i]; i++)
+               src |= (ctr->signal[i] - dom->signal) << (i * 8);
+
+       nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001);
+       nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src);
+       nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log);
+}
+
+static void
+nv40_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
+                 struct nouveau_perfctr *ctr)
+{
+       struct nv40_perfmon_priv *priv = (void *)ppm;
+       struct nv40_perfmon_cntr *cntr = (void *)ctr;
+
+       switch (cntr->base.slot) {
+       case 0: cntr->base.ctr = nv_rd32(priv, 0x00a700 + dom->addr); break;
+       case 1: cntr->base.ctr = nv_rd32(priv, 0x00a6c0 + dom->addr); break;
+       case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break;
+       case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break;
+       }
+       cntr->base.clk = nv_rd32(priv, 0x00a600 + dom->addr);
+}
+
+static void
+nv40_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom)
+{
+       struct nv40_perfmon_priv *priv = (void *)ppm;
+       if (priv->sequence != ppm->sequence) {
+               nv_wr32(priv, 0x400084, 0x00000020);
+               priv->sequence = ppm->sequence;
+       }
+}
+
+const struct nouveau_funcdom
+nv40_perfctr_func = {
+       .init = nv40_perfctr_init,
+       .read = nv40_perfctr_read,
+       .next = nv40_perfctr_next,
+};
+
+static const struct nouveau_specdom
+nv40_perfmon[] = {
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       {}
+};
+
+int
+nv40_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+                 struct nouveau_oclass *oclass, void *data, u32 size,
+                 struct nouveau_object **pobject)
+{
+       struct nv40_perfmon_oclass *mclass = (void *)oclass;
+       struct nv40_perfmon_priv *priv;
+       int ret;
+
+       ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       ret = nouveau_perfdom_new(&priv->base, "pm", 0, 0, 0, 4, mclass->doms);
+       if (ret)
+               return ret;
+
+       nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
+       nv_engine(priv)->sclass =  nouveau_perfmon_sclass;
+       return 0;
+}
+
+struct nouveau_oclass *
+nv40_perfmon_oclass = &(struct nv40_perfmon_oclass) {
+       .base.handle = NV_ENGINE(PERFMON, 0x40),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv40_perfmon_ctor,
+               .dtor = _nouveau_perfmon_dtor,
+               .init = _nouveau_perfmon_init,
+               .fini = _nouveau_perfmon_fini,
+       },
+       .doms = nv40_perfmon,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h
new file mode 100644 (file)
index 0000000..1b5792d
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __NVKM_PM_NV40_H__
+#define __NVKM_PM_NV40_H__
+
+#include "priv.h"
+
+struct nv40_perfmon_oclass {
+       struct nouveau_oclass base;
+       const struct nouveau_specdom *doms;
+};
+
+struct nv40_perfmon_priv {
+       struct nouveau_perfmon base;
+       u32 sequence;
+};
+
+int nv40_perfmon_ctor(struct nouveau_object *, struct nouveau_object *,
+                     struct nouveau_oclass *, void *data, u32 size,
+                     struct nouveau_object **pobject);
+
+struct nv40_perfmon_cntr {
+       struct nouveau_perfctr base;
+};
+
+extern const struct nouveau_funcdom nv40_perfctr_func;
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c
new file mode 100644 (file)
index 0000000..9421769
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv40.h"
+
+/*******************************************************************************
+ * Perfmon object classes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM context
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM engine/subdev functions
+ ******************************************************************************/
+
+static const struct nouveau_specdom
+nv50_perfmon[] = {
+       { 0x040, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x100, (const struct nouveau_specsig[]) {
+                       { 0xc8, "gr_idle" },
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x100, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x020, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x040, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       {}
+};
+
+struct nouveau_oclass *
+nv50_perfmon_oclass = &(struct nv40_perfmon_oclass) {
+       .base.handle = NV_ENGINE(PERFMON, 0x50),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv40_perfmon_ctor,
+               .dtor = _nouveau_perfmon_dtor,
+               .init = _nouveau_perfmon_init,
+               .fini = _nouveau_perfmon_fini,
+       },
+       .doms = nv50_perfmon,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c
new file mode 100644 (file)
index 0000000..9232c7f
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv40.h"
+
+/*******************************************************************************
+ * Perfmon object classes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM context
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM engine/subdev functions
+ ******************************************************************************/
+
+static const struct nouveau_specdom
+nv84_perfmon[] = {
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       {}
+};
+
+struct nouveau_oclass *
+nv84_perfmon_oclass = &(struct nv40_perfmon_oclass) {
+       .base.handle = NV_ENGINE(PERFMON, 0x84),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv40_perfmon_ctor,
+               .dtor = _nouveau_perfmon_dtor,
+               .init = _nouveau_perfmon_init,
+               .fini = _nouveau_perfmon_fini,
+       },
+       .doms = nv84_perfmon,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c
new file mode 100644 (file)
index 0000000..6197ebd
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv40.h"
+
+/*******************************************************************************
+ * Perfmon object classes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM context
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM engine/subdev functions
+ ******************************************************************************/
+
+static const struct nouveau_specdom
+nva3_perfmon[] = {
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       { 0x20, (const struct nouveau_specsig[]) {
+                       {}
+               }, &nv40_perfctr_func },
+       {}
+};
+
+static int
+nva3_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+                 struct nouveau_oclass *oclass, void *data, u32 size,
+                 struct nouveau_object **object)
+{
+       int ret = nv40_perfmon_ctor(parent, engine, oclass, data, size, object);
+       if (ret == 0) {
+               struct nv40_perfmon_priv *priv = (void *)*object;
+               ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
+                                          nva3_perfmon_pwr);
+               if (ret)
+                       return ret;
+
+               priv->base.last = 3;
+       }
+       return ret;
+}
+
+struct nouveau_oclass *
+nva3_perfmon_oclass = &(struct nv40_perfmon_oclass) {
+       .base.handle = NV_ENGINE(PERFMON, 0xa3),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nva3_perfmon_ctor,
+               .dtor = _nouveau_perfmon_dtor,
+               .init = _nouveau_perfmon_init,
+               .fini = _nouveau_perfmon_fini,
+       },
+       .doms = nva3_perfmon,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c
new file mode 100644 (file)
index 0000000..74b2410
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Perfmon object classes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM context
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM engine/subdev functions
+ ******************************************************************************/
+
+static const struct nouveau_specdom
+nvc0_perfmon_hub[] = {
+       {}
+};
+
+static const struct nouveau_specdom
+nvc0_perfmon_gpc[] = {
+       {}
+};
+
+static const struct nouveau_specdom
+nvc0_perfmon_part[] = {
+       {}
+};
+
+static void
+nvc0_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
+                 struct nouveau_perfctr *ctr)
+{
+       struct nvc0_perfmon_priv *priv = (void *)ppm;
+       struct nvc0_perfmon_cntr *cntr = (void *)ctr;
+       u32 log = ctr->logic_op;
+       u32 src = 0x00000000;
+       int i;
+
+       for (i = 0; i < 4 && ctr->signal[i]; i++)
+               src |= (ctr->signal[i] - dom->signal) << (i * 8);
+
+       nv_wr32(priv, dom->addr + 0x09c, 0x00040002);
+       nv_wr32(priv, dom->addr + 0x100, 0x00000000);
+       nv_wr32(priv, dom->addr + 0x040 + (cntr->base.slot * 0x08), src);
+       nv_wr32(priv, dom->addr + 0x044 + (cntr->base.slot * 0x08), log);
+}
+
+static void
+nvc0_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
+                 struct nouveau_perfctr *ctr)
+{
+       struct nvc0_perfmon_priv *priv = (void *)ppm;
+       struct nvc0_perfmon_cntr *cntr = (void *)ctr;
+
+       switch (cntr->base.slot) {
+       case 0: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x08c); break;
+       case 1: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x088); break;
+       case 2: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x080); break;
+       case 3: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x090); break;
+       }
+       cntr->base.clk = nv_rd32(priv, dom->addr + 0x070);
+}
+
+static void
+nvc0_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom)
+{
+       struct nvc0_perfmon_priv *priv = (void *)ppm;
+       nv_wr32(priv, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27);
+       nv_wr32(priv, dom->addr + 0x0ec, 0x00000011);
+}
+
+const struct nouveau_funcdom
+nvc0_perfctr_func = {
+       .init = nvc0_perfctr_init,
+       .read = nvc0_perfctr_read,
+       .next = nvc0_perfctr_next,
+};
+
+int
+nvc0_perfmon_fini(struct nouveau_object *object, bool suspend)
+{
+       struct nvc0_perfmon_priv *priv = (void *)object;
+       nv_mask(priv, 0x000200, 0x10000000, 0x00000000);
+       nv_mask(priv, 0x000200, 0x10000000, 0x10000000);
+       return nouveau_perfmon_fini(&priv->base, suspend);
+}
+
+static int
+nvc0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+                 struct nouveau_oclass *oclass, void *data, u32 size,
+                 struct nouveau_object **pobject)
+{
+       struct nvc0_perfmon_priv *priv;
+       u32 mask;
+       int ret;
+
+       ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
+                                  nvc0_perfmon_pwr);
+       if (ret)
+               return ret;
+
+       /* HUB */
+       ret = nouveau_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200,
+                                  nvc0_perfmon_hub);
+       if (ret)
+               return ret;
+
+       /* GPC */
+       mask  = (1 << nv_rd32(priv, 0x022430)) - 1;
+       mask &= ~nv_rd32(priv, 0x022504);
+       mask &= ~nv_rd32(priv, 0x022584);
+
+       ret = nouveau_perfdom_new(&priv->base, "gpc", mask, 0x180000,
+                                 0x1000, 0x200, nvc0_perfmon_gpc);
+       if (ret)
+               return ret;
+
+       /* PART */
+       mask  = (1 << nv_rd32(priv, 0x022438)) - 1;
+       mask &= ~nv_rd32(priv, 0x022548);
+       mask &= ~nv_rd32(priv, 0x0225c8);
+
+       ret = nouveau_perfdom_new(&priv->base, "part", mask, 0x1a0000,
+                                 0x1000, 0x200, nvc0_perfmon_part);
+       if (ret)
+               return ret;
+
+       nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
+       nv_engine(priv)->sclass =  nouveau_perfmon_sclass;
+       priv->base.last = 7;
+       return 0;
+}
+
+struct nouveau_oclass
+nvc0_perfmon_oclass = {
+       .handle = NV_ENGINE(PERFMON, 0xc0),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvc0_perfmon_ctor,
+               .dtor = _nouveau_perfmon_dtor,
+               .init = _nouveau_perfmon_init,
+               .fini = nvc0_perfmon_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h
new file mode 100644 (file)
index 0000000..f66bca4
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __NVKM_PM_NVC0_H__
+#define __NVKM_PM_NVC0_H__
+
+#include "priv.h"
+
+struct nvc0_perfmon_priv {
+       struct nouveau_perfmon base;
+};
+
+struct nvc0_perfmon_cntr {
+       struct nouveau_perfctr base;
+};
+
+extern const struct nouveau_funcdom nvc0_perfctr_func;
+int nvc0_perfmon_fini(struct nouveau_object *, bool);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c
new file mode 100644 (file)
index 0000000..71d718c
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Perfmon object classes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM context
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM engine/subdev functions
+ ******************************************************************************/
+
+static const struct nouveau_specdom
+nve0_perfmon_hub[] = {
+       { 0x60, (const struct nouveau_specsig[]) {
+                       { 0x47, "hub00_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       { 0x40, (const struct nouveau_specsig[]) {
+                       { 0x27, "hub01_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       { 0x60, (const struct nouveau_specsig[]) {
+                       { 0x47, "hub02_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       { 0x60, (const struct nouveau_specsig[]) {
+                       { 0x47, "hub03_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       { 0x40, (const struct nouveau_specsig[]) {
+                       { 0x03, "host_mmio_rd" },
+                       { 0x27, "hub04_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       { 0x60, (const struct nouveau_specsig[]) {
+                       { 0x47, "hub05_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       { 0xc0, (const struct nouveau_specsig[]) {
+                       { 0x74, "host_fb_rd3x" },
+                       { 0x75, "host_fb_rd3x_2" },
+                       { 0xa7, "hub06_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       { 0x60, (const struct nouveau_specsig[]) {
+                       { 0x47, "hub07_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       {}
+};
+
+static const struct nouveau_specdom
+nve0_perfmon_gpc[] = {
+       { 0xe0, (const struct nouveau_specsig[]) {
+                       { 0xc7, "gpc00_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       {}
+};
+
+static const struct nouveau_specdom
+nve0_perfmon_part[] = {
+       { 0x60, (const struct nouveau_specsig[]) {
+                       { 0x47, "part00_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       { 0x60, (const struct nouveau_specsig[]) {
+                       { 0x47, "part01_user_0" },
+                       {}
+               }, &nvc0_perfctr_func },
+       {}
+};
+
+static int
+nve0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+                 struct nouveau_oclass *oclass, void *data, u32 size,
+                 struct nouveau_object **pobject)
+{
+       struct nvc0_perfmon_priv *priv;
+       u32 mask;
+       int ret;
+
+       ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       /* PDAEMON */
+       ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
+                                  nve0_perfmon_pwr);
+       if (ret)
+               return ret;
+
+       /* HUB */
+       ret = nouveau_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200,
+                                  nve0_perfmon_hub);
+       if (ret)
+               return ret;
+
+       /* GPC */
+       mask  = (1 << nv_rd32(priv, 0x022430)) - 1;
+       mask &= ~nv_rd32(priv, 0x022504);
+       mask &= ~nv_rd32(priv, 0x022584);
+
+       ret = nouveau_perfdom_new(&priv->base, "gpc", mask, 0x180000,
+                                 0x1000, 0x200, nve0_perfmon_gpc);
+       if (ret)
+               return ret;
+
+       /* PART */
+       mask  = (1 << nv_rd32(priv, 0x022438)) - 1;
+       mask &= ~nv_rd32(priv, 0x022548);
+       mask &= ~nv_rd32(priv, 0x0225c8);
+
+       ret = nouveau_perfdom_new(&priv->base, "part", mask, 0x1a0000,
+                                 0x1000, 0x200, nve0_perfmon_part);
+       if (ret)
+               return ret;
+
+       nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
+       nv_engine(priv)->sclass =  nouveau_perfmon_sclass;
+       priv->base.last = 7;
+       return 0;
+}
+
+struct nouveau_oclass
+nve0_perfmon_oclass = {
+       .handle = NV_ENGINE(PERFMON, 0xe0),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nve0_perfmon_ctor,
+               .dtor = _nouveau_perfmon_dtor,
+               .init = _nouveau_perfmon_init,
+               .fini = nvc0_perfmon_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c
new file mode 100644 (file)
index 0000000..47256f7
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Perfmon object classes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM context
+ ******************************************************************************/
+
+/*******************************************************************************
+ * PPM engine/subdev functions
+ ******************************************************************************/
+
+static int
+nvf0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+                 struct nouveau_oclass *oclass, void *data, u32 size,
+                 struct nouveau_object **pobject)
+{
+       struct nvc0_perfmon_priv *priv;
+       int ret;
+
+       ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
+                                  nve0_perfmon_pwr);
+       if (ret)
+               return ret;
+
+       nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
+       nv_engine(priv)->sclass =  nouveau_perfmon_sclass;
+       return 0;
+}
+
+struct nouveau_oclass
+nvf0_perfmon_oclass = {
+       .handle = NV_ENGINE(PERFMON, 0xf0),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvf0_perfmon_ctor,
+               .dtor = _nouveau_perfmon_dtor,
+               .init = _nouveau_perfmon_init,
+               .fini = nvc0_perfmon_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h
new file mode 100644 (file)
index 0000000..0ac8714
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef __NVKM_PERFMON_PRIV_H__
+#define __NVKM_PERFMON_PRIV_H__
+
+#include <engine/perfmon.h>
+
+struct nouveau_perfctr {
+       struct nouveau_object base;
+       struct list_head head;
+       struct nouveau_perfsig *signal[4];
+       int slot;
+       u32 logic_op;
+       u32 clk;
+       u32 ctr;
+};
+
+extern struct nouveau_oclass nouveau_perfmon_sclass[];
+
+struct nouveau_perfctx {
+       struct nouveau_engctx base;
+};
+
+extern struct nouveau_oclass nouveau_perfmon_cclass;
+
+struct nouveau_specsig {
+       u8 signal;
+       const char *name;
+};
+
+struct nouveau_perfsig {
+       const char *name;
+};
+
+struct nouveau_perfdom;
+struct nouveau_perfctr *
+nouveau_perfsig_wrap(struct nouveau_perfmon *, const char *,
+                    struct nouveau_perfdom **);
+
+struct nouveau_specdom {
+       u16 signal_nr;
+       const struct nouveau_specsig *signal;
+       const struct nouveau_funcdom *func;
+};
+
+extern const struct nouveau_specdom nva3_perfmon_pwr[];
+extern const struct nouveau_specdom nvc0_perfmon_pwr[];
+extern const struct nouveau_specdom nve0_perfmon_pwr[];
+
+struct nouveau_perfdom {
+       struct list_head head;
+       struct list_head list;
+       const struct nouveau_funcdom *func;
+       char name[32];
+       u32 addr;
+       u8  quad;
+       u32 signal_nr;
+       struct nouveau_perfsig signal[];
+};
+
+struct nouveau_funcdom {
+       void (*init)(struct nouveau_perfmon *, struct nouveau_perfdom *,
+                    struct nouveau_perfctr *);
+       void (*read)(struct nouveau_perfmon *, struct nouveau_perfdom *,
+                    struct nouveau_perfctr *);
+       void (*next)(struct nouveau_perfmon *, struct nouveau_perfdom *);
+};
+
+int nouveau_perfdom_new(struct nouveau_perfmon *, const char *, u32,
+                       u32, u32, u32, const struct nouveau_specdom *);
+
+#define nouveau_perfmon_create(p,e,o,d)                                        \
+       nouveau_perfmon_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nouveau_perfmon_dtor(p) ({                                             \
+       struct nouveau_perfmon *c = (p);                                       \
+       _nouveau_perfmon_dtor(nv_object(c));                                   \
+})
+#define nouveau_perfmon_init(p) ({                                             \
+       struct nouveau_perfmon *c = (p);                                       \
+       _nouveau_perfmon_init(nv_object(c));                                   \
+})
+#define nouveau_perfmon_fini(p,s) ({                                           \
+       struct nouveau_perfmon *c = (p);                                       \
+       _nouveau_perfmon_fini(nv_object(c), (s));                              \
+})
+
+int nouveau_perfmon_create_(struct nouveau_object *, struct nouveau_object *,
+                           struct nouveau_oclass *, int, void **);
+void _nouveau_perfmon_dtor(struct nouveau_object *);
+int  _nouveau_perfmon_init(struct nouveau_object *);
+int  _nouveau_perfmon_fini(struct nouveau_object *, bool);
+
+#endif
index 2a859a3..c571758 100644 (file)
@@ -135,8 +135,8 @@ nv04_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nv04_software_oclass = {
+struct nouveau_oclass *
+nv04_software_oclass = &(struct nouveau_oclass) {
        .handle = NV_ENGINE(SW, 0x04),
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv04_software_ctor,
index a019364..a62f11a 100644 (file)
@@ -117,8 +117,8 @@ nv10_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nv10_software_oclass = {
+struct nouveau_oclass *
+nv10_software_oclass = &(struct nouveau_oclass) {
        .handle = NV_ENGINE(SW, 0x10),
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv10_software_ctor,
index c48e749..b574dd4 100644 (file)
 
 #include <subdev/bar.h>
 
-#include <engine/software.h>
 #include <engine/disp.h>
 
-struct nv50_software_priv {
-       struct nouveau_software base;
-};
-
-struct nv50_software_chan {
-       struct nouveau_software_chan base;
-};
+#include "nv50.h"
 
 /*******************************************************************************
  * software object classes
@@ -62,7 +55,7 @@ nv50_software_mthd_dma_vblsem(struct nouveau_object *object, u32 mthd,
 
        if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
                struct nouveau_gpuobj *gpuobj = nv_gpuobj(handle->object);
-               chan->base.vblank.ctxdma = gpuobj->node->offset >> 4;
+               chan->vblank.ctxdma = gpuobj->node->offset >> 4;
                ret = 0;
        }
        nouveau_namedb_put(handle);
@@ -74,34 +67,33 @@ nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
                                 void *args, u32 size)
 {
        struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
-       chan->base.vblank.offset = *(u32 *)args;
+       chan->vblank.offset = *(u32 *)args;
        return 0;
 }
 
-static int
+int
 nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
                                void *args, u32 size)
 {
        struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
-       chan->base.vblank.value = *(u32 *)args;
+       chan->vblank.value = *(u32 *)args;
        return 0;
 }
 
-static int
+int
 nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
                                  void *args, u32 size)
 {
        struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
-       struct nouveau_disp *disp = nouveau_disp(object);
-       u32 crtc = *(u32 *)args;
-       if (crtc > 1)
+       u32 head = *(u32 *)args;
+       if (head >= chan->vblank.nr_event)
                return -EINVAL;
 
-       nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event);
+       nouveau_event_get(chan->vblank.event[head]);
        return 0;
 }
 
-static int
+int
 nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd,
                        void *args, u32 size)
 {
@@ -132,10 +124,9 @@ nv50_software_sclass[] = {
  ******************************************************************************/
 
 static int
-nv50_software_vblsem_release(struct nouveau_eventh *event, int head)
+nv50_software_vblsem_release(void *data, int head)
 {
-       struct nouveau_software_chan *chan =
-               container_of(event, struct nouveau_software_chan, vblank.event);
+       struct nv50_software_chan *chan = data;
        struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
        struct nouveau_bar *bar = nouveau_bar(priv);
 
@@ -154,45 +145,76 @@ nv50_software_vblsem_release(struct nouveau_eventh *event, int head)
        return NVKM_EVENT_DROP;
 }
 
-static int
+void
+nv50_software_context_dtor(struct nouveau_object *object)
+{
+       struct nv50_software_chan *chan = (void *)object;
+       int i;
+
+       if (chan->vblank.event) {
+               for (i = 0; i < chan->vblank.nr_event; i++)
+                       nouveau_event_ref(NULL, &chan->vblank.event[i]);
+               kfree(chan->vblank.event);
+       }
+
+       nouveau_software_context_destroy(&chan->base);
+}
+
+int
 nv50_software_context_ctor(struct nouveau_object *parent,
                           struct nouveau_object *engine,
                           struct nouveau_oclass *oclass, void *data, u32 size,
                           struct nouveau_object **pobject)
 {
+       struct nouveau_disp *pdisp = nouveau_disp(parent);
+       struct nv50_software_cclass *pclass = (void *)oclass;
        struct nv50_software_chan *chan;
-       int ret;
+       int ret, i;
 
        ret = nouveau_software_context_create(parent, engine, oclass, &chan);
        *pobject = nv_object(chan);
        if (ret)
                return ret;
 
-       chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
-       chan->base.vblank.event.func = nv50_software_vblsem_release;
+       chan->vblank.nr_event = pdisp->vblank->index_nr;
+       chan->vblank.event = kzalloc(chan->vblank.nr_event *
+                                    sizeof(*chan->vblank.event), GFP_KERNEL);
+       if (!chan->vblank.event)
+               return -ENOMEM;
+
+       for (i = 0; i < chan->vblank.nr_event; i++) {
+               ret = nouveau_event_new(pdisp->vblank, i, pclass->vblank,
+                                       chan, &chan->vblank.event[i]);
+               if (ret)
+                       return ret;
+       }
+
+       chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
        return 0;
 }
 
-static struct nouveau_oclass
+static struct nv50_software_cclass
 nv50_software_cclass = {
-       .handle = NV_ENGCTX(SW, 0x50),
-       .ofuncs = &(struct nouveau_ofuncs) {
+       .base.handle = NV_ENGCTX(SW, 0x50),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv50_software_context_ctor,
                .dtor = _nouveau_software_context_dtor,
                .init = _nouveau_software_context_init,
                .fini = _nouveau_software_context_fini,
        },
+       .vblank = nv50_software_vblsem_release,
 };
 
 /*******************************************************************************
  * software engine/subdev functions
  ******************************************************************************/
 
-static int
+int
 nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                   struct nouveau_oclass *oclass, void *data, u32 size,
                   struct nouveau_object **pobject)
 {
+       struct nv50_software_oclass *pclass = (void *)oclass;
        struct nv50_software_priv *priv;
        int ret;
 
@@ -201,19 +223,21 @@ nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_engine(priv)->cclass = &nv50_software_cclass;
-       nv_engine(priv)->sclass = nv50_software_sclass;
+       nv_engine(priv)->cclass = pclass->cclass;
+       nv_engine(priv)->sclass = pclass->sclass;
        nv_subdev(priv)->intr = nv04_software_intr;
        return 0;
 }
 
-struct nouveau_oclass
-nv50_software_oclass = {
-       .handle = NV_ENGINE(SW, 0x50),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv50_software_oclass = &(struct nv50_software_oclass) {
+       .base.handle = NV_ENGINE(SW, 0x50),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv50_software_ctor,
                .dtor = _nouveau_software_dtor,
                .init = _nouveau_software_init,
                .fini = _nouveau_software_fini,
        },
-};
+       .cclass = &nv50_software_cclass.base,
+       .sclass =  nv50_software_sclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.h b/drivers/gpu/drm/nouveau/core/engine/software/nv50.h
new file mode 100644 (file)
index 0000000..2de370c
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __NVKM_SW_NV50_H__
+#define __NVKM_SW_NV50_H__
+
+#include <engine/software.h>
+
+struct nv50_software_oclass {
+       struct nouveau_oclass base;
+       struct nouveau_oclass *cclass;
+       struct nouveau_oclass *sclass;
+};
+
+struct nv50_software_priv {
+       struct nouveau_software base;
+};
+
+int  nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
+                       struct nouveau_oclass *, void *, u32,
+                       struct nouveau_object **);
+
+struct nv50_software_cclass {
+       struct nouveau_oclass base;
+       int (*vblank)(void *, int);
+};
+
+struct nv50_software_chan {
+       struct nouveau_software_chan base;
+       struct {
+               struct nouveau_eventh **event;
+               int nr_event;
+               u32 channel;
+               u32 ctxdma;
+               u64 offset;
+               u32 value;
+       } vblank;
+};
+
+int  nv50_software_context_ctor(struct nouveau_object *,
+                               struct nouveau_object *,
+                               struct nouveau_oclass *, void *, u32,
+                               struct nouveau_object **);
+void nv50_software_context_dtor(struct nouveau_object *);
+
+int nv50_software_mthd_vblsem_value(struct nouveau_object *, u32, void *, u32);
+int nv50_software_mthd_vblsem_release(struct nouveau_object *, u32, void *, u32);
+int nv50_software_mthd_flip(struct nouveau_object *, u32, void *, u32);
+
+#endif
index d698e71..f9430c1 100644 (file)
 #include <engine/software.h>
 #include <engine/disp.h>
 
-struct nvc0_software_priv {
-       struct nouveau_software base;
-};
-
-struct nvc0_software_chan {
-       struct nouveau_software_chan base;
-};
+#include "nv50.h"
 
 /*******************************************************************************
  * software object classes
@@ -48,58 +42,24 @@ static int
 nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
                                 void *args, u32 size)
 {
-       struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
+       struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
        u64 data = *(u32 *)args;
        if (mthd == 0x0400) {
-               chan->base.vblank.offset &= 0x00ffffffffULL;
-               chan->base.vblank.offset |= data << 32;
+               chan->vblank.offset &= 0x00ffffffffULL;
+               chan->vblank.offset |= data << 32;
        } else {
-               chan->base.vblank.offset &= 0xff00000000ULL;
-               chan->base.vblank.offset |= data;
+               chan->vblank.offset &= 0xff00000000ULL;
+               chan->vblank.offset |= data;
        }
        return 0;
 }
 
-static int
-nvc0_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
-                               void *args, u32 size)
-{
-       struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
-       chan->base.vblank.value = *(u32 *)args;
-       return 0;
-}
-
-static int
-nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
-                                 void *args, u32 size)
-{
-       struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
-       struct nouveau_disp *disp = nouveau_disp(object);
-       u32 crtc = *(u32 *)args;
-
-       if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3)
-               return -EINVAL;
-
-       nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event);
-       return 0;
-}
-
-static int
-nvc0_software_mthd_flip(struct nouveau_object *object, u32 mthd,
-                       void *args, u32 size)
-{
-       struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
-       if (chan->base.flip)
-               return chan->base.flip(chan->base.flip_data);
-       return -EINVAL;
-}
-
 static int
 nvc0_software_mthd_mp_control(struct nouveau_object *object, u32 mthd,
                               void *args, u32 size)
 {
-       struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
-       struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine;
+       struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
+       struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
        u32 data = *(u32 *)args;
 
        switch (mthd) {
@@ -124,9 +84,9 @@ static struct nouveau_omthds
 nvc0_software_omthds[] = {
        { 0x0400, 0x0400, nvc0_software_mthd_vblsem_offset },
        { 0x0404, 0x0404, nvc0_software_mthd_vblsem_offset },
-       { 0x0408, 0x0408, nvc0_software_mthd_vblsem_value },
-       { 0x040c, 0x040c, nvc0_software_mthd_vblsem_release },
-       { 0x0500, 0x0500, nvc0_software_mthd_flip },
+       { 0x0408, 0x0408, nv50_software_mthd_vblsem_value },
+       { 0x040c, 0x040c, nv50_software_mthd_vblsem_release },
+       { 0x0500, 0x0500, nv50_software_mthd_flip },
        { 0x0600, 0x0600, nvc0_software_mthd_mp_control },
        { 0x0644, 0x0644, nvc0_software_mthd_mp_control },
        { 0x06ac, 0x06ac, nvc0_software_mthd_mp_control },
@@ -144,11 +104,10 @@ nvc0_software_sclass[] = {
  ******************************************************************************/
 
 static int
-nvc0_software_vblsem_release(struct nouveau_eventh *event, int head)
+nvc0_software_vblsem_release(void *data, int head)
 {
-       struct nouveau_software_chan *chan =
-               container_of(event, struct nouveau_software_chan, vblank.event);
-       struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine;
+       struct nv50_software_chan *chan = data;
+       struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
        struct nouveau_bar *bar = nouveau_bar(priv);
 
        nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
@@ -160,66 +119,31 @@ nvc0_software_vblsem_release(struct nouveau_eventh *event, int head)
        return NVKM_EVENT_DROP;
 }
 
-static int
-nvc0_software_context_ctor(struct nouveau_object *parent,
-                          struct nouveau_object *engine,
-                          struct nouveau_oclass *oclass, void *data, u32 size,
-                          struct nouveau_object **pobject)
-{
-       struct nvc0_software_chan *chan;
-       int ret;
-
-       ret = nouveau_software_context_create(parent, engine, oclass, &chan);
-       *pobject = nv_object(chan);
-       if (ret)
-               return ret;
-
-       chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
-       chan->base.vblank.event.func = nvc0_software_vblsem_release;
-       return 0;
-}
-
-static struct nouveau_oclass
+static struct nv50_software_cclass
 nvc0_software_cclass = {
-       .handle = NV_ENGCTX(SW, 0xc0),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nvc0_software_context_ctor,
+       .base.handle = NV_ENGCTX(SW, 0xc0),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_software_context_ctor,
                .dtor = _nouveau_software_context_dtor,
                .init = _nouveau_software_context_init,
                .fini = _nouveau_software_context_fini,
        },
+       .vblank = nvc0_software_vblsem_release,
 };
 
 /*******************************************************************************
  * software engine/subdev functions
  ******************************************************************************/
 
-static int
-nvc0_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-                  struct nouveau_oclass *oclass, void *data, u32 size,
-                  struct nouveau_object **pobject)
-{
-       struct nvc0_software_priv *priv;
-       int ret;
-
-       ret = nouveau_software_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       nv_engine(priv)->cclass = &nvc0_software_cclass;
-       nv_engine(priv)->sclass = nvc0_software_sclass;
-       nv_subdev(priv)->intr = nv04_software_intr;
-       return 0;
-}
-
-struct nouveau_oclass
-nvc0_software_oclass = {
-       .handle = NV_ENGINE(SW, 0xc0),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nvc0_software_ctor,
+struct nouveau_oclass *
+nvc0_software_oclass = &(struct nv50_software_oclass) {
+       .base.handle = NV_ENGINE(SW, 0xc0),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_software_ctor,
                .dtor = _nouveau_software_dtor,
                .init = _nouveau_software_init,
                .fini = _nouveau_software_fini,
        },
-};
+       .cclass = &nvc0_software_cclass.base,
+       .sclass =  nvc0_software_sclass,
+}.base;
index 5a5961b..560c359 100644 (file)
@@ -22,7 +22,7 @@
 #define NV_DEVICE_DISABLE_PPP                             0x0000004000000000ULL
 #define NV_DEVICE_DISABLE_COPY0                           0x0000008000000000ULL
 #define NV_DEVICE_DISABLE_COPY1                           0x0000010000000000ULL
-#define NV_DEVICE_DISABLE_UNK1C1                          0x0000020000000000ULL
+#define NV_DEVICE_DISABLE_VIC                             0x0000020000000000ULL
 #define NV_DEVICE_DISABLE_VENC                            0x0000040000000000ULL
 
 struct nv_device_class {
@@ -98,6 +98,77 @@ struct nv_dma_class {
        u32 conf0;
 };
 
+/* Perfmon counter class
+ *
+ * XXXX: NV_PERFCTR
+ */
+#define NV_PERFCTR_CLASS                                             0x0000ffff
+#define NV_PERFCTR_QUERY                                             0x00000000
+#define NV_PERFCTR_SAMPLE                                            0x00000001
+#define NV_PERFCTR_READ                                              0x00000002
+
+struct nv_perfctr_class {
+       u16 logic_op;
+       struct {
+               char __user *name; /*XXX: use cfu when exposed to userspace */
+               u32 size;
+       } signal[4];
+};
+
+struct nv_perfctr_query {
+       u32 iter;
+       u32 size;
+       char __user *name; /*XXX: use ctu when exposed to userspace */
+};
+
+struct nv_perfctr_sample {
+};
+
+struct nv_perfctr_read {
+       u32 ctr;
+       u32 clk;
+};
+
+/* Device control class
+ *
+ * XXXX: NV_CONTROL
+ */
+#define NV_CONTROL_CLASS                                             0x0000fffe
+
+#define NV_CONTROL_PSTATE_INFO                                       0x00000000
+#define NV_CONTROL_PSTATE_INFO_USTATE_DISABLE                              (-1)
+#define NV_CONTROL_PSTATE_INFO_USTATE_PERFMON                              (-2)
+#define NV_CONTROL_PSTATE_INFO_PSTATE_UNKNOWN                              (-1)
+#define NV_CONTROL_PSTATE_INFO_PSTATE_PERFMON                              (-2)
+#define NV_CONTROL_PSTATE_ATTR                                       0x00000001
+#define NV_CONTROL_PSTATE_ATTR_STATE_CURRENT                               (-1)
+#define NV_CONTROL_PSTATE_USER                                       0x00000002
+#define NV_CONTROL_PSTATE_USER_STATE_UNKNOWN                               (-1)
+#define NV_CONTROL_PSTATE_USER_STATE_PERFMON                               (-2)
+
+struct nv_control_pstate_info {
+       u32 count; /* out: number of power states */
+       s32 ustate; /* out: current target pstate index */
+       u32 pstate; /* out: current pstate index */
+};
+
+struct nv_control_pstate_attr {
+       s32 state; /*  in: index of pstate to query
+                   * out: pstate identifier
+                   */
+       u32 index; /*  in: index of attribute to query
+                   * out: index of next attribute, or 0 if no more
+                   */
+       char name[32];
+       char unit[16];
+       u32 min;
+       u32 max;
+};
+
+struct nv_control_pstate_user {
+       s32 state; /*  in: pstate identifier */
+};
+
 /* DMA FIFO channel classes
  *
  * 006b: NV03_CHANNEL_DMA
index 9ea18df..8092e2e 100644 (file)
@@ -1,13 +1,20 @@
 #ifndef __NOUVEAU_DEBUG_H__
 #define __NOUVEAU_DEBUG_H__
 
+extern int nv_info_debug_level;
+
 #define NV_DBG_FATAL    0
 #define NV_DBG_ERROR    1
 #define NV_DBG_WARN     2
-#define NV_DBG_INFO     3
+#define NV_DBG_INFO     nv_info_debug_level
 #define NV_DBG_DEBUG    4
 #define NV_DBG_TRACE    5
 #define NV_DBG_PARANOIA 6
 #define NV_DBG_SPAM     7
 
+#define NV_DBG_INFO_NORMAL 3
+#define NV_DBG_INFO_SILENT NV_DBG_DEBUG
+
+#define nv_debug_level(a) nv_info_debug_level = NV_DBG_INFO_##a
+
 #endif
index 99b6600..ac2881d 100644 (file)
@@ -33,9 +33,10 @@ enum nv_subdev_type {
        NVDEV_SUBDEV_INSTMEM,
        NVDEV_SUBDEV_VM,
        NVDEV_SUBDEV_BAR,
+       NVDEV_SUBDEV_PWR,
        NVDEV_SUBDEV_VOLT,
-       NVDEV_SUBDEV_CLOCK,
        NVDEV_SUBDEV_THERM,
+       NVDEV_SUBDEV_CLOCK,
 
        NVDEV_ENGINE_DMAOBJ,
        NVDEV_ENGINE_FIFO,
@@ -50,9 +51,10 @@ enum nv_subdev_type {
        NVDEV_ENGINE_COPY0,
        NVDEV_ENGINE_COPY1,
        NVDEV_ENGINE_COPY2,
-       NVDEV_ENGINE_UNK1C1,
+       NVDEV_ENGINE_VIC,
        NVDEV_ENGINE_VENC,
        NVDEV_ENGINE_DISP,
+       NVDEV_ENGINE_PERFMON,
 
        NVDEV_SUBDEV_NR,
 };
@@ -72,6 +74,7 @@ struct nouveau_device {
        enum {
                NV_04    = 0x04,
                NV_10    = 0x10,
+               NV_11    = 0x11,
                NV_20    = 0x20,
                NV_30    = 0x30,
                NV_40    = 0x40,
index 9e09440..5d539eb 100644 (file)
@@ -5,13 +5,21 @@
 #define NVKM_EVENT_DROP 0
 #define NVKM_EVENT_KEEP 1
 
+/* nouveau_eventh.flags bit #s */
+#define NVKM_EVENT_ENABLE 0
+
 struct nouveau_eventh {
+       struct nouveau_event *event;
        struct list_head head;
-       int (*func)(struct nouveau_eventh *, int index);
+       unsigned long flags;
+       int index;
+       int (*func)(void *, int);
+       void *priv;
 };
 
 struct nouveau_event {
-       spinlock_t lock;
+       spinlock_t list_lock;
+       spinlock_t refs_lock;
 
        void *priv;
        void (*enable)(struct nouveau_event *, int index);
@@ -28,9 +36,11 @@ int  nouveau_event_create(int index_nr, struct nouveau_event **);
 void nouveau_event_destroy(struct nouveau_event **);
 void nouveau_event_trigger(struct nouveau_event *, int index);
 
-void nouveau_event_get(struct nouveau_event *, int index,
-                      struct nouveau_eventh *);
-void nouveau_event_put(struct nouveau_event *, int index,
-                      struct nouveau_eventh *);
+int  nouveau_event_new(struct nouveau_event *, int index,
+                      int (*func)(void *, int), void *,
+                      struct nouveau_eventh **);
+void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **);
+void nouveau_event_get(struct nouveau_eventh *);
+void nouveau_event_put(struct nouveau_eventh *);
 
 #endif
index 2707495..ed05584 100644 (file)
@@ -8,4 +8,13 @@ bool nouveau_boolopt(const char *optstr, const char *opt, bool value);
 
 int nouveau_dbgopt(const char *optstr, const char *sub);
 
+/* compares unterminated string 'str' with zero-terminated string 'cmp' */
+static inline int
+strncasecmpz(const char *str, const char *cmp, size_t len)
+{
+       if (strlen(cmp) != len)
+               return len;
+       return strncasecmp(str, cmp, len);
+}
+
 #endif
index d87836e..0f9a37b 100644 (file)
@@ -6,27 +6,12 @@
 
 struct nouveau_object;
 
-#define NV_PRINTK_FATAL    KERN_CRIT
-#define NV_PRINTK_ERROR    KERN_ERR
-#define NV_PRINTK_WARN     KERN_WARNING
-#define NV_PRINTK_INFO     KERN_INFO
-#define NV_PRINTK_DEBUG    KERN_DEBUG
-#define NV_PRINTK_PARANOIA KERN_DEBUG
-#define NV_PRINTK_TRACE    KERN_DEBUG
-#define NV_PRINTK_SPAM     KERN_DEBUG
-
-extern int nv_printk_suspend_level;
-
-#define NV_DBG_SUSPEND (nv_printk_suspend_level)
-#define NV_PRINTK_SUSPEND  (nv_printk_level_to_pfx(nv_printk_suspend_level))
-
-const char *nv_printk_level_to_pfx(int level);
-void __printf(4, 5)
-nv_printk_(struct nouveau_object *, const char *, int, const char *, ...);
+void __printf(3, 4)
+nv_printk_(struct nouveau_object *, int, const char *, ...);
 
 #define nv_printk(o,l,f,a...) do {                                             \
        if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG)                                \
-               nv_printk_(nv_object(o), NV_PRINTK_##l, NV_DBG_##l, f, ##a);   \
+               nv_printk_(nv_object(o), NV_DBG_##l, f, ##a);                  \
 } while(0)
 
 #define nv_fatal(o,f,a...) nv_printk((o), FATAL, f, ##a)
@@ -37,16 +22,9 @@ nv_printk_(struct nouveau_object *, const char *, int, const char *, ...);
 #define nv_trace(o,f,a...) nv_printk((o), TRACE, f, ##a)
 #define nv_spam(o,f,a...) nv_printk((o), SPAM, f, ##a)
 
-#define nv_suspend(o,f,a...) nv_printk((o), SUSPEND, f, ##a)
-
-static inline void nv_suspend_set_printk_level(int level)
-{
-       nv_printk_suspend_level = level;
-}
-
 #define nv_assert(f,a...) do {                                                 \
        if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG)                              \
-               nv_printk_(NULL, NV_PRINTK_FATAL, NV_DBG_FATAL, f "\n", ##a);  \
+               nv_printk_(NULL, NV_DBG_FATAL, f "\n", ##a);                   \
        BUG_ON(1);                                                             \
 } while(0)
 
index 633c2f8..8c32cf4 100644 (file)
@@ -101,14 +101,14 @@ nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid);
 #define _nouveau_fifo_init _nouveau_engine_init
 #define _nouveau_fifo_fini _nouveau_engine_fini
 
-extern struct nouveau_oclass nv04_fifo_oclass;
-extern struct nouveau_oclass nv10_fifo_oclass;
-extern struct nouveau_oclass nv17_fifo_oclass;
-extern struct nouveau_oclass nv40_fifo_oclass;
-extern struct nouveau_oclass nv50_fifo_oclass;
-extern struct nouveau_oclass nv84_fifo_oclass;
-extern struct nouveau_oclass nvc0_fifo_oclass;
-extern struct nouveau_oclass nve0_fifo_oclass;
+extern struct nouveau_oclass *nv04_fifo_oclass;
+extern struct nouveau_oclass *nv10_fifo_oclass;
+extern struct nouveau_oclass *nv17_fifo_oclass;
+extern struct nouveau_oclass *nv40_fifo_oclass;
+extern struct nouveau_oclass *nv50_fifo_oclass;
+extern struct nouveau_oclass *nv84_fifo_oclass;
+extern struct nouveau_oclass *nvc0_fifo_oclass;
+extern struct nouveau_oclass *nve0_fifo_oclass;
 
 void nv04_fifo_intr(struct nouveau_subdev *);
 int  nv04_fifo_context_attach(struct nouveau_object *, struct nouveau_object *);
index 1d1a89a..9b0d938 100644 (file)
@@ -42,10 +42,13 @@ struct nouveau_mpeg {
 
 extern struct nouveau_oclass nv31_mpeg_oclass;
 extern struct nouveau_oclass nv40_mpeg_oclass;
+extern struct nouveau_oclass nv44_mpeg_oclass;
 extern struct nouveau_oclass nv50_mpeg_oclass;
 extern struct nouveau_oclass nv84_mpeg_oclass;
-
+extern struct nouveau_ofuncs nv31_mpeg_ofuncs;
+extern struct nouveau_oclass nv31_mpeg_cclass;
 extern struct nouveau_oclass nv31_mpeg_sclass[];
+extern struct nouveau_oclass nv40_mpeg_sclass[];
 void nv31_mpeg_intr(struct nouveau_subdev *);
 void nv31_mpeg_tile_prog(struct nouveau_engine *, int);
 int  nv31_mpeg_init(struct nouveau_object *);
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h b/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h
new file mode 100644 (file)
index 0000000..49b0024
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __NVKM_PERFMON_H__
+#define __NVKM_PERFMON_H__
+
+#include <core/device.h>
+#include <core/engine.h>
+#include <core/engctx.h>
+#include <core/class.h>
+
+struct nouveau_perfdom;
+struct nouveau_perfctr;
+struct nouveau_perfmon {
+       struct nouveau_engine base;
+
+       struct nouveau_perfctx *context;
+       void *profile_data;
+
+       struct list_head domains;
+       u32 sequence;
+
+       /*XXX: temp for daemon backend */
+       u32 pwr[8];
+       u32 last;
+};
+
+static inline struct nouveau_perfmon *
+nouveau_perfmon(void *obj)
+{
+       return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_PERFMON];
+}
+
+extern struct nouveau_oclass *nv40_perfmon_oclass;
+extern struct nouveau_oclass *nv50_perfmon_oclass;
+extern struct nouveau_oclass *nv84_perfmon_oclass;
+extern struct nouveau_oclass *nva3_perfmon_oclass;
+extern struct nouveau_oclass nvc0_perfmon_oclass;
+extern struct nouveau_oclass nve0_perfmon_oclass;
+extern struct nouveau_oclass nvf0_perfmon_oclass;
+
+#endif
index 4579948..23a462b 100644 (file)
@@ -3,19 +3,10 @@
 
 #include <core/engine.h>
 #include <core/engctx.h>
-#include <core/event.h>
 
 struct nouveau_software_chan {
        struct nouveau_engctx base;
 
-       struct {
-               struct nouveau_eventh event;
-               u32 channel;
-               u32 ctxdma;
-               u64 offset;
-               u32 value;
-       } vblank;
-
        int (*flip)(void *);
        void *flip_data;
 };
@@ -50,10 +41,10 @@ struct nouveau_software {
 #define _nouveau_software_init _nouveau_engine_init
 #define _nouveau_software_fini _nouveau_engine_fini
 
-extern struct nouveau_oclass nv04_software_oclass;
-extern struct nouveau_oclass nv10_software_oclass;
-extern struct nouveau_oclass nv50_software_oclass;
-extern struct nouveau_oclass nvc0_software_oclass;
+extern struct nouveau_oclass *nv04_software_oclass;
+extern struct nouveau_oclass *nv10_software_oclass;
+extern struct nouveau_oclass *nv50_software_oclass;
+extern struct nouveau_oclass *nvc0_software_oclass;
 
 void nv04_software_intr(struct nouveau_subdev *);
 
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h
new file mode 100644 (file)
index 0000000..662b207
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __NVBIOS_BOOST_H__
+#define __NVBIOS_BOOST_H__
+
+u16 nvbios_boostTe(struct nouveau_bios *, u8 *, u8 *, u8 *, u8 *, u8 *, u8 *);
+
+struct nvbios_boostE {
+       u8  pstate;
+       u32 min;
+       u32 max;
+};
+
+u16 nvbios_boostEe(struct nouveau_bios *, int idx, u8 *, u8 *, u8 *, u8 *);
+u16 nvbios_boostEp(struct nouveau_bios *, int idx, u8 *, u8 *, u8 *, u8 *,
+                  struct nvbios_boostE *);
+u16 nvbios_boostEm(struct nouveau_bios *, u8, u8 *, u8 *, u8 *, u8 *,
+                  struct nvbios_boostE *);
+
+struct nvbios_boostS {
+       u8  domain;
+       u8  percent;
+       u32 min;
+       u32 max;
+};
+
+u16 nvbios_boostSe(struct nouveau_bios *, int, u16, u8 *, u8 *, u8, u8);
+u16 nvbios_boostSp(struct nouveau_bios *, int, u16, u8 *, u8 *, u8, u8,
+                  struct nvbios_boostS *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h
new file mode 100644 (file)
index 0000000..a80a438
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __NVBIOS_CSTEP_H__
+#define __NVBIOS_CSTEP_H__
+
+u16 nvbios_cstepTe(struct nouveau_bios *,
+                  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz);
+
+struct nvbios_cstepE {
+       u8  pstate;
+       u8  index;
+};
+
+u16 nvbios_cstepEe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
+u16 nvbios_cstepEp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
+                  struct nvbios_cstepE *);
+u16 nvbios_cstepEm(struct nouveau_bios *, u8 pstate, u8 *ver, u8 *hdr,
+                  struct nvbios_cstepE *);
+
+struct nvbios_cstepX {
+       u32 freq;
+       u8  unkn[2];
+       u8  voltage;
+};
+
+u16 nvbios_cstepXe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
+u16 nvbios_cstepXp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
+                  struct nvbios_cstepX *);
+
+#endif
index 96d3364..c7b2e58 100644 (file)
@@ -7,7 +7,15 @@ enum dcb_gpio_func_name {
        DCB_GPIO_TVDAC1 = 0x2d,
        DCB_GPIO_FAN = 0x09,
        DCB_GPIO_FAN_SENSE = 0x3d,
-       DCB_GPIO_UNUSED = 0xff
+       DCB_GPIO_UNUSED = 0xff,
+       DCB_GPIO_VID0 = 0x04,
+       DCB_GPIO_VID1 = 0x05,
+       DCB_GPIO_VID2 = 0x06,
+       DCB_GPIO_VID3 = 0x1a,
+       DCB_GPIO_VID4 = 0x73,
+       DCB_GPIO_VID5 = 0x74,
+       DCB_GPIO_VID6 = 0x75,
+       DCB_GPIO_VID7 = 0x76,
 };
 
 #define DCB_GPIO_LOG_DIR     0x02
index 0b285e9..16ff06e 100644 (file)
@@ -3,6 +3,39 @@
 
 struct nouveau_bios;
 
+u16 nvbios_perf_table(struct nouveau_bios *, u8 *ver, u8 *hdr,
+                     u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+
+struct nvbios_perfE {
+       u8  pstate;
+       u8  fanspeed;
+       u8  voltage;
+       u32 core;
+       u32 shader;
+       u32 memory;
+       u32 vdec;
+       u32 disp;
+       u32 script;
+};
+
+u16 nvbios_perf_entry(struct nouveau_bios *, int idx,
+                     u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_perfEp(struct nouveau_bios *, int idx,
+                 u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *);
+
+struct nvbios_perfS {
+       union {
+               struct {
+                       u32 freq;
+               } v40;
+       };
+};
+
+u32 nvbios_perfSe(struct nouveau_bios *, u32 data, int idx,
+                 u8 *ver, u8 *hdr, u8 cnt, u8 len);
+u32 nvbios_perfSp(struct nouveau_bios *, u32 data, int idx,
+                 u8 *ver, u8 *hdr, u8 cnt, u8 len, struct nvbios_perfS *);
+
 struct nvbios_perf_fan {
        u32 pwm_divisor;
 };
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h
new file mode 100644 (file)
index 0000000..bc15e03
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __NVBIOS_RAMMAP_H__
+#define __NVBIOS_RAMMAP_H__
+
+u16 nvbios_rammap_table(struct nouveau_bios *, u8 *ver, u8 *hdr,
+                       u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+u16 nvbios_rammap_entry(struct nouveau_bios *, int idx,
+                       u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_rammap_match(struct nouveau_bios *, u16 khz,
+                       u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h
new file mode 100644 (file)
index 0000000..963694b
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __NVBIOS_TIMING_H__
+#define __NVBIOS_TIMING_H__
+
+u16 nvbios_timing_table(struct nouveau_bios *,
+                       u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_timing_entry(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h
new file mode 100644 (file)
index 0000000..ad5a8f2
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __NVBIOS_VMAP_H__
+#define __NVBIOS_VMAP_H__
+
+struct nouveau_bios;
+
+struct nvbios_vmap {
+};
+
+u16 nvbios_vmap_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_vmap_parse(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+                     struct nvbios_vmap *);
+
+struct nvbios_vmap_entry {
+       u8  unk0;
+       u8  link;
+       u32 min;
+       u32 max;
+       s32 arg[6];
+};
+
+u16 nvbios_vmap_entry(struct nouveau_bios *, int idx, u8 *ver, u8 *len);
+u16 nvbios_vmap_entry_parse(struct nouveau_bios *, int idx, u8 *ver, u8 *len,
+                           struct nvbios_vmap_entry *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h
new file mode 100644 (file)
index 0000000..6a11dcd
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __NVBIOS_VOLT_H__
+#define __NVBIOS_VOLT_H__
+
+struct nouveau_bios;
+
+struct nvbios_volt {
+       u8  vidmask;
+       u32 min;
+       u32 max;
+       u32 base;
+       s16 step;
+};
+
+u16 nvbios_volt_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_volt_parse(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+                     struct nvbios_volt *);
+
+struct nvbios_volt_entry {
+       u32 voltage;
+       u8  vid;
+};
+
+u16 nvbios_volt_entry(struct nouveau_bios *, int idx, u8 *ver, u8 *len);
+u16 nvbios_volt_entry_parse(struct nouveau_bios *, int idx, u8 *ver, u8 *len,
+                           struct nvbios_volt_entry *);
+
+#endif
index 7d88ec4..697f7ce 100644 (file)
@@ -11,6 +11,8 @@ struct nouveau_bus_intr {
 
 struct nouveau_bus {
        struct nouveau_subdev base;
+       int (*hwsq_exec)(struct nouveau_bus *, u32 *, u32);
+       u32 hwsq_size;
 };
 
 static inline struct nouveau_bus *
@@ -33,9 +35,19 @@ nouveau_bus(void *obj)
 #define _nouveau_bus_init _nouveau_subdev_init
 #define _nouveau_bus_fini _nouveau_subdev_fini
 
-extern struct nouveau_oclass nv04_bus_oclass;
-extern struct nouveau_oclass nv31_bus_oclass;
-extern struct nouveau_oclass nv50_bus_oclass;
-extern struct nouveau_oclass nvc0_bus_oclass;
+extern struct nouveau_oclass *nv04_bus_oclass;
+extern struct nouveau_oclass *nv31_bus_oclass;
+extern struct nouveau_oclass *nv50_bus_oclass;
+extern struct nouveau_oclass *nv94_bus_oclass;
+extern struct nouveau_oclass *nvc0_bus_oclass;
+
+/* interface to sequencer */
+struct nouveau_hwsq;
+int  nouveau_hwsq_init(struct nouveau_bus *, struct nouveau_hwsq **);
+int  nouveau_hwsq_fini(struct nouveau_hwsq **, bool exec);
+void nouveau_hwsq_wr32(struct nouveau_hwsq *, u32 addr, u32 data);
+void nouveau_hwsq_setf(struct nouveau_hwsq *, u8 flag, int data);
+void nouveau_hwsq_wait(struct nouveau_hwsq *, u8 flag, u8 data);
+void nouveau_hwsq_nsec(struct nouveau_hwsq *, u32 nsec);
 
 #endif
index 89ee289..e2675bc 100644 (file)
@@ -7,9 +7,78 @@
 struct nouveau_pll_vals;
 struct nvbios_pll;
 
+enum nv_clk_src {
+       nv_clk_src_crystal,
+       nv_clk_src_href,
+
+       nv_clk_src_hclk,
+       nv_clk_src_hclkm3,
+       nv_clk_src_hclkm3d2,
+
+       nv_clk_src_host,
+
+       nv_clk_src_sppll0,
+       nv_clk_src_sppll1,
+
+       nv_clk_src_mpllsrcref,
+       nv_clk_src_mpllsrc,
+       nv_clk_src_mpll,
+       nv_clk_src_mdiv,
+
+       nv_clk_src_core,
+       nv_clk_src_shader,
+
+       nv_clk_src_mem,
+
+       nv_clk_src_gpc,
+       nv_clk_src_rop,
+       nv_clk_src_hubk01,
+       nv_clk_src_hubk06,
+       nv_clk_src_hubk07,
+       nv_clk_src_copy,
+       nv_clk_src_daemon,
+       nv_clk_src_disp,
+       nv_clk_src_vdec,
+
+       nv_clk_src_dom6,
+
+       nv_clk_src_max,
+};
+
+struct nouveau_cstate {
+       struct list_head head;
+       u8  voltage;
+       u32 domain[nv_clk_src_max];
+};
+
+struct nouveau_pstate {
+       struct list_head head;
+       struct list_head list; /* c-states */
+       struct nouveau_cstate base;
+       u8 pstate;
+       u8 fanspeed;
+};
+
 struct nouveau_clock {
        struct nouveau_subdev base;
 
+       struct nouveau_clocks *domains;
+       struct nouveau_pstate bstate;
+
+       struct list_head states;
+       int state_nr;
+
+       int pstate; /* current */
+       int ustate; /* user-requested (-1 disabled, -2 perfmon) */
+       int astate; /* perfmon adjustment (base) */
+       int tstate; /* thermal adjustment (max-) */
+       int dstate; /* display adjustment (min+) */
+
+       int  (*read)(struct nouveau_clock *, enum nv_clk_src);
+       int  (*calc)(struct nouveau_clock *, struct nouveau_cstate *);
+       int  (*prog)(struct nouveau_clock *);
+       void (*tidy)(struct nouveau_clock *);
+
        /*XXX: die, these are here *only* to support the completely
         *     bat-shit insane what-was-nouveau_hw.c code
         */
@@ -25,27 +94,42 @@ nouveau_clock(void *obj)
        return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_CLOCK];
 }
 
-#define nouveau_clock_create(p,e,o,d)                                          \
-       nouveau_subdev_create((p), (e), (o), 0, "CLOCK", "clock", d)
-#define nouveau_clock_destroy(p)                                               \
-       nouveau_subdev_destroy(&(p)->base)
-#define nouveau_clock_init(p)                                                  \
-       nouveau_subdev_init(&(p)->base)
+struct nouveau_clocks {
+       enum nv_clk_src name;
+       u8 bios; /* 0xff for none */
+#define NVKM_CLK_DOM_FLAG_CORE 0x01
+       u8 flags;
+       const char *mname;
+       int mdiv;
+};
+
+#define nouveau_clock_create(p,e,o,i,d)                                        \
+       nouveau_clock_create_((p), (e), (o), (i), sizeof(**d), (void **)d)
+#define nouveau_clock_destroy(p) ({                                            \
+       struct nouveau_clock *clk = (p);                                       \
+       _nouveau_clock_dtor(nv_object(clk));                                   \
+})
+#define nouveau_clock_init(p) ({                                               \
+       struct nouveau_clock *clk = (p);                                       \
+       _nouveau_clock_init(nv_object(clk));                                   \
+})
 #define nouveau_clock_fini(p,s)                                                \
        nouveau_subdev_fini(&(p)->base, (s))
 
 int  nouveau_clock_create_(struct nouveau_object *, struct nouveau_object *,
-                          struct nouveau_oclass *, void *, u32, int, void **);
-
-#define _nouveau_clock_dtor _nouveau_subdev_dtor
-#define _nouveau_clock_init _nouveau_subdev_init
+                          struct nouveau_oclass *,
+                          struct nouveau_clocks *, int, void **);
+void _nouveau_clock_dtor(struct nouveau_object *);
+int _nouveau_clock_init(struct nouveau_object *);
 #define _nouveau_clock_fini _nouveau_subdev_fini
 
 extern struct nouveau_oclass nv04_clock_oclass;
 extern struct nouveau_oclass nv40_clock_oclass;
-extern struct nouveau_oclass nv50_clock_oclass;
+extern struct nouveau_oclass *nv50_clock_oclass;
+extern struct nouveau_oclass *nv84_clock_oclass;
 extern struct nouveau_oclass nva3_clock_oclass;
 extern struct nouveau_oclass nvc0_clock_oclass;
+extern struct nouveau_oclass nve0_clock_oclass;
 
 int nv04_clock_pll_set(struct nouveau_clock *, u32 type, u32 freq);
 int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,
@@ -55,4 +139,9 @@ int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1,
 int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,
                        int clk, struct nouveau_pll_vals *);
 
+int nouveau_clock_ustate(struct nouveau_clock *, int req);
+int nouveau_clock_astate(struct nouveau_clock *, int req, int rel);
+int nouveau_clock_dstate(struct nouveau_clock *, int req, int rel);
+int nouveau_clock_tstate(struct nouveau_clock *, int req, int rel);
+
 #endif
index 2e74050..8541aa3 100644 (file)
@@ -78,23 +78,28 @@ nouveau_fb(void *obj)
        return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FB];
 }
 
-extern struct nouveau_oclass nv04_fb_oclass;
-extern struct nouveau_oclass nv10_fb_oclass;
-extern struct nouveau_oclass nv1a_fb_oclass;
-extern struct nouveau_oclass nv20_fb_oclass;
-extern struct nouveau_oclass nv25_fb_oclass;
-extern struct nouveau_oclass nv30_fb_oclass;
-extern struct nouveau_oclass nv35_fb_oclass;
-extern struct nouveau_oclass nv36_fb_oclass;
-extern struct nouveau_oclass nv40_fb_oclass;
-extern struct nouveau_oclass nv41_fb_oclass;
-extern struct nouveau_oclass nv44_fb_oclass;
-extern struct nouveau_oclass nv46_fb_oclass;
-extern struct nouveau_oclass nv47_fb_oclass;
-extern struct nouveau_oclass nv49_fb_oclass;
-extern struct nouveau_oclass nv4e_fb_oclass;
-extern struct nouveau_oclass nv50_fb_oclass;
-extern struct nouveau_oclass nvc0_fb_oclass;
+extern struct nouveau_oclass *nv04_fb_oclass;
+extern struct nouveau_oclass *nv10_fb_oclass;
+extern struct nouveau_oclass *nv1a_fb_oclass;
+extern struct nouveau_oclass *nv20_fb_oclass;
+extern struct nouveau_oclass *nv25_fb_oclass;
+extern struct nouveau_oclass *nv30_fb_oclass;
+extern struct nouveau_oclass *nv35_fb_oclass;
+extern struct nouveau_oclass *nv36_fb_oclass;
+extern struct nouveau_oclass *nv40_fb_oclass;
+extern struct nouveau_oclass *nv41_fb_oclass;
+extern struct nouveau_oclass *nv44_fb_oclass;
+extern struct nouveau_oclass *nv46_fb_oclass;
+extern struct nouveau_oclass *nv47_fb_oclass;
+extern struct nouveau_oclass *nv49_fb_oclass;
+extern struct nouveau_oclass *nv4e_fb_oclass;
+extern struct nouveau_oclass *nv50_fb_oclass;
+extern struct nouveau_oclass *nv84_fb_oclass;
+extern struct nouveau_oclass *nva3_fb_oclass;
+extern struct nouveau_oclass *nvaa_fb_oclass;
+extern struct nouveau_oclass *nvaf_fb_oclass;
+extern struct nouveau_oclass *nvc0_fb_oclass;
+extern struct nouveau_oclass *nve0_fb_oclass;
 
 struct nouveau_ram {
        struct nouveau_object base;
@@ -121,6 +126,17 @@ struct nouveau_ram {
        int  (*get)(struct nouveau_fb *, u64 size, u32 align,
                    u32 size_nc, u32 type, struct nouveau_mem **);
        void (*put)(struct nouveau_fb *, struct nouveau_mem **);
+
+       int  (*calc)(struct nouveau_fb *, u32 freq);
+       int  (*prog)(struct nouveau_fb *);
+       void (*tidy)(struct nouveau_fb *);
+       struct {
+               u8  version;
+               u32 data;
+               u8  size;
+       } rammap, ramcfg, timing;
+       u32 freq;
+       u32 mr[16];
 };
 
 #endif
index 7e4e277..9fa5da7 100644 (file)
@@ -60,13 +60,18 @@ void _nouveau_i2c_port_dtor(struct nouveau_object *);
 #define _nouveau_i2c_port_init nouveau_object_init
 #define _nouveau_i2c_port_fini nouveau_object_fini
 
+struct nouveau_i2c_board_info {
+       struct i2c_board_info dev;
+       u8 udelay; /* set to 0 to use the standard delay */
+};
+
 struct nouveau_i2c {
        struct nouveau_subdev base;
 
        struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
        struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
        int (*identify)(struct nouveau_i2c *, int index,
-                       const char *what, struct i2c_board_info *,
+                       const char *what, struct nouveau_i2c_board_info *,
                        bool (*match)(struct nouveau_i2c_port *,
                                      struct i2c_board_info *));
        struct list_head ports;
index ce6569f..adc88b7 100644 (file)
@@ -11,7 +11,6 @@ struct nouveau_mc_intr {
 
 struct nouveau_mc {
        struct nouveau_subdev base;
-       const struct nouveau_mc_intr *intr_map;
        bool use_msi;
 };
 
@@ -21,8 +20,8 @@ nouveau_mc(void *obj)
        return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC];
 }
 
-#define nouveau_mc_create(p,e,o,m,d)                                           \
-       nouveau_mc_create_((p), (e), (o), (m), sizeof(**d), (void **)d)
+#define nouveau_mc_create(p,e,o,d)                                             \
+       nouveau_mc_create_((p), (e), (o), sizeof(**d), (void **)d)
 #define nouveau_mc_destroy(p) ({                                               \
        struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc));        \
 })
@@ -34,20 +33,24 @@ nouveau_mc(void *obj)
 })
 
 int  nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *,
-                       struct nouveau_oclass *, const struct nouveau_mc_intr *,
-                       int, void **);
+                       struct nouveau_oclass *, int, void **);
 void _nouveau_mc_dtor(struct nouveau_object *);
 int  _nouveau_mc_init(struct nouveau_object *);
 int  _nouveau_mc_fini(struct nouveau_object *, bool);
 
-extern struct nouveau_oclass nv04_mc_oclass;
-extern struct nouveau_oclass nv44_mc_oclass;
-extern struct nouveau_oclass nv50_mc_oclass;
-extern struct nouveau_oclass nv98_mc_oclass;
-extern struct nouveau_oclass nvc0_mc_oclass;
+struct nouveau_mc_oclass {
+       struct nouveau_oclass base;
+       const struct nouveau_mc_intr *intr;
+       void (*msi_rearm)(struct nouveau_mc *);
+};
 
-extern const struct nouveau_mc_intr nv04_mc_intr[];
-int nv04_mc_init(struct nouveau_object *);
-int nv50_mc_init(struct nouveau_object *);
+extern struct nouveau_oclass *nv04_mc_oclass;
+extern struct nouveau_oclass *nv40_mc_oclass;
+extern struct nouveau_oclass *nv44_mc_oclass;
+extern struct nouveau_oclass *nv50_mc_oclass;
+extern struct nouveau_oclass *nv94_mc_oclass;
+extern struct nouveau_oclass *nv98_mc_oclass;
+extern struct nouveau_oclass *nvc0_mc_oclass;
+extern struct nouveau_oclass *nvc3_mc_oclass;
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h b/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h
new file mode 100644 (file)
index 0000000..c5c92cb
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef __NOUVEAU_PWR_H__
+#define __NOUVEAU_PWR_H__
+
+#include <core/subdev.h>
+#include <core/device.h>
+
+struct nouveau_pwr {
+       struct nouveau_subdev base;
+
+       struct {
+               u32 limit;
+               u32 *data;
+               u32  size;
+       } code;
+
+       struct {
+               u32 limit;
+               u32 *data;
+               u32  size;
+       } data;
+
+       struct {
+               u32 base;
+               u32 size;
+       } send;
+
+       struct {
+               u32 base;
+               u32 size;
+
+               struct work_struct work;
+               wait_queue_head_t wait;
+               u32 process;
+               u32 message;
+               u32 data[2];
+       } recv;
+
+       int (*message)(struct nouveau_pwr *, u32[2], u32, u32, u32, u32);
+};
+
+static inline struct nouveau_pwr *
+nouveau_pwr(void *obj)
+{
+       return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_PWR];
+}
+
+#define nouveau_pwr_create(p, e, o, d)                                         \
+       nouveau_pwr_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nouveau_pwr_destroy(p)                                                 \
+       nouveau_subdev_destroy(&(p)->base)
+#define nouveau_pwr_init(p) ({                                                 \
+       struct nouveau_pwr *ppwr = (p);                                        \
+       _nouveau_pwr_init(nv_object(ppwr));                                    \
+})
+#define nouveau_pwr_fini(p,s) ({                                               \
+       struct nouveau_pwr *ppwr = (p);                                        \
+       _nouveau_pwr_fini(nv_object(ppwr), (s));                               \
+})
+
+int nouveau_pwr_create_(struct nouveau_object *, struct nouveau_object *,
+                          struct nouveau_oclass *, int, void **);
+#define _nouveau_pwr_dtor _nouveau_subdev_dtor
+int _nouveau_pwr_init(struct nouveau_object *);
+int _nouveau_pwr_fini(struct nouveau_object *, bool);
+
+extern struct nouveau_oclass nva3_pwr_oclass;
+extern struct nouveau_oclass nvc0_pwr_oclass;
+extern struct nouveau_oclass nvd0_pwr_oclass;
+extern struct nouveau_oclass nv108_pwr_oclass;
+
+/* interface to MEMX process running on PPWR */
+struct nouveau_memx;
+int  nouveau_memx_init(struct nouveau_pwr *, struct nouveau_memx **);
+int  nouveau_memx_fini(struct nouveau_memx **, bool exec);
+void nouveau_memx_wr32(struct nouveau_memx *, u32 addr, u32 data);
+void nouveau_memx_wait(struct nouveau_memx *,
+                      u32 addr, u32 mask, u32 data, u32 nsec);
+void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec);
+
+#endif
index c075998..69891d4 100644 (file)
@@ -71,6 +71,8 @@ void _nouveau_therm_dtor(struct nouveau_object *);
 int  _nouveau_therm_init(struct nouveau_object *);
 int  _nouveau_therm_fini(struct nouveau_object *, bool);
 
+int  nouveau_therm_cstate(struct nouveau_therm *, int, int);
+
 extern struct nouveau_oclass nv40_therm_oclass;
 extern struct nouveau_oclass nv50_therm_oclass;
 extern struct nouveau_oclass nv84_therm_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/volt.h b/drivers/gpu/drm/nouveau/core/include/subdev/volt.h
new file mode 100644 (file)
index 0000000..820b62f
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __NOUVEAU_VOLT_H__
+#define __NOUVEAU_VOLT_H__
+
+#include <core/subdev.h>
+#include <core/device.h>
+
+struct nouveau_voltage {
+       u32 uv;
+       u8  id;
+};
+
+struct nouveau_volt {
+       struct nouveau_subdev base;
+
+       int (*vid_get)(struct nouveau_volt *);
+       int (*get)(struct nouveau_volt *);
+       int (*vid_set)(struct nouveau_volt *, u8 vid);
+       int (*set)(struct nouveau_volt *, u32 uv);
+       int (*set_id)(struct nouveau_volt *, u8 id, int condition);
+
+       u8 vid_mask;
+       u8 vid_nr;
+       struct {
+               u32 uv;
+               u8 vid;
+       } vid[256];
+};
+
+static inline struct nouveau_volt *
+nouveau_volt(void *obj)
+{
+       return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VOLT];
+}
+
+#define nouveau_volt_create(p, e, o, d)                                        \
+       nouveau_volt_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nouveau_volt_destroy(p) ({                                             \
+       struct nouveau_volt *v = (p);                                          \
+       _nouveau_volt_dtor(nv_object(v));                                      \
+})
+#define nouveau_volt_init(p) ({                                                \
+       struct nouveau_volt *v = (p);                                          \
+       _nouveau_volt_init(nv_object(v));                                      \
+})
+#define nouveau_volt_fini(p,s)                                                 \
+       nouveau_subdev_fini((p), (s))
+
+int  nouveau_volt_create_(struct nouveau_object *, struct nouveau_object *,
+                         struct nouveau_oclass *, int, void **);
+void _nouveau_volt_dtor(struct nouveau_object *);
+int  _nouveau_volt_init(struct nouveau_object *);
+#define _nouveau_volt_fini _nouveau_subdev_fini
+
+extern struct nouveau_oclass nv40_volt_oclass;
+
+int nouveau_voltgpio_init(struct nouveau_volt *);
+int nouveau_voltgpio_get(struct nouveau_volt *);
+int nouveau_voltgpio_set(struct nouveau_volt *, u8);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c b/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c
new file mode 100644 (file)
index 0000000..c1835e5
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/boost.h>
+
+u16
+nvbios_boostTe(struct nouveau_bios *bios,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+       struct bit_entry bit_P;
+       u16 boost = 0x0000;
+
+       if (!bit_entry(bios, 'P', &bit_P)) {
+               if (bit_P.version == 2)
+                       boost = nv_ro16(bios, bit_P.offset + 0x30);
+
+               if (boost) {
+                       *ver = nv_ro08(bios, boost + 0);
+                       switch (*ver) {
+                       case 0x11:
+                               *hdr = nv_ro08(bios, boost + 1);
+                               *cnt = nv_ro08(bios, boost + 5);
+                               *len = nv_ro08(bios, boost + 2);
+                               *snr = nv_ro08(bios, boost + 4);
+                               *ssz = nv_ro08(bios, boost + 3);
+                               return boost;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0x0000;
+}
+
+u16
+nvbios_boostEe(struct nouveau_bios *bios, int idx,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       u8  snr, ssz;
+       u16 data = nvbios_boostTe(bios, ver, hdr, cnt, len, &snr, &ssz);
+       if (data && idx < *cnt) {
+               data = data + *hdr + (idx * (*len + (snr * ssz)));
+               *hdr = *len;
+               *cnt = snr;
+               *len = ssz;
+               return data;
+       }
+       return 0x0000;
+}
+
+u16
+nvbios_boostEp(struct nouveau_bios *bios, int idx,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info)
+{
+       u16 data = nvbios_boostEe(bios, idx, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
+       if (data) {
+               info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5;
+               info->min    =  nv_ro16(bios, data + 0x02) * 1000;
+               info->max    =  nv_ro16(bios, data + 0x04) * 1000;
+       }
+       return data;
+}
+
+u16
+nvbios_boostEm(struct nouveau_bios *bios, u8 pstate,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info)
+{
+       u32 data, idx = 0;
+       while ((data = nvbios_boostEp(bios, idx++, ver, hdr, cnt, len, info))) {
+               if (info->pstate == pstate)
+                       break;
+       }
+       return data;
+}
+
+u16
+nvbios_boostSe(struct nouveau_bios *bios, int idx,
+              u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len)
+{
+       if (data && idx < cnt) {
+               data = data + *hdr + (idx * len);
+               *hdr = len;
+               return data;
+       }
+       return 0x0000;
+}
+
+u16
+nvbios_boostSp(struct nouveau_bios *bios, int idx,
+              u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len,
+              struct nvbios_boostS *info)
+{
+       data = nvbios_boostSe(bios, idx, data, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
+       if (data) {
+               info->domain  = nv_ro08(bios, data + 0x00);
+               info->percent = nv_ro08(bios, data + 0x01);
+               info->min     = nv_ro16(bios, data + 0x02) * 1000;
+               info->max     = nv_ro16(bios, data + 0x04) * 1000;
+       }
+       return data;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c b/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c
new file mode 100644 (file)
index 0000000..d3b1532
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/cstep.h>
+
+u16
+nvbios_cstepTe(struct nouveau_bios *bios,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz)
+{
+       struct bit_entry bit_P;
+       u16 cstep = 0x0000;
+
+       if (!bit_entry(bios, 'P', &bit_P)) {
+               if (bit_P.version == 2)
+                       cstep = nv_ro16(bios, bit_P.offset + 0x34);
+
+               if (cstep) {
+                       *ver = nv_ro08(bios, cstep + 0);
+                       switch (*ver) {
+                       case 0x10:
+                               *hdr = nv_ro08(bios, cstep + 1);
+                               *cnt = nv_ro08(bios, cstep + 3);
+                               *len = nv_ro08(bios, cstep + 2);
+                               *xnr = nv_ro08(bios, cstep + 5);
+                               *xsz = nv_ro08(bios, cstep + 4);
+                               return cstep;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0x0000;
+}
+
+u16
+nvbios_cstepEe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+       u8  cnt, len, xnr, xsz;
+       u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz);
+       if (data && idx < cnt) {
+               data = data + *hdr + (idx * len);
+               *hdr = len;
+               return data;
+       }
+       return 0x0000;
+}
+
+u16
+nvbios_cstepEp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
+              struct nvbios_cstepE *info)
+{
+       u16 data = nvbios_cstepEe(bios, idx, ver, hdr);
+       memset(info, 0x00, sizeof(*info));
+       if (data) {
+               info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5;
+               info->index   = nv_ro08(bios, data + 0x03);
+       }
+       return data;
+}
+
+u16
+nvbios_cstepEm(struct nouveau_bios *bios, u8 pstate, u8 *ver, u8 *hdr,
+              struct nvbios_cstepE *info)
+{
+       u32 data, idx = 0;
+       while ((data = nvbios_cstepEp(bios, idx++, ver, hdr, info))) {
+               if (info->pstate == pstate)
+                       break;
+       }
+       return data;
+}
+
+u16
+nvbios_cstepXe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+       u8  cnt, len, xnr, xsz;
+       u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz);
+       if (data && idx < xnr) {
+               data = data + *hdr + (cnt * len) + (idx * xsz);
+               *hdr = xsz;
+               return data;
+       }
+       return 0x0000;
+}
+
+u16
+nvbios_cstepXp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
+              struct nvbios_cstepX *info)
+{
+       u16 data = nvbios_cstepXe(bios, idx, ver, hdr);
+       memset(info, 0x00, sizeof(*info));
+       if (data) {
+               info->freq    = nv_ro16(bios, data + 0x00) * 1000;
+               info->unkn[0] = nv_ro08(bios, data + 0x02);
+               info->unkn[1] = nv_ro08(bios, data + 0x03);
+               info->voltage = nv_ro08(bios, data + 0x04);
+       }
+       return data;
+}
index 663853b..7628fe7 100644 (file)
@@ -89,6 +89,7 @@ nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx,
                   struct nvbios_dpout *info)
 {
        u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
        if (data && *ver) {
                info->type = nv_ro16(bios, data + 0x00);
                info->mask = nv_ro16(bios, data + 0x02);
@@ -99,9 +100,12 @@ nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx,
                        info->script[0] = nv_ro16(bios, data + 0x06);
                        info->script[1] = nv_ro16(bios, data + 0x08);
                        info->lnkcmp    = nv_ro16(bios, data + 0x0a);
-                       info->script[2] = nv_ro16(bios, data + 0x0c);
-                       info->script[3] = nv_ro16(bios, data + 0x0e);
-                       info->script[4] = nv_ro16(bios, data + 0x10);
+                       if (*len >= 0x0f) {
+                               info->script[2] = nv_ro16(bios, data + 0x0c);
+                               info->script[3] = nv_ro16(bios, data + 0x0e);
+                       }
+                       if (*len >= 0x11)
+                               info->script[4] = nv_ro16(bios, data + 0x10);
                        break;
                case 0x40:
                        info->flags     = nv_ro08(bios, data + 0x04);
index 57cda2a..420908c 100644 (file)
@@ -2180,7 +2180,7 @@ nvbios_init(struct nouveau_subdev *subdev, bool execute)
        u16 data;
 
        if (execute)
-               nv_suspend(bios, "running init tables\n");
+               nv_info(bios, "running init tables\n");
        while (!ret && (data = (init_script(bios, ++i)))) {
                struct nvbios_init init = {
                        .subdev = subdev,
@@ -2210,5 +2210,5 @@ nvbios_init(struct nouveau_subdev *subdev, bool execute)
                ret = nvbios_exec(&init);
        }
 
-       return 0;
+       return ret;
 }
index bcbb056..675e221 100644 (file)
@@ -26,8 +26,9 @@
 #include <subdev/bios/bit.h>
 #include <subdev/bios/perf.h>
 
-static u16
-perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+u16
+nvbios_perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr,
+                 u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
 {
        struct bit_entry bit_P;
        u16 perf = 0x0000;
@@ -38,10 +39,22 @@ perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
                        if (perf) {
                                *ver = nv_ro08(bios, perf + 0);
                                *hdr = nv_ro08(bios, perf + 1);
+                               if (*ver >= 0x40 && *ver < 0x41) {
+                                       *cnt = nv_ro08(bios, perf + 5);
+                                       *len = nv_ro08(bios, perf + 2);
+                                       *snr = nv_ro08(bios, perf + 4);
+                                       *ssz = nv_ro08(bios, perf + 3);
+                                       return perf;
+                               } else
+                               if (*ver >= 0x20 && *ver < 0x40) {
+                                       *cnt = nv_ro08(bios, perf + 2);
+                                       *len = nv_ro08(bios, perf + 3);
+                                       *snr = nv_ro08(bios, perf + 4);
+                                       *ssz = nv_ro08(bios, perf + 5);
+                                       return perf;
+                               }
                        }
-               } else
-                       nv_error(bios, "unknown offset for perf in BIT P %d\n",
-                               bit_P.version);
+               }
        }
 
        if (bios->bmp_offset) {
@@ -50,19 +63,132 @@ perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
                        if (perf) {
                                *hdr = nv_ro08(bios, perf + 0);
                                *ver = nv_ro08(bios, perf + 1);
+                               *cnt = nv_ro08(bios, perf + 2);
+                               *len = nv_ro08(bios, perf + 3);
+                               *snr = 0;
+                               *ssz = 0;
+                               return perf;
                        }
                }
        }
 
+       return 0x0000;
+}
+
+u16
+nvbios_perf_entry(struct nouveau_bios *bios, int idx,
+                 u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       u8  snr, ssz;
+       u16 perf = nvbios_perf_table(bios, ver, hdr, cnt, len, &snr, &ssz);
+       if (perf && idx < *cnt) {
+               perf = perf + *hdr + (idx * (*len + (snr * ssz)));
+               *hdr = *len;
+               *cnt = snr;
+               *len = ssz;
+               return perf;
+       }
+       return 0x0000;
+}
+
+u16
+nvbios_perfEp(struct nouveau_bios *bios, int idx,
+             u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+             struct nvbios_perfE *info)
+{
+       u16 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
+       info->pstate = nv_ro08(bios, perf + 0x00);
+       switch (!!perf * *ver) {
+       case 0x12:
+       case 0x13:
+       case 0x14:
+               info->core     = nv_ro32(bios, perf + 0x01) * 10;
+               info->memory   = nv_ro32(bios, perf + 0x05) * 20;
+               info->fanspeed = nv_ro08(bios, perf + 0x37);
+               if (*hdr > 0x38)
+                       info->voltage = nv_ro08(bios, perf + 0x38);
+               break;
+       case 0x21:
+       case 0x23:
+       case 0x24:
+               info->fanspeed = nv_ro08(bios, perf + 0x04);
+               info->voltage  = nv_ro08(bios, perf + 0x05);
+               info->shader   = nv_ro16(bios, perf + 0x06) * 1000;
+               info->core     = info->shader + (signed char)
+                                nv_ro08(bios, perf + 0x08) * 1000;
+               switch (nv_device(bios)->chipset) {
+               case 0x49:
+               case 0x4b:
+                       info->memory = nv_ro16(bios, perf + 0x0b) * 1000;
+                       break;
+               default:
+                       info->memory = nv_ro16(bios, perf + 0x0b) * 2000;
+                       break;
+               }
+               break;
+       case 0x25:
+               info->fanspeed = nv_ro08(bios, perf + 0x04);
+               info->voltage  = nv_ro08(bios, perf + 0x05);
+               info->core     = nv_ro16(bios, perf + 0x06) * 1000;
+               info->shader   = nv_ro16(bios, perf + 0x0a) * 1000;
+               info->memory   = nv_ro16(bios, perf + 0x0c) * 1000;
+               break;
+       case 0x30:
+               info->script   = nv_ro16(bios, perf + 0x02);
+       case 0x35:
+               info->fanspeed = nv_ro08(bios, perf + 0x06);
+               info->voltage  = nv_ro08(bios, perf + 0x07);
+               info->core     = nv_ro16(bios, perf + 0x08) * 1000;
+               info->shader   = nv_ro16(bios, perf + 0x0a) * 1000;
+               info->memory   = nv_ro16(bios, perf + 0x0c) * 1000;
+               info->vdec     = nv_ro16(bios, perf + 0x10) * 1000;
+               info->disp     = nv_ro16(bios, perf + 0x14) * 1000;
+               break;
+       case 0x40:
+               info->voltage  = nv_ro08(bios, perf + 0x02);
+               break;
+       default:
+               return 0x0000;
+       }
        return perf;
 }
 
+u32
+nvbios_perfSe(struct nouveau_bios *bios, u32 perfE, int idx,
+             u8 *ver, u8 *hdr, u8 cnt, u8 len)
+{
+       u32 data = 0x00000000;
+       if (idx < cnt) {
+               data = perfE + *hdr + (idx * len);
+               *hdr = len;
+       }
+       return data;
+}
+
+u32
+nvbios_perfSp(struct nouveau_bios *bios, u32 perfE, int idx,
+             u8 *ver, u8 *hdr, u8 cnt, u8 len,
+             struct nvbios_perfS *info)
+{
+       u32 data = nvbios_perfSe(bios, perfE, idx, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       case 0x40:
+               info->v40.freq = (nv_ro16(bios, data + 0x00) & 0x3fff) * 1000;
+               break;
+       default:
+               break;
+       }
+       return data;
+}
+
 int
 nvbios_perf_fan_parse(struct nouveau_bios *bios,
                      struct nvbios_perf_fan *fan)
 {
-       u8 ver = 0, hdr = 0, cnt = 0, len = 0;
-       u16 perf = perf_table(bios, &ver, &hdr, &cnt, &len);
+       u8  ver, hdr, cnt, len, snr, ssz;
+       u16 perf = nvbios_perf_table(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
        if (!perf)
                return -ENODEV;
 
index f835501..1f76de5 100644 (file)
@@ -114,6 +114,7 @@ pll_map(struct nouveau_bios *bios)
        switch (nv_device(bios)->card_type) {
        case NV_04:
        case NV_10:
+       case NV_11:
        case NV_20:
        case NV_30:
                return nv04_pll_mapping;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c
new file mode 100644 (file)
index 0000000..916fa9d
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/rammap.h>
+
+u16
+nvbios_rammap_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr,
+                   u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+       struct bit_entry bit_P;
+       u16 rammap = 0x0000;
+
+       if (!bit_entry(bios, 'P', &bit_P)) {
+               if (bit_P.version == 2)
+                       rammap = nv_ro16(bios, bit_P.offset + 4);
+
+               if (rammap) {
+                       *ver = nv_ro08(bios, rammap + 0);
+                       switch (*ver) {
+                       case 0x10:
+                       case 0x11:
+                               *hdr = nv_ro08(bios, rammap + 1);
+                               *cnt = nv_ro08(bios, rammap + 5);
+                               *len = nv_ro08(bios, rammap + 2);
+                               *snr = nv_ro08(bios, rammap + 4);
+                               *ssz = nv_ro08(bios, rammap + 3);
+                               return rammap;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0x0000;
+}
+
+u16
+nvbios_rammap_entry(struct nouveau_bios *bios, int idx,
+                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       u8  snr, ssz;
+       u16 rammap = nvbios_rammap_table(bios, ver, hdr, cnt, len, &snr, &ssz);
+       if (rammap && idx < *cnt) {
+               rammap = rammap + *hdr + (idx * (*len + (snr * ssz)));
+               *hdr = *len;
+               *cnt = snr;
+               *len = ssz;
+               return rammap;
+       }
+       return 0x0000;
+}
+
+u16
+nvbios_rammap_match(struct nouveau_bios *bios, u16 khz,
+                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       int idx = 0;
+       u32 data;
+       while ((data = nvbios_rammap_entry(bios, idx++, ver, hdr, cnt, len))) {
+               if (khz >= nv_ro16(bios, data + 0x00) &&
+                   khz <= nv_ro16(bios, data + 0x02))
+                       break;
+       }
+       return data;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c b/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c
new file mode 100644 (file)
index 0000000..151c2d6
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/timing.h>
+
+u16
+nvbios_timing_table(struct nouveau_bios *bios,
+                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       struct bit_entry bit_P;
+       u16 timing = 0x0000;
+
+       if (!bit_entry(bios, 'P', &bit_P)) {
+               if (bit_P.version == 1)
+                       timing = nv_ro16(bios, bit_P.offset + 4);
+               else
+               if (bit_P.version == 2)
+                       timing = nv_ro16(bios, bit_P.offset + 8);
+
+               if (timing) {
+                       *ver = nv_ro08(bios, timing + 0);
+                       switch (*ver) {
+                       case 0x10:
+                               *hdr = nv_ro08(bios, timing + 1);
+                               *cnt = nv_ro08(bios, timing + 2);
+                               *len = nv_ro08(bios, timing + 3);
+                               return timing;
+                       case 0x20:
+                               *hdr = nv_ro08(bios, timing + 1);
+                               *cnt = nv_ro08(bios, timing + 3);
+                               *len = nv_ro08(bios, timing + 2);
+                               return timing;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0x0000;
+}
+
+u16
+nvbios_timing_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
+{
+       u8  hdr, cnt;
+       u16 timing = nvbios_timing_table(bios, ver, &hdr, &cnt, len);
+       if (timing && idx < cnt)
+               return timing + hdr + (idx * *len);
+       return 0x0000;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c b/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c
new file mode 100644 (file)
index 0000000..f343a1b
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/vmap.h>
+
+u16
+nvbios_vmap_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       struct bit_entry bit_P;
+       u16 vmap = 0x0000;
+
+       if (!bit_entry(bios, 'P', &bit_P)) {
+               if (bit_P.version == 2) {
+                       vmap = nv_ro16(bios, bit_P.offset + 0x20);
+                       if (vmap) {
+                               *ver = nv_ro08(bios, vmap + 0);
+                               switch (*ver) {
+                               case 0x10:
+                               case 0x20:
+                                       *hdr = nv_ro08(bios, vmap + 1);
+                                       *cnt = nv_ro08(bios, vmap + 3);
+                                       *len = nv_ro08(bios, vmap + 2);
+                                       return vmap;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return 0x0000;
+}
+
+u16
+nvbios_vmap_parse(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+                 struct nvbios_vmap *info)
+{
+       u16 vmap = nvbios_vmap_table(bios, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!vmap * *ver) {
+       case 0x10:
+       case 0x20:
+               break;
+       }
+       return vmap;
+}
+
+u16
+nvbios_vmap_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
+{
+       u8  hdr, cnt;
+       u16 vmap = nvbios_vmap_table(bios, ver, &hdr, &cnt, len);
+       if (vmap && idx < cnt) {
+               vmap = vmap + hdr + (idx * *len);
+               return vmap;
+       }
+       return 0x0000;
+}
+
+u16
+nvbios_vmap_entry_parse(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len,
+                       struct nvbios_vmap_entry *info)
+{
+       u16 vmap = nvbios_vmap_entry(bios, idx, ver, len);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!vmap * *ver) {
+       case 0x10:
+               info->link   = 0xff;
+               info->min    = nv_ro32(bios, vmap + 0x00);
+               info->max    = nv_ro32(bios, vmap + 0x04);
+               info->arg[0] = nv_ro32(bios, vmap + 0x08);
+               info->arg[1] = nv_ro32(bios, vmap + 0x0c);
+               info->arg[2] = nv_ro32(bios, vmap + 0x10);
+               break;
+       case 0x20:
+               info->unk0   = nv_ro08(bios, vmap + 0x00);
+               info->link   = nv_ro08(bios, vmap + 0x01);
+               info->min    = nv_ro32(bios, vmap + 0x02);
+               info->max    = nv_ro32(bios, vmap + 0x06);
+               info->arg[0] = nv_ro32(bios, vmap + 0x0a);
+               info->arg[1] = nv_ro32(bios, vmap + 0x0e);
+               info->arg[2] = nv_ro32(bios, vmap + 0x12);
+               info->arg[3] = nv_ro32(bios, vmap + 0x16);
+               info->arg[4] = nv_ro32(bios, vmap + 0x1a);
+               info->arg[5] = nv_ro32(bios, vmap + 0x1e);
+               break;
+       }
+       return vmap;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c b/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c
new file mode 100644 (file)
index 0000000..bb590de
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/volt.h>
+
+u16
+nvbios_volt_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       struct bit_entry bit_P;
+       u16 volt = 0x0000;
+
+       if (!bit_entry(bios, 'P', &bit_P)) {
+               if (bit_P.version == 2)
+                       volt = nv_ro16(bios, bit_P.offset + 0x0c);
+               else
+               if (bit_P.version == 1)
+                       volt = nv_ro16(bios, bit_P.offset + 0x10);
+
+               if (volt) {
+                       *ver = nv_ro08(bios, volt + 0);
+                       switch (*ver) {
+                       case 0x12:
+                               *hdr = 5;
+                               *cnt = nv_ro08(bios, volt + 2);
+                               *len = nv_ro08(bios, volt + 1);
+                               return volt;
+                       case 0x20:
+                               *hdr = nv_ro08(bios, volt + 1);
+                               *cnt = nv_ro08(bios, volt + 2);
+                               *len = nv_ro08(bios, volt + 3);
+                               return volt;
+                       case 0x30:
+                       case 0x40:
+                       case 0x50:
+                               *hdr = nv_ro08(bios, volt + 1);
+                               *cnt = nv_ro08(bios, volt + 3);
+                               *len = nv_ro08(bios, volt + 2);
+                               return volt;
+                       }
+               }
+       }
+
+       return 0x0000;
+}
+
+u16
+nvbios_volt_parse(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+                 struct nvbios_volt *info)
+{
+       u16 volt = nvbios_volt_table(bios, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!volt * *ver) {
+       case 0x12:
+               info->vidmask = nv_ro08(bios, volt + 0x04);
+               break;
+       case 0x20:
+               info->vidmask = nv_ro08(bios, volt + 0x05);
+               break;
+       case 0x30:
+               info->vidmask = nv_ro08(bios, volt + 0x04);
+               break;
+       case 0x40:
+               info->base    = nv_ro32(bios, volt + 0x04);
+               info->step    = nv_ro16(bios, volt + 0x08);
+               info->vidmask = nv_ro08(bios, volt + 0x0b);
+               /*XXX*/
+               info->min     = 0;
+               info->max     = info->base;
+               break;
+       case 0x50:
+               info->vidmask = nv_ro08(bios, volt + 0x06);
+               info->min     = nv_ro32(bios, volt + 0x0a);
+               info->max     = nv_ro32(bios, volt + 0x0e);
+               info->base    = nv_ro32(bios, volt + 0x12) & 0x00ffffff;
+               info->step    = nv_ro16(bios, volt + 0x16);
+               break;
+       }
+       return volt;
+}
+
+u16
+nvbios_volt_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
+{
+       u8  hdr, cnt;
+       u16 volt = nvbios_volt_table(bios, ver, &hdr, &cnt, len);
+       if (volt && idx < cnt) {
+               volt = volt + hdr + (idx * *len);
+               return volt;
+       }
+       return 0x0000;
+}
+
+u16
+nvbios_volt_entry_parse(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len,
+                       struct nvbios_volt_entry *info)
+{
+       u16 volt = nvbios_volt_entry(bios, idx, ver, len);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!volt * *ver) {
+       case 0x12:
+       case 0x20:
+               info->voltage = nv_ro08(bios, volt + 0x00) * 10000;
+               info->vid     = nv_ro08(bios, volt + 0x01);
+               break;
+       case 0x30:
+               info->voltage = nv_ro08(bios, volt + 0x00) * 10000;
+               info->vid     = nv_ro08(bios, volt + 0x01) >> 2;
+               break;
+       case 0x40:
+       case 0x50:
+               break;
+       }
+       return volt;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c b/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c
new file mode 100644 (file)
index 0000000..f757470
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include <subdev/timer.h>
+#include <subdev/bus.h>
+
+struct nouveau_hwsq {
+       struct nouveau_bus *pbus;
+       u32 addr;
+       u32 data;
+       struct {
+               u8 data[512];
+               u8 size;
+       } c;
+};
+
+static void
+hwsq_cmd(struct nouveau_hwsq *hwsq, int size, u8 data[])
+{
+       memcpy(&hwsq->c.data[hwsq->c.size], data, size * sizeof(data[0]));
+       hwsq->c.size += size;
+}
+
+int
+nouveau_hwsq_init(struct nouveau_bus *pbus, struct nouveau_hwsq **phwsq)
+{
+       struct nouveau_hwsq *hwsq;
+
+       hwsq = *phwsq = kmalloc(sizeof(*hwsq), GFP_KERNEL);
+       if (hwsq) {
+               hwsq->pbus = pbus;
+               hwsq->addr = ~0;
+               hwsq->data = ~0;
+               memset(hwsq->c.data, 0x7f, sizeof(hwsq->c.data));
+               hwsq->c.size = 0;
+       }
+
+       return hwsq ? 0 : -ENOMEM;
+}
+
+int
+nouveau_hwsq_fini(struct nouveau_hwsq **phwsq, bool exec)
+{
+       struct nouveau_hwsq *hwsq = *phwsq;
+       int ret = 0, i;
+       if (hwsq) {
+               struct nouveau_bus *pbus = hwsq->pbus;
+               hwsq->c.size = (hwsq->c.size + 4) / 4;
+               if (hwsq->c.size <= pbus->hwsq_size) {
+                       if (exec)
+                               ret = pbus->hwsq_exec(pbus, (u32 *)hwsq->c.data,
+                                                     hwsq->c.size);
+                       if (ret)
+                               nv_error(pbus, "hwsq exec failed: %d\n", ret);
+               } else {
+                       nv_error(pbus, "hwsq ucode too large\n");
+                       ret = -ENOSPC;
+               }
+
+               for (i = 0; ret && i < hwsq->c.size; i++)
+                       nv_error(pbus, "\t0x%08x\n", ((u32 *)hwsq->c.data)[i]);
+
+               *phwsq = NULL;
+               kfree(hwsq);
+       }
+       return ret;
+}
+
+void
+nouveau_hwsq_wr32(struct nouveau_hwsq *hwsq, u32 addr, u32 data)
+{
+       nv_debug(hwsq->pbus, "R[%06x] = 0x%08x\n", addr, data);
+
+       if (hwsq->data != data) {
+               if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) {
+                       hwsq_cmd(hwsq, 5, (u8[]){ 0xe2, data, data >> 8,
+                                                 data >> 16, data >> 24 });
+               } else {
+                       hwsq_cmd(hwsq, 3, (u8[]){ 0x42, data, data >> 8 });
+               }
+       }
+
+       if ((addr & 0xffff0000) != (hwsq->addr & 0xffff0000)) {
+               hwsq_cmd(hwsq, 5, (u8[]){ 0xe0, addr, addr >> 8,
+                                         addr >> 16, addr >> 24 });
+       } else {
+               hwsq_cmd(hwsq, 3, (u8[]){ 0x40, addr, addr >> 8 });
+       }
+
+       hwsq->addr = addr;
+       hwsq->data = data;
+}
+
+void
+nouveau_hwsq_setf(struct nouveau_hwsq *hwsq, u8 flag, int data)
+{
+       nv_debug(hwsq->pbus, " FLAG[%02x] = %d\n", flag, data);
+       flag += 0x80;
+       if (data >= 0)
+               flag += 0x20;
+       if (data >= 1)
+               flag += 0x20;
+       hwsq_cmd(hwsq, 1, (u8[]){ flag });
+}
+
+void
+nouveau_hwsq_wait(struct nouveau_hwsq *hwsq, u8 flag, u8 data)
+{
+       nv_debug(hwsq->pbus, " WAIT[%02x] = %d\n", flag, data);
+       hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data });
+}
+
+void
+nouveau_hwsq_nsec(struct nouveau_hwsq *hwsq, u32 nsec)
+{
+       u8 shift = 0, usec = nsec / 1000;
+       while (usec & ~3) {
+               usec >>= 2;
+               shift++;
+       }
+
+       nv_debug(hwsq->pbus, "    DELAY = %d ns\n", nsec);
+       hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec });
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h b/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h
new file mode 100644 (file)
index 0000000..12176f9
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef __NVKM_BUS_HWSQ_H__
+#define __NVKM_BUS_HWSQ_H__
+
+#include <subdev/bus.h>
+
+struct hwsq {
+       struct nouveau_subdev *subdev;
+       struct nouveau_hwsq *hwsq;
+       int sequence;
+};
+
+struct hwsq_reg {
+       int sequence;
+       bool force;
+       u32 addr[2];
+       u32 data;
+};
+
+static inline struct hwsq_reg
+hwsq_reg2(u32 addr1, u32 addr2)
+{
+       return (struct hwsq_reg) {
+               .sequence = 0,
+               .force = 0,
+               .addr = { addr1, addr2 },
+               .data = 0xdeadbeef,
+       };
+}
+
+static inline struct hwsq_reg
+hwsq_reg(u32 addr)
+{
+       return hwsq_reg2(addr, addr);
+}
+
+static inline int
+hwsq_init(struct hwsq *ram, struct nouveau_subdev *subdev)
+{
+       struct nouveau_bus *pbus = nouveau_bus(subdev);
+       int ret;
+
+       ret = nouveau_hwsq_init(pbus, &ram->hwsq);
+       if (ret)
+               return ret;
+
+       ram->sequence++;
+       ram->subdev = subdev;
+       return 0;
+}
+
+static inline int
+hwsq_exec(struct hwsq *ram, bool exec)
+{
+       int ret = 0;
+       if (ram->subdev) {
+               ret = nouveau_hwsq_fini(&ram->hwsq, exec);
+               ram->subdev = NULL;
+       }
+       return ret;
+}
+
+static inline u32
+hwsq_rd32(struct hwsq *ram, struct hwsq_reg *reg)
+{
+       if (reg->sequence != ram->sequence)
+               reg->data = nv_rd32(ram->subdev, reg->addr[0]);
+       return reg->data;
+}
+
+static inline void
+hwsq_wr32(struct hwsq *ram, struct hwsq_reg *reg, u32 data)
+{
+       reg->sequence = ram->sequence;
+       reg->data = data;
+       if (reg->addr[0] != reg->addr[1])
+               nouveau_hwsq_wr32(ram->hwsq, reg->addr[1], reg->data);
+       nouveau_hwsq_wr32(ram->hwsq, reg->addr[0], reg->data);
+}
+
+static inline void
+hwsq_nuke(struct hwsq *ram, struct hwsq_reg *reg)
+{
+       reg->force = true;
+}
+
+static inline u32
+hwsq_mask(struct hwsq *ram, struct hwsq_reg *reg, u32 mask, u32 data)
+{
+       u32 temp = hwsq_rd32(ram, reg);
+       if (temp != ((temp & ~mask) | data) || reg->force)
+               hwsq_wr32(ram, reg, (temp & ~mask) | data);
+       return temp;
+}
+
+static inline void
+hwsq_setf(struct hwsq *ram, u8 flag, int data)
+{
+       nouveau_hwsq_setf(ram->hwsq, flag, data);
+}
+
+static inline void
+hwsq_wait(struct hwsq *ram, u8 flag, u8 data)
+{
+       nouveau_hwsq_wait(ram->hwsq, flag, data);
+}
+
+static inline void
+hwsq_nsec(struct hwsq *ram, u32 nsec)
+{
+       nouveau_hwsq_nsec(ram->hwsq, nsec);
+}
+
+#endif
index 8c7f805..23921b5 100644 (file)
  *          Ben Skeggs
  */
 
-#include <subdev/bus.h>
-
-struct nv04_bus_priv {
-       struct nouveau_bus base;
-};
+#include "nv04.h"
 
 static void
 nv04_bus_intr(struct nouveau_subdev *subdev)
@@ -56,10 +52,22 @@ nv04_bus_intr(struct nouveau_subdev *subdev)
 }
 
 static int
+nv04_bus_init(struct nouveau_object *object)
+{
+       struct nv04_bus_priv *priv = (void *)object;
+
+       nv_wr32(priv, 0x001100, 0xffffffff);
+       nv_wr32(priv, 0x001140, 0x00000111);
+
+       return nouveau_bus_init(&priv->base);
+}
+
+int
 nv04_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
              struct nouveau_oclass *oclass, void *data, u32 size,
              struct nouveau_object **pobject)
 {
+       struct nv04_bus_impl *impl = (void *)oclass;
        struct nv04_bus_priv *priv;
        int ret;
 
@@ -68,28 +76,20 @@ nv04_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_subdev(priv)->intr = nv04_bus_intr;
+       nv_subdev(priv)->intr = impl->intr;
+       priv->base.hwsq_exec = impl->hwsq_exec;
+       priv->base.hwsq_size = impl->hwsq_size;
        return 0;
 }
 
-static int
-nv04_bus_init(struct nouveau_object *object)
-{
-       struct nv04_bus_priv *priv = (void *)object;
-
-       nv_wr32(priv, 0x001100, 0xffffffff);
-       nv_wr32(priv, 0x001140, 0x00000111);
-
-       return nouveau_bus_init(&priv->base);
-}
-
-struct nouveau_oclass
-nv04_bus_oclass = {
-       .handle = NV_SUBDEV(BUS, 0x04),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv04_bus_oclass = &(struct nv04_bus_impl) {
+       .base.handle = NV_SUBDEV(BUS, 0x04),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv04_bus_ctor,
                .dtor = _nouveau_bus_dtor,
                .init = nv04_bus_init,
                .fini = _nouveau_bus_fini,
        },
-};
+       .intr = nv04_bus_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h
new file mode 100644 (file)
index 0000000..4d76024
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __NVKM_BUS_NV04_H__
+#define __NVKM_BUS_NV04_H__
+
+#include <subdev/bus.h>
+
+struct nv04_bus_priv {
+       struct nouveau_bus base;
+};
+
+int  nv04_bus_ctor(struct nouveau_object *, struct nouveau_object *,
+                  struct nouveau_oclass *, void *, u32,
+                  struct nouveau_object **);
+int  nv50_bus_init(struct nouveau_object *);
+void nv50_bus_intr(struct nouveau_subdev *);
+
+struct nv04_bus_impl {
+       struct nouveau_oclass base;
+       void (*intr)(struct nouveau_subdev *);
+       int  (*hwsq_exec)(struct nouveau_bus *, u32 *, u32);
+       u32  hwsq_size;
+};
+
+#endif
index 34132ae..94da46f 100644 (file)
  *          Ben Skeggs
  */
 
-#include <subdev/bus.h>
-
-struct nv31_bus_priv {
-       struct nouveau_bus base;
-};
+#include "nv04.h"
 
 static void
 nv31_bus_intr(struct nouveau_subdev *subdev)
@@ -71,7 +67,7 @@ nv31_bus_intr(struct nouveau_subdev *subdev)
 static int
 nv31_bus_init(struct nouveau_object *object)
 {
-       struct nv31_bus_priv *priv = (void *)object;
+       struct nv04_bus_priv *priv = (void *)object;
        int ret;
 
        ret = nouveau_bus_init(&priv->base);
@@ -83,30 +79,14 @@ nv31_bus_init(struct nouveau_object *object)
        return 0;
 }
 
-static int
-nv31_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-             struct nouveau_oclass *oclass, void *data, u32 size,
-             struct nouveau_object **pobject)
-{
-       struct nv31_bus_priv *priv;
-       int ret;
-
-       ret = nouveau_bus_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       nv_subdev(priv)->intr = nv31_bus_intr;
-       return 0;
-}
-
-struct nouveau_oclass
-nv31_bus_oclass = {
-       .handle = NV_SUBDEV(BUS, 0x31),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv31_bus_ctor,
+struct nouveau_oclass *
+nv31_bus_oclass = &(struct nv04_bus_impl) {
+       .base.handle = NV_SUBDEV(BUS, 0x31),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_bus_ctor,
                .dtor = _nouveau_bus_dtor,
                .init = nv31_bus_init,
                .fini = _nouveau_bus_fini,
        },
-};
+       .intr = nv31_bus_intr,
+}.base;
index f5b2117..11918f7 100644 (file)
  *          Ben Skeggs
  */
 
-#include <subdev/bus.h>
+#include <subdev/timer.h>
 
-struct nv50_bus_priv {
-       struct nouveau_bus base;
-};
+#include "nv04.h"
 
-static void
+static int
+nv50_bus_hwsq_exec(struct nouveau_bus *pbus, u32 *data, u32 size)
+{
+       struct nv50_bus_priv *priv = (void *)pbus;
+       int i;
+
+       nv_mask(pbus, 0x001098, 0x00000008, 0x00000000);
+       nv_wr32(pbus, 0x001304, 0x00000000);
+       for (i = 0; i < size; i++)
+               nv_wr32(priv, 0x001400 + (i * 4), data[i]);
+       nv_mask(pbus, 0x001098, 0x00000018, 0x00000018);
+       nv_wr32(pbus, 0x00130c, 0x00000003);
+
+       return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT;
+}
+
+void
 nv50_bus_intr(struct nouveau_subdev *subdev)
 {
        struct nouveau_bus *pbus = nouveau_bus(subdev);
@@ -61,10 +75,10 @@ nv50_bus_intr(struct nouveau_subdev *subdev)
        }
 }
 
-static int
+int
 nv50_bus_init(struct nouveau_object *object)
 {
-       struct nv50_bus_priv *priv = (void *)object;
+       struct nv04_bus_priv *priv = (void *)object;
        int ret;
 
        ret = nouveau_bus_init(&priv->base);
@@ -76,30 +90,16 @@ nv50_bus_init(struct nouveau_object *object)
        return 0;
 }
 
-static int
-nv50_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-             struct nouveau_oclass *oclass, void *data, u32 size,
-             struct nouveau_object **pobject)
-{
-       struct nv50_bus_priv *priv;
-       int ret;
-
-       ret = nouveau_bus_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       nv_subdev(priv)->intr = nv50_bus_intr;
-       return 0;
-}
-
-struct nouveau_oclass
-nv50_bus_oclass = {
-       .handle = NV_SUBDEV(BUS, 0x50),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv50_bus_ctor,
+struct nouveau_oclass *
+nv50_bus_oclass = &(struct nv04_bus_impl) {
+       .base.handle = NV_SUBDEV(BUS, 0x50),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_bus_ctor,
                .dtor = _nouveau_bus_dtor,
                .init = nv50_bus_init,
                .fini = _nouveau_bus_fini,
        },
-};
+       .intr = nv50_bus_intr,
+       .hwsq_exec = nv50_bus_hwsq_exec,
+       .hwsq_size = 64,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c
new file mode 100644 (file)
index 0000000..d365905
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ *          Ben Skeggs
+ */
+
+#include <subdev/timer.h>
+
+#include "nv04.h"
+
+static int
+nv94_bus_hwsq_exec(struct nouveau_bus *pbus, u32 *data, u32 size)
+{
+       struct nv50_bus_priv *priv = (void *)pbus;
+       int i;
+
+       nv_mask(pbus, 0x001098, 0x00000008, 0x00000000);
+       nv_wr32(pbus, 0x001304, 0x00000000);
+       nv_wr32(pbus, 0x001318, 0x00000000);
+       for (i = 0; i < size; i++)
+               nv_wr32(priv, 0x080000 + (i * 4), data[i]);
+       nv_mask(pbus, 0x001098, 0x00000018, 0x00000018);
+       nv_wr32(pbus, 0x00130c, 0x00000001);
+
+       return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT;
+}
+
+struct nouveau_oclass *
+nv94_bus_oclass = &(struct nv04_bus_impl) {
+       .base.handle = NV_SUBDEV(BUS, 0x94),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_bus_ctor,
+               .dtor = _nouveau_bus_dtor,
+               .init = nv50_bus_init,
+               .fini = _nouveau_bus_fini,
+       },
+       .intr = nv50_bus_intr,
+       .hwsq_exec = nv94_bus_hwsq_exec,
+       .hwsq_size = 128,
+}.base;
index b192d62..73839d7 100644 (file)
  *          Ben Skeggs
  */
 
-#include <subdev/bus.h>
-
-struct nvc0_bus_priv {
-       struct nouveau_bus base;
-};
+#include "nv04.h"
 
 static void
 nvc0_bus_intr(struct nouveau_subdev *subdev)
@@ -60,7 +56,7 @@ nvc0_bus_intr(struct nouveau_subdev *subdev)
 static int
 nvc0_bus_init(struct nouveau_object *object)
 {
-       struct nvc0_bus_priv *priv = (void *)object;
+       struct nv04_bus_priv *priv = (void *)object;
        int ret;
 
        ret = nouveau_bus_init(&priv->base);
@@ -72,30 +68,14 @@ nvc0_bus_init(struct nouveau_object *object)
        return 0;
 }
 
-static int
-nvc0_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-             struct nouveau_oclass *oclass, void *data, u32 size,
-             struct nouveau_object **pobject)
-{
-       struct nvc0_bus_priv *priv;
-       int ret;
-
-       ret = nouveau_bus_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       nv_subdev(priv)->intr = nvc0_bus_intr;
-       return 0;
-}
-
-struct nouveau_oclass
-nvc0_bus_oclass = {
-       .handle = NV_SUBDEV(BUS, 0xc0),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nvc0_bus_ctor,
+struct nouveau_oclass *
+nvc0_bus_oclass = &(struct nv04_bus_impl) {
+       .base.handle = NV_SUBDEV(BUS, 0xc0),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_bus_ctor,
                .dtor = _nouveau_bus_dtor,
                .init = nvc0_bus_init,
                .fini = _nouveau_bus_fini,
        },
-};
+       .intr = nvc0_bus_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/base.c b/drivers/gpu/drm/nouveau/core/subdev/clock/base.c
new file mode 100644 (file)
index 0000000..e2938a2
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <core/option.h>
+
+#include <subdev/clock.h>
+#include <subdev/therm.h>
+#include <subdev/volt.h>
+#include <subdev/fb.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/boost.h>
+#include <subdev/bios/cstep.h>
+#include <subdev/bios/perf.h>
+
+/******************************************************************************
+ * misc
+ *****************************************************************************/
+static u32
+nouveau_clock_adjust(struct nouveau_clock *clk, bool adjust,
+                    u8 pstate, u8 domain, u32 input)
+{
+       struct nouveau_bios *bios = nouveau_bios(clk);
+       struct nvbios_boostE boostE;
+       u8  ver, hdr, cnt, len;
+       u16 data;
+
+       data = nvbios_boostEm(bios, pstate, &ver, &hdr, &cnt, &len, &boostE);
+       if (data) {
+               struct nvbios_boostS boostS;
+               u8  idx = 0, sver, shdr;
+               u16 subd;
+
+               input = max(boostE.min, input);
+               input = min(boostE.max, input);
+               do {
+                       sver = ver;
+                       shdr = hdr;
+                       subd = nvbios_boostSp(bios, idx++, data, &sver, &shdr,
+                                             cnt, len, &boostS);
+                       if (subd && boostS.domain == domain) {
+                               if (adjust)
+                                       input = input * boostS.percent / 100;
+                               input = max(boostS.min, input);
+                               input = min(boostS.max, input);
+                               break;
+                       }
+               } while (subd);
+       }
+
+       return input;
+}
+
+/******************************************************************************
+ * C-States
+ *****************************************************************************/
+static int
+nouveau_cstate_prog(struct nouveau_clock *clk,
+                   struct nouveau_pstate *pstate, int cstatei)
+{
+       struct nouveau_therm *ptherm = nouveau_therm(clk);
+       struct nouveau_volt *volt = nouveau_volt(clk);
+       struct nouveau_cstate *cstate;
+       int ret;
+
+       if (!list_empty(&pstate->list)) {
+               cstate = list_entry(pstate->list.prev, typeof(*cstate), head);
+       } else {
+               cstate = &pstate->base;
+       }
+
+       ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, +1);
+       if (ret && ret != -ENODEV) {
+               nv_error(clk, "failed to raise fan speed: %d\n", ret);
+               return ret;
+       }
+
+       ret = volt->set_id(volt, cstate->voltage, +1);
+       if (ret && ret != -ENODEV) {
+               nv_error(clk, "failed to raise voltage: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk->calc(clk, cstate);
+       if (ret == 0) {
+               ret = clk->prog(clk);
+               clk->tidy(clk);
+       }
+
+       ret = volt->set_id(volt, cstate->voltage, -1);
+       if (ret && ret != -ENODEV)
+               nv_error(clk, "failed to lower voltage: %d\n", ret);
+
+       ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, -1);
+       if (ret && ret != -ENODEV)
+               nv_error(clk, "failed to lower fan speed: %d\n", ret);
+
+       return 0;
+}
+
+static void
+nouveau_cstate_del(struct nouveau_cstate *cstate)
+{
+       list_del(&cstate->head);
+       kfree(cstate);
+}
+
+static int
+nouveau_cstate_new(struct nouveau_clock *clk, int idx,
+                  struct nouveau_pstate *pstate)
+{
+       struct nouveau_bios *bios = nouveau_bios(clk);
+       struct nouveau_clocks *domain = clk->domains;
+       struct nouveau_cstate *cstate = NULL;
+       struct nvbios_cstepX cstepX;
+       u8  ver, hdr;
+       u16 data;
+
+       data = nvbios_cstepXp(bios, idx, &ver, &hdr, &cstepX);
+       if (!data)
+               return -ENOENT;
+
+       cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
+       if (!cstate)
+               return -ENOMEM;
+
+       *cstate = pstate->base;
+       cstate->voltage = cstepX.voltage;
+
+       while (domain && domain->name != nv_clk_src_max) {
+               if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
+                       u32 freq = nouveau_clock_adjust(clk, true,
+                                                       pstate->pstate,
+                                                       domain->bios,
+                                                       cstepX.freq);
+                       cstate->domain[domain->name] = freq;
+               }
+               domain++;
+       }
+
+       list_add(&cstate->head, &pstate->list);
+       return 0;
+}
+
+/******************************************************************************
+ * P-States
+ *****************************************************************************/
+static int
+nouveau_pstate_prog(struct nouveau_clock *clk, int pstatei)
+{
+       struct nouveau_fb *pfb = nouveau_fb(clk);
+       struct nouveau_pstate *pstate;
+       int ret, idx = 0;
+
+       list_for_each_entry(pstate, &clk->states, head) {
+               if (idx++ == pstatei)
+                       break;
+       }
+
+       nv_debug(clk, "setting performance state %d\n", pstatei);
+       clk->pstate = pstatei;
+
+       if (pfb->ram->calc) {
+               ret = pfb->ram->calc(pfb, pstate->base.domain[nv_clk_src_mem]);
+               if (ret == 0)
+                       ret = pfb->ram->prog(pfb);
+               pfb->ram->tidy(pfb);
+       }
+
+       return nouveau_cstate_prog(clk, pstate, 0);
+}
+
+static int
+nouveau_pstate_calc(struct nouveau_clock *clk)
+{
+       int pstate, ret = 0;
+
+       nv_trace(clk, "P %d U %d A %d T %d D %d\n", clk->pstate,
+                clk->ustate, clk->astate, clk->tstate, clk->dstate);
+
+       if (clk->state_nr && clk->ustate != -1) {
+               pstate = (clk->ustate < 0) ? clk->astate : clk->ustate;
+               pstate = min(pstate, clk->state_nr - 1 - clk->tstate);
+               pstate = max(pstate, clk->dstate);
+       } else {
+               pstate = clk->pstate = -1;
+       }
+
+       nv_trace(clk, "-> %d\n", pstate);
+       if (pstate != clk->pstate)
+               ret = nouveau_pstate_prog(clk, pstate);
+       return ret;
+}
+
+static void
+nouveau_pstate_info(struct nouveau_clock *clk, struct nouveau_pstate *pstate)
+{
+       struct nouveau_clocks *clock = clk->domains - 1;
+       struct nouveau_cstate *cstate;
+       char info[3][32] = { "", "", "" };
+       char name[4] = "--";
+       int i = -1;
+
+       if (pstate->pstate != 0xff)
+               snprintf(name, sizeof(name), "%02x", pstate->pstate);
+
+       while ((++clock)->name != nv_clk_src_max) {
+               u32 lo = pstate->base.domain[clock->name];
+               u32 hi = lo;
+               if (hi == 0)
+                       continue;
+
+               nv_debug(clk, "%02x: %10d KHz\n", clock->name, lo);
+               list_for_each_entry(cstate, &pstate->list, head) {
+                       u32 freq = cstate->domain[clock->name];
+                       lo = min(lo, freq);
+                       hi = max(hi, freq);
+                       nv_debug(clk, "%10d KHz\n", freq);
+               }
+
+               if (clock->mname && ++i < ARRAY_SIZE(info)) {
+                       lo /= clock->mdiv;
+                       hi /= clock->mdiv;
+                       if (lo == hi) {
+                               snprintf(info[i], sizeof(info[i]), "%s %d MHz",
+                                        clock->mname, lo);
+                       } else {
+                               snprintf(info[i], sizeof(info[i]),
+                                        "%s %d-%d MHz", clock->mname, lo, hi);
+                       }
+               }
+       }
+
+       nv_info(clk, "%s: %s %s %s\n", name, info[0], info[1], info[2]);
+}
+
+static void
+nouveau_pstate_del(struct nouveau_pstate *pstate)
+{
+       struct nouveau_cstate *cstate, *temp;
+
+       list_for_each_entry_safe(cstate, temp, &pstate->list, head) {
+               nouveau_cstate_del(cstate);
+       }
+
+       list_del(&pstate->head);
+       kfree(pstate);
+}
+
+static int
+nouveau_pstate_new(struct nouveau_clock *clk, int idx)
+{
+       struct nouveau_bios *bios = nouveau_bios(clk);
+       struct nouveau_clocks *domain = clk->domains - 1;
+       struct nouveau_pstate *pstate;
+       struct nouveau_cstate *cstate;
+       struct nvbios_cstepE cstepE;
+       struct nvbios_perfE perfE;
+       u8  ver, hdr, cnt, len;
+       u16 data;
+
+       data = nvbios_perfEp(bios, idx, &ver, &hdr, &cnt, &len, &perfE);
+       if (!data)
+               return -EINVAL;
+       if (perfE.pstate == 0xff)
+               return 0;
+
+       pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
+       cstate = &pstate->base;
+       if (!pstate)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&pstate->list);
+
+       pstate->pstate = perfE.pstate;
+       pstate->fanspeed = perfE.fanspeed;
+       cstate->voltage = perfE.voltage;
+       cstate->domain[nv_clk_src_core] = perfE.core;
+       cstate->domain[nv_clk_src_shader] = perfE.shader;
+       cstate->domain[nv_clk_src_mem] = perfE.memory;
+       cstate->domain[nv_clk_src_vdec] = perfE.vdec;
+       cstate->domain[nv_clk_src_dom6] = perfE.disp;
+
+       while (ver >= 0x40 && (++domain)->name != nv_clk_src_max) {
+               struct nvbios_perfS perfS;
+               u8  sver = ver, shdr = hdr;
+               u32 perfSe = nvbios_perfSp(bios, data, domain->bios,
+                                         &sver, &shdr, cnt, len, &perfS);
+               if (perfSe == 0 || sver != 0x40)
+                       continue;
+
+               if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
+                       perfS.v40.freq = nouveau_clock_adjust(clk, false,
+                                                             pstate->pstate,
+                                                             domain->bios,
+                                                             perfS.v40.freq);
+               }
+
+               cstate->domain[domain->name] = perfS.v40.freq;
+       }
+
+       data = nvbios_cstepEm(bios, pstate->pstate, &ver, &hdr, &cstepE);
+       if (data) {
+               int idx = cstepE.index;
+               do {
+                       nouveau_cstate_new(clk, idx, pstate);
+               } while(idx--);
+       }
+
+       nouveau_pstate_info(clk, pstate);
+       list_add_tail(&pstate->head, &clk->states);
+       clk->state_nr++;
+       return 0;
+}
+
+/******************************************************************************
+ * Adjustment triggers
+ *****************************************************************************/
+static int
+nouveau_clock_ustate_update(struct nouveau_clock *clk, int req)
+{
+       struct nouveau_pstate *pstate;
+       int i = 0;
+
+       /* YKW repellant */
+       return -ENOSYS;
+
+       if (req != -1 && req != -2) {
+               list_for_each_entry(pstate, &clk->states, head) {
+                       if (pstate->pstate == req)
+                               break;
+                       i++;
+               }
+
+               if (pstate->pstate != req)
+                       return -EINVAL;
+               req = i;
+       }
+
+       clk->ustate = req;
+       return 0;
+}
+
+int
+nouveau_clock_ustate(struct nouveau_clock *clk, int req)
+{
+       int ret = nouveau_clock_ustate_update(clk, req);
+       if (ret)
+               return ret;
+       return nouveau_pstate_calc(clk);
+}
+
+int
+nouveau_clock_astate(struct nouveau_clock *clk, int req, int rel)
+{
+       if (!rel) clk->astate  = req;
+       if ( rel) clk->astate += rel;
+       clk->astate = min(clk->astate, clk->state_nr - 1);
+       clk->astate = max(clk->astate, 0);
+       return nouveau_pstate_calc(clk);
+}
+
+int
+nouveau_clock_tstate(struct nouveau_clock *clk, int req, int rel)
+{
+       if (!rel) clk->tstate  = req;
+       if ( rel) clk->tstate += rel;
+       clk->tstate = min(clk->tstate, 0);
+       clk->tstate = max(clk->tstate, -(clk->state_nr - 1));
+       return nouveau_pstate_calc(clk);
+}
+
+int
+nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel)
+{
+       if (!rel) clk->dstate  = req;
+       if ( rel) clk->dstate += rel;
+       clk->dstate = min(clk->dstate, clk->state_nr - 1);
+       clk->dstate = max(clk->dstate, 0);
+       return nouveau_pstate_calc(clk);
+}
+
+/******************************************************************************
+ * subdev base class implementation
+ *****************************************************************************/
+int
+_nouveau_clock_init(struct nouveau_object *object)
+{
+       struct nouveau_clock *clk = (void *)object;
+       struct nouveau_clocks *clock = clk->domains;
+       int ret;
+
+       memset(&clk->bstate, 0x00, sizeof(clk->bstate));
+       INIT_LIST_HEAD(&clk->bstate.list);
+       clk->bstate.pstate = 0xff;
+
+       while (clock->name != nv_clk_src_max) {
+               ret = clk->read(clk, clock->name);
+               if (ret < 0) {
+                       nv_error(clk, "%02x freq unknown\n", clock->name);
+                       return ret;
+               }
+               clk->bstate.base.domain[clock->name] = ret;
+               clock++;
+       }
+
+       nouveau_pstate_info(clk, &clk->bstate);
+
+       clk->astate = clk->state_nr - 1;
+       clk->tstate = 0;
+       clk->dstate = 0;
+       clk->pstate = -1;
+       nouveau_pstate_calc(clk);
+       return 0;
+}
+
+void
+_nouveau_clock_dtor(struct nouveau_object *object)
+{
+       struct nouveau_clock *clk = (void *)object;
+       struct nouveau_pstate *pstate, *temp;
+
+       list_for_each_entry_safe(pstate, temp, &clk->states, head) {
+               nouveau_pstate_del(pstate);
+       }
+
+       nouveau_subdev_destroy(&clk->base);
+}
+
+int
+nouveau_clock_create_(struct nouveau_object *parent,
+                     struct nouveau_object *engine,
+                     struct nouveau_oclass *oclass,
+                     struct nouveau_clocks *clocks,
+                     int length, void **object)
+{
+       struct nouveau_device *device = nv_device(parent);
+       struct nouveau_clock *clk;
+       int ret, idx, arglen;
+       const char *mode;
+
+       ret = nouveau_subdev_create_(parent, engine, oclass, 0, "CLK",
+                                    "clock", length, object);
+       clk = *object;
+       if (ret)
+               return ret;
+
+       INIT_LIST_HEAD(&clk->states);
+       clk->domains = clocks;
+       clk->ustate = -1;
+
+       idx = 0;
+       do {
+               ret = nouveau_pstate_new(clk, idx++);
+       } while (ret == 0);
+
+       mode = nouveau_stropt(device->cfgopt, "NvClkMode", &arglen);
+       if (mode) {
+               if (!strncasecmpz(mode, "disabled", arglen)) {
+                       clk->ustate = -1;
+               } else {
+                       char save = mode[arglen];
+                       long v;
+
+                       ((char *)mode)[arglen] = '\0';
+                       if (!kstrtol(mode, 0, &v))
+                               nouveau_clock_ustate_update(clk, v);
+                       ((char *)mode)[arglen] = save;
+               }
+       }
+
+       return 0;
+}
index a142775..da50c1b 100644 (file)
@@ -77,7 +77,7 @@ nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nv04_clock_priv *priv;
        int ret;
 
-       ret = nouveau_clock_create(parent, engine, oclass, &priv);
+       ret = nouveau_clock_create(parent, engine, oclass, NULL, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
index 0db5dbf..db7346f 100644 (file)
  */
 
 #include <subdev/clock.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+#include "pll.h"
 
 struct nv40_clock_priv {
        struct nouveau_clock base;
+       u32 ctrl;
+       u32 npll_ctrl;
+       u32 npll_coef;
+       u32 spll;
+};
+
+static struct nouveau_clocks
+nv40_domain[] = {
+       { nv_clk_src_crystal, 0xff },
+       { nv_clk_src_href   , 0xff },
+       { nv_clk_src_core   , 0xff, 0, "core", 1000 },
+       { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+       { nv_clk_src_mem    , 0xff, 0, "memory", 1000 },
+       { nv_clk_src_max }
 };
 
+static u32
+read_pll_1(struct nv40_clock_priv *priv, u32 reg)
+{
+       u32 ctrl = nv_rd32(priv, reg + 0x00);
+       int P = (ctrl & 0x00070000) >> 16;
+       int N = (ctrl & 0x0000ff00) >> 8;
+       int M = (ctrl & 0x000000ff) >> 0;
+       u32 ref = 27000, clk = 0;
+
+       if (ctrl & 0x80000000)
+               clk = ref * N / M;
+
+       return clk >> P;
+}
+
+static u32
+read_pll_2(struct nv40_clock_priv *priv, u32 reg)
+{
+       u32 ctrl = nv_rd32(priv, reg + 0x00);
+       u32 coef = nv_rd32(priv, reg + 0x04);
+       int N2 = (coef & 0xff000000) >> 24;
+       int M2 = (coef & 0x00ff0000) >> 16;
+       int N1 = (coef & 0x0000ff00) >> 8;
+       int M1 = (coef & 0x000000ff) >> 0;
+       int P = (ctrl & 0x00070000) >> 16;
+       u32 ref = 27000, clk = 0;
+
+       if ((ctrl & 0x80000000) && M1) {
+               clk = ref * N1 / M1;
+               if ((ctrl & 0x40000100) == 0x40000000) {
+                       if (M2)
+                               clk = clk * N2 / M2;
+                       else
+                               clk = 0;
+               }
+       }
+
+       return clk >> P;
+}
+
+static u32
+read_clk(struct nv40_clock_priv *priv, u32 src)
+{
+       switch (src) {
+       case 3:
+               return read_pll_2(priv, 0x004000);
+       case 2:
+               return read_pll_1(priv, 0x004008);
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int
+nv40_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
+{
+       struct nv40_clock_priv *priv = (void *)clk;
+       u32 mast = nv_rd32(priv, 0x00c040);
+
+       switch (src) {
+       case nv_clk_src_crystal:
+               return nv_device(priv)->crystal;
+       case nv_clk_src_href:
+               return 100000; /*XXX: PCIE/AGP differ*/
+       case nv_clk_src_core:
+               return read_clk(priv, (mast & 0x00000003) >> 0);
+       case nv_clk_src_shader:
+               return read_clk(priv, (mast & 0x00000030) >> 4);
+       case nv_clk_src_mem:
+               return read_pll_2(priv, 0x4020);
+       default:
+               break;
+       }
+
+       nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
+       return -EINVAL;
+}
+
+static int
+nv40_clock_calc_pll(struct nv40_clock_priv *priv, u32 reg, u32 clk,
+                   int *N1, int *M1, int *N2, int *M2, int *log2P)
+{
+       struct nouveau_bios *bios = nouveau_bios(priv);
+       struct nvbios_pll pll;
+       int ret;
+
+       ret = nvbios_pll_parse(bios, reg, &pll);
+       if (ret)
+               return ret;
+
+       if (clk < pll.vco1.max_freq)
+               pll.vco2.max_freq = 0;
+
+       ret = nv04_pll_calc(nv_subdev(priv), &pll, clk, N1, M1, N2, M2, log2P);
+       if (ret == 0)
+               return -ERANGE;
+       return ret;
+}
+
+static int
+nv40_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
+{
+       struct nv40_clock_priv *priv = (void *)clk;
+       int gclk = cstate->domain[nv_clk_src_core];
+       int sclk = cstate->domain[nv_clk_src_shader];
+       int N1, M1, N2, M2, log2P;
+       int ret;
+
+       /* core/geometric clock */
+       ret = nv40_clock_calc_pll(priv, 0x004000, gclk,
+                                &N1, &M1, &N2, &M2, &log2P);
+       if (ret < 0)
+               return ret;
+
+       if (N2 == M2) {
+               priv->npll_ctrl = 0x80000100 | (log2P << 16);
+               priv->npll_coef = (N1 << 8) | M1;
+       } else {
+               priv->npll_ctrl = 0xc0000000 | (log2P << 16);
+               priv->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
+       }
+
+       /* use the second pll for shader/rop clock, if it differs from core */
+       if (sclk && sclk != gclk) {
+               ret = nv40_clock_calc_pll(priv, 0x004008, sclk,
+                                        &N1, &M1, NULL, NULL, &log2P);
+               if (ret < 0)
+                       return ret;
+
+               priv->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1;
+               priv->ctrl = 0x00000223;
+       } else {
+               priv->spll = 0x00000000;
+               priv->ctrl = 0x00000333;
+       }
+
+       return 0;
+}
+
+static int
+nv40_clock_prog(struct nouveau_clock *clk)
+{
+       struct nv40_clock_priv *priv = (void *)clk;
+       nv_mask(priv, 0x00c040, 0x00000333, 0x00000000);
+       nv_wr32(priv, 0x004004, priv->npll_coef);
+       nv_mask(priv, 0x004000, 0xc0070100, priv->npll_ctrl);
+       nv_mask(priv, 0x004008, 0xc007ffff, priv->spll);
+       mdelay(5);
+       nv_mask(priv, 0x00c040, 0x00000333, priv->ctrl);
+       return 0;
+}
+
+static void
+nv40_clock_tidy(struct nouveau_clock *clk)
+{
+}
+
 static int
 nv40_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                struct nouveau_oclass *oclass, void *data, u32 size,
@@ -36,13 +213,17 @@ nv40_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nv40_clock_priv *priv;
        int ret;
 
-       ret = nouveau_clock_create(parent, engine, oclass, &priv);
+       ret = nouveau_clock_create(parent, engine, oclass, nv40_domain, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
 
        priv->base.pll_calc = nv04_clock_pll_calc;
        priv->base.pll_prog = nv04_clock_pll_prog;
+       priv->base.read = nv40_clock_read;
+       priv->base.calc = nv40_clock_calc;
+       priv->base.prog = nv40_clock_prog;
+       priv->base.tidy = nv40_clock_tidy;
        return 0;
 }
 
index d09d3e7..250a6d9 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/clock.h>
 #include <subdev/bios.h>
 #include <subdev/bios/pll.h>
 
+#include "nv50.h"
 #include "pll.h"
+#include "seq.h"
 
-struct nv50_clock_priv {
-       struct nouveau_clock base;
-};
+static u32
+read_div(struct nv50_clock_priv *priv)
+{
+       switch (nv_device(priv)->chipset) {
+       case 0x50: /* it exists, but only has bit 31, not the dividers.. */
+       case 0x84:
+       case 0x86:
+       case 0x98:
+       case 0xa0:
+               return nv_rd32(priv, 0x004700);
+       case 0x92:
+       case 0x94:
+       case 0x96:
+               return nv_rd32(priv, 0x004800);
+       default:
+               return 0x00000000;
+       }
+}
+
+static u32
+read_pll_src(struct nv50_clock_priv *priv, u32 base)
+{
+       struct nouveau_clock *clk = &priv->base;
+       u32 coef, ref = clk->read(clk, nv_clk_src_crystal);
+       u32 rsel = nv_rd32(priv, 0x00e18c);
+       int P, N, M, id;
+
+       switch (nv_device(priv)->chipset) {
+       case 0x50:
+       case 0xa0:
+               switch (base) {
+               case 0x4020:
+               case 0x4028: id = !!(rsel & 0x00000004); break;
+               case 0x4008: id = !!(rsel & 0x00000008); break;
+               case 0x4030: id = 0; break;
+               default:
+                       nv_error(priv, "ref: bad pll 0x%06x\n", base);
+                       return 0;
+               }
+
+               coef = nv_rd32(priv, 0x00e81c + (id * 0x0c));
+               ref *=  (coef & 0x01000000) ? 2 : 4;
+               P    =  (coef & 0x00070000) >> 16;
+               N    = ((coef & 0x0000ff00) >> 8) + 1;
+               M    = ((coef & 0x000000ff) >> 0) + 1;
+               break;
+       case 0x84:
+       case 0x86:
+       case 0x92:
+               coef = nv_rd32(priv, 0x00e81c);
+               P    = (coef & 0x00070000) >> 16;
+               N    = (coef & 0x0000ff00) >> 8;
+               M    = (coef & 0x000000ff) >> 0;
+               break;
+       case 0x94:
+       case 0x96:
+       case 0x98:
+               rsel = nv_rd32(priv, 0x00c050);
+               switch (base) {
+               case 0x4020: rsel = (rsel & 0x00000003) >> 0; break;
+               case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break;
+               case 0x4028: rsel = (rsel & 0x00001800) >> 11; break;
+               case 0x4030: rsel = 3; break;
+               default:
+                       nv_error(priv, "ref: bad pll 0x%06x\n", base);
+                       return 0;
+               }
+
+               switch (rsel) {
+               case 0: id = 1; break;
+               case 1: return clk->read(clk, nv_clk_src_crystal);
+               case 2: return clk->read(clk, nv_clk_src_href);
+               case 3: id = 0; break;
+               }
+
+               coef =  nv_rd32(priv, 0x00e81c + (id * 0x28));
+               P    = (nv_rd32(priv, 0x00e824 + (id * 0x28)) >> 16) & 7;
+               P   += (coef & 0x00070000) >> 16;
+               N    = (coef & 0x0000ff00) >> 8;
+               M    = (coef & 0x000000ff) >> 0;
+               break;
+       default:
+               BUG_ON(1);
+       }
+
+       if (M)
+               return (ref * N / M) >> P;
+       return 0;
+}
+
+static u32
+read_pll_ref(struct nv50_clock_priv *priv, u32 base)
+{
+       struct nouveau_clock *clk = &priv->base;
+       u32 src, mast = nv_rd32(priv, 0x00c040);
+
+       switch (base) {
+       case 0x004028:
+               src = !!(mast & 0x00200000);
+               break;
+       case 0x004020:
+               src = !!(mast & 0x00400000);
+               break;
+       case 0x004008:
+               src = !!(mast & 0x00010000);
+               break;
+       case 0x004030:
+               src = !!(mast & 0x02000000);
+               break;
+       case 0x00e810:
+               return clk->read(clk, nv_clk_src_crystal);
+       default:
+               nv_error(priv, "bad pll 0x%06x\n", base);
+               return 0;
+       }
+
+       if (src)
+               return clk->read(clk, nv_clk_src_href);
+       return read_pll_src(priv, base);
+}
+
+static u32
+read_pll(struct nv50_clock_priv *priv, u32 base)
+{
+       struct nouveau_clock *clk = &priv->base;
+       u32 mast = nv_rd32(priv, 0x00c040);
+       u32 ctrl = nv_rd32(priv, base + 0);
+       u32 coef = nv_rd32(priv, base + 4);
+       u32 ref = read_pll_ref(priv, base);
+       u32 freq = 0;
+       int N1, N2, M1, M2;
+
+       if (base == 0x004028 && (mast & 0x00100000)) {
+               /* wtf, appears to only disable post-divider on nva0 */
+               if (nv_device(priv)->chipset != 0xa0)
+                       return clk->read(clk, nv_clk_src_dom6);
+       }
+
+       N2 = (coef & 0xff000000) >> 24;
+       M2 = (coef & 0x00ff0000) >> 16;
+       N1 = (coef & 0x0000ff00) >> 8;
+       M1 = (coef & 0x000000ff);
+       if ((ctrl & 0x80000000) && M1) {
+               freq = ref * N1 / M1;
+               if ((ctrl & 0x40000100) == 0x40000000) {
+                       if (M2)
+                               freq = freq * N2 / M2;
+                       else
+                               freq = 0;
+               }
+       }
+
+       return freq;
+}
 
 static int
+nv50_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
+{
+       struct nv50_clock_priv *priv = (void *)clk;
+       u32 mast = nv_rd32(priv, 0x00c040);
+       u32 P = 0;
+
+       switch (src) {
+       case nv_clk_src_crystal:
+               return nv_device(priv)->crystal;
+       case nv_clk_src_href:
+               return 100000; /* PCIE reference clock */
+       case nv_clk_src_hclk:
+               return div_u64((u64)clk->read(clk, nv_clk_src_href) * 27778, 10000);
+       case nv_clk_src_hclkm3:
+               return clk->read(clk, nv_clk_src_hclk) * 3;
+       case nv_clk_src_hclkm3d2:
+               return clk->read(clk, nv_clk_src_hclk) * 3 / 2;
+       case nv_clk_src_host:
+               switch (mast & 0x30000000) {
+               case 0x00000000: return clk->read(clk, nv_clk_src_href);
+               case 0x10000000: break;
+               case 0x20000000: /* !0x50 */
+               case 0x30000000: return clk->read(clk, nv_clk_src_hclk);
+               }
+               break;
+       case nv_clk_src_core:
+               if (!(mast & 0x00100000))
+                       P = (nv_rd32(priv, 0x004028) & 0x00070000) >> 16;
+               switch (mast & 0x00000003) {
+               case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P;
+               case 0x00000001: return clk->read(clk, nv_clk_src_dom6);
+               case 0x00000002: return read_pll(priv, 0x004020) >> P;
+               case 0x00000003: return read_pll(priv, 0x004028) >> P;
+               }
+               break;
+       case nv_clk_src_shader:
+               P = (nv_rd32(priv, 0x004020) & 0x00070000) >> 16;
+               switch (mast & 0x00000030) {
+               case 0x00000000:
+                       if (mast & 0x00000080)
+                               return clk->read(clk, nv_clk_src_host) >> P;
+                       return clk->read(clk, nv_clk_src_crystal) >> P;
+               case 0x00000010: break;
+               case 0x00000020: return read_pll(priv, 0x004028) >> P;
+               case 0x00000030: return read_pll(priv, 0x004020) >> P;
+               }
+               break;
+       case nv_clk_src_mem:
+               P = (nv_rd32(priv, 0x004008) & 0x00070000) >> 16;
+               if (nv_rd32(priv, 0x004008) & 0x00000200) {
+                       switch (mast & 0x0000c000) {
+                       case 0x00000000:
+                               return clk->read(clk, nv_clk_src_crystal) >> P;
+                       case 0x00008000:
+                       case 0x0000c000:
+                               return clk->read(clk, nv_clk_src_href) >> P;
+                       }
+               } else {
+                       return read_pll(priv, 0x004008) >> P;
+               }
+               break;
+       case nv_clk_src_vdec:
+               P = (read_div(priv) & 0x00000700) >> 8;
+               switch (nv_device(priv)->chipset) {
+               case 0x84:
+               case 0x86:
+               case 0x92:
+               case 0x94:
+               case 0x96:
+               case 0xa0:
+                       switch (mast & 0x00000c00) {
+                       case 0x00000000:
+                               if (nv_device(priv)->chipset == 0xa0) /* wtf?? */
+                                       return clk->read(clk, nv_clk_src_core) >> P;
+                               return clk->read(clk, nv_clk_src_crystal) >> P;
+                       case 0x00000400:
+                               return 0;
+                       case 0x00000800:
+                               if (mast & 0x01000000)
+                                       return read_pll(priv, 0x004028) >> P;
+                               return read_pll(priv, 0x004030) >> P;
+                       case 0x00000c00:
+                               return clk->read(clk, nv_clk_src_core) >> P;
+                       }
+                       break;
+               case 0x98:
+                       switch (mast & 0x00000c00) {
+                       case 0x00000000:
+                               return clk->read(clk, nv_clk_src_core) >> P;
+                       case 0x00000400:
+                               return 0;
+                       case 0x00000800:
+                               return clk->read(clk, nv_clk_src_hclkm3d2) >> P;
+                       case 0x00000c00:
+                               return clk->read(clk, nv_clk_src_mem) >> P;
+                       }
+                       break;
+               }
+               break;
+       case nv_clk_src_dom6:
+               switch (nv_device(priv)->chipset) {
+               case 0x50:
+               case 0xa0:
+                       return read_pll(priv, 0x00e810) >> 2;
+               case 0x84:
+               case 0x86:
+               case 0x92:
+               case 0x94:
+               case 0x96:
+               case 0x98:
+                       P = (read_div(priv) & 0x00000007) >> 0;
+                       switch (mast & 0x0c000000) {
+                       case 0x00000000: return clk->read(clk, nv_clk_src_href);
+                       case 0x04000000: break;
+                       case 0x08000000: return clk->read(clk, nv_clk_src_hclk);
+                       case 0x0c000000:
+                               return clk->read(clk, nv_clk_src_hclkm3) >> P;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       default:
+               break;
+       }
+
+       nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
+       return -EINVAL;
+}
+
+static u32
+calc_pll(struct nv50_clock_priv *priv, u32 reg, u32 clk, int *N, int *M, int *P)
+{
+       struct nouveau_bios *bios = nouveau_bios(priv);
+       struct nvbios_pll pll;
+       int ret;
+
+       ret = nvbios_pll_parse(bios, reg, &pll);
+       if (ret)
+               return 0;
+
+       pll.vco2.max_freq = 0;
+       pll.refclk = read_pll_ref(priv, reg);
+       if (!pll.refclk)
+               return 0;
+
+       return nv04_pll_calc(nv_subdev(priv), &pll, clk, N, M, NULL, NULL, P);
+}
+
+static inline u32
+calc_div(u32 src, u32 target, int *div)
+{
+       u32 clk0 = src, clk1 = src;
+       for (*div = 0; *div <= 7; (*div)++) {
+               if (clk0 <= target) {
+                       clk1 = clk0 << (*div ? 1 : 0);
+                       break;
+               }
+               clk0 >>= 1;
+       }
+
+       if (target - clk0 <= clk1 - target)
+               return clk0;
+       (*div)--;
+       return clk1;
+}
+
+static inline u32
+clk_same(u32 a, u32 b)
+{
+       return ((a / 1000) == (b / 1000));
+}
+
+static int
+nv50_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
+{
+       struct nv50_clock_priv *priv = (void *)clk;
+       struct nv50_clock_hwsq *hwsq = &priv->hwsq;
+       const int shader = cstate->domain[nv_clk_src_shader];
+       const int core = cstate->domain[nv_clk_src_core];
+       const int vdec = cstate->domain[nv_clk_src_vdec];
+       const int dom6 = cstate->domain[nv_clk_src_dom6];
+       u32 mastm = 0, mastv = 0;
+       u32 divsm = 0, divsv = 0;
+       int N, M, P1, P2;
+       int freq, out;
+
+       /* prepare a hwsq script from which we'll perform the reclock */
+       out = clk_init(hwsq, nv_subdev(clk));
+       if (out)
+               return out;
+
+       clk_wr32(hwsq, fifo, 0x00000001); /* block fifo */
+       clk_nsec(hwsq, 8000);
+       clk_setf(hwsq, 0x10, 0x00); /* disable fb */
+       clk_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
+
+       /* vdec: avoid modifying xpll until we know exactly how the other
+        * clock domains work, i suspect at least some of them can also be
+        * tied to xpll...
+        */
+       if (vdec) {
+               /* see how close we can get using nvclk as a source */
+               freq = calc_div(core, vdec, &P1);
+
+               /* see how close we can get using xpll/hclk as a source */
+               if (nv_device(priv)->chipset != 0x98)
+                       out = read_pll(priv, 0x004030);
+               else
+                       out = clk->read(clk, nv_clk_src_hclkm3d2);
+               out = calc_div(out, vdec, &P2);
+
+               /* select whichever gets us closest */
+               if (abs(vdec - freq) <= abs(vdec - out)) {
+                       if (nv_device(priv)->chipset != 0x98)
+                               mastv |= 0x00000c00;
+                       divsv |= P1 << 8;
+               } else {
+                       mastv |= 0x00000800;
+                       divsv |= P2 << 8;
+               }
+
+               mastm |= 0x00000c00;
+               divsm |= 0x00000700;
+       }
+
+       /* dom6: nfi what this is, but we're limited to various combinations
+        * of the host clock frequency
+        */
+       if (dom6) {
+               if (clk_same(dom6, clk->read(clk, nv_clk_src_href))) {
+                       mastv |= 0x00000000;
+               } else
+               if (clk_same(dom6, clk->read(clk, nv_clk_src_hclk))) {
+                       mastv |= 0x08000000;
+               } else {
+                       freq = clk->read(clk, nv_clk_src_hclk) * 3;
+                       freq = calc_div(freq, dom6, &P1);
+
+                       mastv |= 0x0c000000;
+                       divsv |= P1;
+               }
+
+               mastm |= 0x0c000000;
+               divsm |= 0x00000007;
+       }
+
+       /* vdec/dom6: switch to "safe" clocks temporarily, update dividers
+        * and then switch to target clocks
+        */
+       clk_mask(hwsq, mast, mastm, 0x00000000);
+       clk_mask(hwsq, divs, divsm, divsv);
+       clk_mask(hwsq, mast, mastm, mastv);
+
+       /* core/shader: disconnect nvclk/sclk from their PLLs (nvclk to dom6,
+        * sclk to hclk) before reprogramming
+        */
+       if (nv_device(priv)->chipset < 0x92)
+               clk_mask(hwsq, mast, 0x001000b0, 0x00100080);
+       else
+               clk_mask(hwsq, mast, 0x000000b3, 0x00000081);
+
+       /* core: for the moment at least, always use nvpll */
+       freq = calc_pll(priv, 0x4028, core, &N, &M, &P1);
+       if (freq == 0)
+               return -ERANGE;
+
+       clk_mask(hwsq, nvpll[0], 0xc03f0100,
+                                0x80000000 | (P1 << 19) | (P1 << 16));
+       clk_mask(hwsq, nvpll[1], 0x0000ffff, (N << 8) | M);
+
+       /* shader: tie to nvclk if possible, otherwise use spll.  have to be
+        * very careful that the shader clock is at least twice the core, or
+        * some chipsets will be very unhappy.  i expect most or all of these
+        * cases will be handled by tying to nvclk, but it's possible there's
+        * corners
+        */
+       if (P1-- && shader == (core << 1)) {
+               clk_mask(hwsq, spll[0], 0xc03f0100, (P1 << 19) | (P1 << 16));
+               clk_mask(hwsq, mast, 0x00100033, 0x00000023);
+       } else {
+               freq = calc_pll(priv, 0x4020, shader, &N, &M, &P1);
+               if (freq == 0)
+                       return -ERANGE;
+
+               clk_mask(hwsq, spll[0], 0xc03f0100,
+                                       0x80000000 | (P1 << 19) | (P1 << 16));
+               clk_mask(hwsq, spll[1], 0x0000ffff, (N << 8) | M);
+               clk_mask(hwsq, mast, 0x00100033, 0x00000033);
+       }
+
+       /* restore normal operation */
+       clk_setf(hwsq, 0x10, 0x01); /* enable fb */
+       clk_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
+       clk_wr32(hwsq, fifo, 0x00000000); /* un-block fifo */
+       return 0;
+}
+
+static int
+nv50_clock_prog(struct nouveau_clock *clk)
+{
+       struct nv50_clock_priv *priv = (void *)clk;
+       return clk_exec(&priv->hwsq, true);
+}
+
+static void
+nv50_clock_tidy(struct nouveau_clock *clk)
+{
+       struct nv50_clock_priv *priv = (void *)clk;
+       clk_exec(&priv->hwsq, false);
+}
+
+int
 nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                struct nouveau_oclass *oclass, void *data, u32 size,
                struct nouveau_object **pobject)
 {
+       struct nv50_clock_oclass *pclass = (void *)oclass;
        struct nv50_clock_priv *priv;
        int ret;
 
-       ret = nouveau_clock_create(parent, engine, oclass, &priv);
+       ret = nouveau_clock_create(parent, engine, oclass, pclass->domains,
+                                 &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
 
-       priv->base.pll_calc = nv04_clock_pll_calc;
+       priv->hwsq.r_fifo = hwsq_reg(0x002504);
+       priv->hwsq.r_spll[0] = hwsq_reg(0x004020);
+       priv->hwsq.r_spll[1] = hwsq_reg(0x004024);
+       priv->hwsq.r_nvpll[0] = hwsq_reg(0x004028);
+       priv->hwsq.r_nvpll[1] = hwsq_reg(0x00402c);
+       switch (nv_device(priv)->chipset) {
+       case 0x92:
+       case 0x94:
+       case 0x96:
+               priv->hwsq.r_divs = hwsq_reg(0x004800);
+               break;
+       default:
+               priv->hwsq.r_divs = hwsq_reg(0x004700);
+               break;
+       }
+       priv->hwsq.r_mast = hwsq_reg(0x00c040);
+
+       priv->base.read = nv50_clock_read;
+       priv->base.calc = nv50_clock_calc;
+       priv->base.prog = nv50_clock_prog;
+       priv->base.tidy = nv50_clock_tidy;
        return 0;
 }
 
-struct nouveau_oclass
-nv50_clock_oclass = {
-       .handle = NV_SUBDEV(CLOCK, 0x50),
-       .ofuncs = &(struct nouveau_ofuncs) {
+static struct nouveau_clocks
+nv50_domains[] = {
+       { nv_clk_src_crystal, 0xff },
+       { nv_clk_src_href   , 0xff },
+       { nv_clk_src_core   , 0xff, 0, "core", 1000 },
+       { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+       { nv_clk_src_mem    , 0xff, 0, "memory", 1000 },
+       { nv_clk_src_max }
+};
+
+struct nouveau_oclass *
+nv50_clock_oclass = &(struct nv50_clock_oclass) {
+       .base.handle = NV_SUBDEV(CLOCK, 0x50),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv50_clock_ctor,
                .dtor = _nouveau_clock_dtor,
                .init = _nouveau_clock_init,
                .fini = _nouveau_clock_fini,
        },
-};
+       .domains = nv50_domains,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h
new file mode 100644 (file)
index 0000000..f10917d
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __NVKM_CLK_NV50_H__
+#define __NVKM_CLK_NV50_H__
+
+#include <subdev/bus.h>
+#include <subdev/bus/hwsq.h>
+#include <subdev/clock.h>
+
+struct nv50_clock_hwsq {
+       struct hwsq base;
+       struct hwsq_reg r_fifo;
+       struct hwsq_reg r_spll[2];
+       struct hwsq_reg r_nvpll[2];
+       struct hwsq_reg r_divs;
+       struct hwsq_reg r_mast;
+};
+
+struct nv50_clock_priv {
+       struct nouveau_clock base;
+       struct nv50_clock_hwsq hwsq;
+};
+
+int  nv50_clock_ctor(struct nouveau_object *, struct nouveau_object *,
+                    struct nouveau_oclass *, void *, u32,
+                    struct nouveau_object **);
+
+struct nv50_clock_oclass {
+       struct nouveau_oclass base;
+       struct nouveau_clocks *domains;
+};
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c
new file mode 100644 (file)
index 0000000..b0b7c14
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nv50.h"
+
+static struct nouveau_clocks
+nv84_domains[] = {
+       { nv_clk_src_crystal, 0xff },
+       { nv_clk_src_href   , 0xff },
+       { nv_clk_src_core   , 0xff, 0, "core", 1000 },
+       { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+       { nv_clk_src_mem    , 0xff, 0, "memory", 1000 },
+       { nv_clk_src_vdec   , 0xff },
+       { nv_clk_src_max }
+};
+
+struct nouveau_oclass *
+nv84_clock_oclass = &(struct nv50_clock_oclass) {
+       .base.handle = NV_SUBDEV(CLOCK, 0x84),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_clock_ctor,
+               .dtor = _nouveau_clock_dtor,
+               .init = _nouveau_clock_init,
+               .fini = _nouveau_clock_fini,
+       },
+       .domains = nv84_domains,
+}.base;
index f074cd2..4f5a137 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/clock.h>
 #include <subdev/bios.h>
 #include <subdev/bios/pll.h>
+#include <subdev/timer.h>
 
 #include "pll.h"
 
+#include "nva3.h"
+
 struct nva3_clock_priv {
        struct nouveau_clock base;
+       struct nva3_clock_info eng[nv_clk_src_max];
 };
 
+static u32 read_clk(struct nva3_clock_priv *, int, bool);
+static u32 read_pll(struct nva3_clock_priv *, int, u32);
+
+static u32
+read_vco(struct nva3_clock_priv *priv, int clk)
+{
+       u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4));
+       if ((sctl & 0x00000030) != 0x00000030)
+               return read_pll(priv, 0x41, 0x00e820);
+       return read_pll(priv, 0x42, 0x00e8a0);
+}
+
+static u32
+read_clk(struct nva3_clock_priv *priv, int clk, bool ignore_en)
+{
+       u32 sctl, sdiv, sclk;
+
+       /* refclk for the 0xe8xx plls is a fixed frequency */
+       if (clk >= 0x40) {
+               if (nv_device(priv)->chipset == 0xaf) {
+                       /* no joke.. seriously.. sigh.. */
+                       return nv_rd32(priv, 0x00471c) * 1000;
+               }
+
+               return nv_device(priv)->crystal;
+       }
+
+       sctl = nv_rd32(priv, 0x4120 + (clk * 4));
+       if (!ignore_en && !(sctl & 0x00000100))
+               return 0;
+
+       switch (sctl & 0x00003000) {
+       case 0x00000000:
+               return nv_device(priv)->crystal;
+       case 0x00002000:
+               if (sctl & 0x00000040)
+                       return 108000;
+               return 100000;
+       case 0x00003000:
+               sclk = read_vco(priv, clk);
+               sdiv = ((sctl & 0x003f0000) >> 16) + 2;
+               return (sclk * 2) / sdiv;
+       default:
+               return 0;
+       }
+}
+
+static u32
+read_pll(struct nva3_clock_priv *priv, int clk, u32 pll)
+{
+       u32 ctrl = nv_rd32(priv, pll + 0);
+       u32 sclk = 0, P = 1, N = 1, M = 1;
+
+       if (!(ctrl & 0x00000008)) {
+               if (ctrl & 0x00000001) {
+                       u32 coef = nv_rd32(priv, pll + 4);
+                       M = (coef & 0x000000ff) >> 0;
+                       N = (coef & 0x0000ff00) >> 8;
+                       P = (coef & 0x003f0000) >> 16;
+
+                       /* no post-divider on these.. */
+                       if ((pll & 0x00ff00) == 0x00e800)
+                               P = 1;
+
+                       sclk = read_clk(priv, 0x00 + clk, false);
+               }
+       } else {
+               sclk = read_clk(priv, 0x10 + clk, false);
+       }
+
+       if (M * P)
+               return sclk * N / (M * P);
+       return 0;
+}
+
+static int
+nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
+{
+       struct nva3_clock_priv *priv = (void *)clk;
+
+       switch (src) {
+       case nv_clk_src_crystal:
+               return nv_device(priv)->crystal;
+       case nv_clk_src_href:
+               return 100000;
+       case nv_clk_src_core:
+               return read_pll(priv, 0x00, 0x4200);
+       case nv_clk_src_shader:
+               return read_pll(priv, 0x01, 0x4220);
+       case nv_clk_src_mem:
+               return read_pll(priv, 0x02, 0x4000);
+       case nv_clk_src_disp:
+               return read_clk(priv, 0x20, false);
+       case nv_clk_src_vdec:
+               return read_clk(priv, 0x21, false);
+       case nv_clk_src_daemon:
+               return read_clk(priv, 0x25, false);
+       default:
+               nv_error(clk, "invalid clock source %d\n", src);
+               return -EINVAL;
+       }
+}
+
 int
-nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
-                   int clk, struct nouveau_pll_vals *pv)
+nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
+               struct nva3_clock_info *info)
 {
-       int ret, N, M, P;
+       struct nouveau_bios *bios = nouveau_bios(clock);
+       struct nva3_clock_priv *priv = (void *)clock;
+       struct nvbios_pll limits;
+       u32 oclk, sclk, sdiv;
+       int P, N, M, diff;
+       int ret;
+
+       info->pll = 0;
+       info->clk = 0;
+
+       switch (khz) {
+       case 27000:
+               info->clk = 0x00000100;
+               return khz;
+       case 100000:
+               info->clk = 0x00002100;
+               return khz;
+       case 108000:
+               info->clk = 0x00002140;
+               return khz;
+       default:
+               sclk = read_vco(priv, clk);
+               sdiv = min((sclk * 2) / (khz - 2999), (u32)65);
+               /* if the clock has a PLL attached, and we can get a within
+                * [-2, 3) MHz of a divider, we'll disable the PLL and use
+                * the divider instead.
+                *
+                * divider can go as low as 2, limited here because NVIDIA
+                * and the VBIOS on my NVA8 seem to prefer using the PLL
+                * for 810MHz - is there a good reason?
+                */
+               if (sdiv > 4) {
+                       oclk = (sclk * 2) / sdiv;
+                       diff = khz - oclk;
+                       if (!pll || (diff >= -2000 && diff < 3000)) {
+                               info->clk = (((sdiv - 2) << 16) | 0x00003100);
+                               return oclk;
+                       }
+               }
+
+               if (!pll)
+                       return -ERANGE;
+               break;
+       }
 
-       ret = nva3_pll_calc(nv_subdev(clock), info, clk, &N, NULL, &M, &P);
+       ret = nvbios_pll_parse(bios, pll, &limits);
+       if (ret)
+               return ret;
+
+       limits.refclk = read_clk(priv, clk - 0x10, true);
+       if (!limits.refclk)
+               return -EINVAL;
 
-       if (ret > 0) {
-               pv->refclk = info->refclk;
-               pv->N1 = N;
-               pv->M1 = M;
-               pv->log2P = P;
+       ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P);
+       if (ret >= 0) {
+               info->clk = nv_rd32(priv, 0x4120 + (clk * 4));
+               info->pll = (P << 16) | (N << 8) | M;
        }
+
+       return ret ? ret : -ERANGE;
+}
+
+static int
+calc_clk(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate,
+        int clk, u32 pll, int idx)
+{
+       int ret = nva3_clock_info(&priv->base, clk, pll, cstate->domain[idx],
+                                 &priv->eng[idx]);
+       if (ret >= 0)
+               return 0;
        return ret;
 }
 
+static void
+prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx)
+{
+       struct nva3_clock_info *info = &priv->eng[idx];
+       const u32 src0 = 0x004120 + (clk * 4);
+       const u32 src1 = 0x004160 + (clk * 4);
+       const u32 ctrl = pll + 0;
+       const u32 coef = pll + 4;
+
+       if (info->pll) {
+               nv_mask(priv, src0, 0x00000101, 0x00000101);
+               nv_wr32(priv, coef, info->pll);
+               nv_mask(priv, ctrl, 0x00000015, 0x00000015);
+               nv_mask(priv, ctrl, 0x00000010, 0x00000000);
+               nv_wait(priv, ctrl, 0x00020000, 0x00020000);
+               nv_mask(priv, ctrl, 0x00000010, 0x00000010);
+               nv_mask(priv, ctrl, 0x00000008, 0x00000000);
+               nv_mask(priv, src1, 0x00000100, 0x00000000);
+               nv_mask(priv, src1, 0x00000001, 0x00000000);
+       } else {
+               nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk);
+               nv_mask(priv, ctrl, 0x00000018, 0x00000018);
+               udelay(20);
+               nv_mask(priv, ctrl, 0x00000001, 0x00000000);
+               nv_mask(priv, src0, 0x00000100, 0x00000000);
+               nv_mask(priv, src0, 0x00000001, 0x00000000);
+       }
+}
+
+static void
+prog_clk(struct nva3_clock_priv *priv, int clk, int idx)
+{
+       struct nva3_clock_info *info = &priv->eng[idx];
+       nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk);
+}
+
+static int
+nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
+{
+       struct nva3_clock_priv *priv = (void *)clk;
+       int ret;
+
+       if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) ||
+           (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) ||
+           (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) ||
+           (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)))
+               return ret;
+
+       return 0;
+}
+
+static int
+nva3_clock_prog(struct nouveau_clock *clk)
+{
+       struct nva3_clock_priv *priv = (void *)clk;
+       prog_pll(priv, 0x00, 0x004200, nv_clk_src_core);
+       prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader);
+       prog_clk(priv, 0x20, nv_clk_src_disp);
+       prog_clk(priv, 0x21, nv_clk_src_vdec);
+       return 0;
+}
+
+static void
+nva3_clock_tidy(struct nouveau_clock *clk)
+{
+}
+
+static struct nouveau_clocks
+nva3_domain[] = {
+       { nv_clk_src_crystal, 0xff },
+       { nv_clk_src_href   , 0xff },
+       { nv_clk_src_core   , 0x00, 0, "core", 1000 },
+       { nv_clk_src_shader , 0x01, 0, "shader", 1000 },
+       { nv_clk_src_mem    , 0x02, 0, "memory", 1000 },
+       { nv_clk_src_vdec   , 0x03 },
+       { nv_clk_src_disp   , 0x04 },
+       { nv_clk_src_max }
+};
 
 static int
 nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
@@ -58,12 +302,15 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nva3_clock_priv *priv;
        int ret;
 
-       ret = nouveau_clock_create(parent, engine, oclass, &priv);
+       ret = nouveau_clock_create(parent, engine, oclass, nva3_domain, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
 
-       priv->base.pll_calc = nva3_clock_pll_calc;
+       priv->base.read = nva3_clock_read;
+       priv->base.calc = nva3_clock_calc;
+       priv->base.prog = nva3_clock_prog;
+       priv->base.tidy = nva3_clock_tidy;
        return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h
new file mode 100644 (file)
index 0000000..6229a50
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __NVKM_CLK_NVA3_H__
+#define __NVKM_CLK_NVA3_H__
+
+#include <subdev/clock.h>
+
+struct nva3_clock_info {
+       u32 clk;
+       u32 pll;
+};
+
+int nva3_clock_info(struct nouveau_clock *, int, u32, u32,
+                   struct nva3_clock_info *);
+
+#endif
index 439d81c..c310572 100644 (file)
 #include <subdev/clock.h>
 #include <subdev/bios.h>
 #include <subdev/bios/pll.h>
+#include <subdev/timer.h>
 
 #include "pll.h"
 
+struct nvc0_clock_info {
+       u32 freq;
+       u32 ssel;
+       u32 mdiv;
+       u32 dsrc;
+       u32 ddiv;
+       u32 coef;
+};
+
 struct nvc0_clock_priv {
        struct nouveau_clock base;
+       struct nvc0_clock_info eng[16];
+};
+
+static u32 read_div(struct nvc0_clock_priv *, int, u32, u32);
+
+static u32
+read_vco(struct nvc0_clock_priv *priv, u32 dsrc)
+{
+       struct nouveau_clock *clk = &priv->base;
+       u32 ssrc = nv_rd32(priv, dsrc);
+       if (!(ssrc & 0x00000100))
+               return clk->read(clk, nv_clk_src_sppll0);
+       return clk->read(clk, nv_clk_src_sppll1);
+}
+
+static u32
+read_pll(struct nvc0_clock_priv *priv, u32 pll)
+{
+       struct nouveau_clock *clk = &priv->base;
+       u32 ctrl = nv_rd32(priv, pll + 0x00);
+       u32 coef = nv_rd32(priv, pll + 0x04);
+       u32 P = (coef & 0x003f0000) >> 16;
+       u32 N = (coef & 0x0000ff00) >> 8;
+       u32 M = (coef & 0x000000ff) >> 0;
+       u32 sclk;
+
+       if (!(ctrl & 0x00000001))
+               return 0;
+
+       switch (pll) {
+       case 0x00e800:
+       case 0x00e820:
+               sclk = nv_device(priv)->crystal;
+               P = 1;
+               break;
+       case 0x132000:
+               sclk = clk->read(clk, nv_clk_src_mpllsrc);
+               break;
+       case 0x132020:
+               sclk = clk->read(clk, nv_clk_src_mpllsrcref);
+               break;
+       case 0x137000:
+       case 0x137020:
+       case 0x137040:
+       case 0x1370e0:
+               sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
+               break;
+       default:
+               return 0;
+       }
+
+       return sclk * N / M / P;
+}
+
+static u32
+read_div(struct nvc0_clock_priv *priv, int doff, u32 dsrc, u32 dctl)
+{
+       u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
+       u32 sctl = nv_rd32(priv, dctl + (doff * 4));
+
+       switch (ssrc & 0x00000003) {
+       case 0:
+               if ((ssrc & 0x00030000) != 0x00030000)
+                       return nv_device(priv)->crystal;
+               return 108000;
+       case 2:
+               return 100000;
+       case 3:
+               if (sctl & 0x80000000) {
+                       u32 sclk = read_vco(priv, dsrc + (doff * 4));
+                       u32 sdiv = (sctl & 0x0000003f) + 2;
+                       return (sclk * 2) / sdiv;
+               }
+
+               return read_vco(priv, dsrc + (doff * 4));
+       default:
+               return 0;
+       }
+}
+
+static u32
+read_clk(struct nvc0_clock_priv *priv, int clk)
+{
+       u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
+       u32 ssel = nv_rd32(priv, 0x137100);
+       u32 sclk, sdiv;
+
+       if (ssel & (1 << clk)) {
+               if (clk < 7)
+                       sclk = read_pll(priv, 0x137000 + (clk * 0x20));
+               else
+                       sclk = read_pll(priv, 0x1370e0);
+               sdiv = ((sctl & 0x00003f00) >> 8) + 2;
+       } else {
+               sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+               sdiv = ((sctl & 0x0000003f) >> 0) + 2;
+       }
+
+       if (sctl & 0x80000000)
+               return (sclk * 2) / sdiv;
+
+       return sclk;
+}
+
+static int
+nvc0_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
+{
+       struct nouveau_device *device = nv_device(clk);
+       struct nvc0_clock_priv *priv = (void *)clk;
+
+       switch (src) {
+       case nv_clk_src_crystal:
+               return device->crystal;
+       case nv_clk_src_href:
+               return 100000;
+       case nv_clk_src_sppll0:
+               return read_pll(priv, 0x00e800);
+       case nv_clk_src_sppll1:
+               return read_pll(priv, 0x00e820);
+
+       case nv_clk_src_mpllsrcref:
+               return read_div(priv, 0, 0x137320, 0x137330);
+       case nv_clk_src_mpllsrc:
+               return read_pll(priv, 0x132020);
+       case nv_clk_src_mpll:
+               return read_pll(priv, 0x132000);
+       case nv_clk_src_mdiv:
+               return read_div(priv, 0, 0x137300, 0x137310);
+       case nv_clk_src_mem:
+               if (nv_rd32(priv, 0x1373f0) & 0x00000002)
+                       return clk->read(clk, nv_clk_src_mpll);
+               return clk->read(clk, nv_clk_src_mdiv);
+
+       case nv_clk_src_gpc:
+               return read_clk(priv, 0x00);
+       case nv_clk_src_rop:
+               return read_clk(priv, 0x01);
+       case nv_clk_src_hubk07:
+               return read_clk(priv, 0x02);
+       case nv_clk_src_hubk06:
+               return read_clk(priv, 0x07);
+       case nv_clk_src_hubk01:
+               return read_clk(priv, 0x08);
+       case nv_clk_src_copy:
+               return read_clk(priv, 0x09);
+       case nv_clk_src_daemon:
+               return read_clk(priv, 0x0c);
+       case nv_clk_src_vdec:
+               return read_clk(priv, 0x0e);
+       default:
+               nv_error(clk, "invalid clock source %d\n", src);
+               return -EINVAL;
+       }
+}
+
+static u32
+calc_div(struct nvc0_clock_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
+{
+       u32 div = min((ref * 2) / freq, (u32)65);
+       if (div < 2)
+               div = 2;
+
+       *ddiv = div - 2;
+       return (ref * 2) / div;
+}
+
+static u32
+calc_src(struct nvc0_clock_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
+{
+       u32 sclk;
+
+       /* use one of the fixed frequencies if possible */
+       *ddiv = 0x00000000;
+       switch (freq) {
+       case  27000:
+       case 108000:
+               *dsrc = 0x00000000;
+               if (freq == 108000)
+                       *dsrc |= 0x00030000;
+               return freq;
+       case 100000:
+               *dsrc = 0x00000002;
+               return freq;
+       default:
+               *dsrc = 0x00000003;
+               break;
+       }
+
+       /* otherwise, calculate the closest divider */
+       sclk = read_vco(priv, 0x137160 + (clk * 4));
+       if (clk < 7)
+               sclk = calc_div(priv, clk, sclk, freq, ddiv);
+       return sclk;
+}
+
+static u32
+calc_pll(struct nvc0_clock_priv *priv, int clk, u32 freq, u32 *coef)
+{
+       struct nouveau_bios *bios = nouveau_bios(priv);
+       struct nvbios_pll limits;
+       int N, M, P, ret;
+
+       ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
+       if (ret)
+               return 0;
+
+       limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
+       if (!limits.refclk)
+               return 0;
+
+       ret = nva3_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
+       if (ret <= 0)
+               return 0;
+
+       *coef = (P << 16) | (N << 8) | M;
+       return ret;
+}
+
+static int
+calc_clk(struct nvc0_clock_priv *priv,
+        struct nouveau_cstate *cstate, int clk, int dom)
+{
+       struct nvc0_clock_info *info = &priv->eng[clk];
+       u32 freq = cstate->domain[dom];
+       u32 src0, div0, div1D, div1P = 0;
+       u32 clk0, clk1 = 0;
+
+       /* invalid clock domain */
+       if (!freq)
+               return 0;
+
+       /* first possible path, using only dividers */
+       clk0 = calc_src(priv, clk, freq, &src0, &div0);
+       clk0 = calc_div(priv, clk, clk0, freq, &div1D);
+
+       /* see if we can get any closer using PLLs */
+       if (clk0 != freq && (0x00004387 & (1 << clk))) {
+               if (clk <= 7)
+                       clk1 = calc_pll(priv, clk, freq, &info->coef);
+               else
+                       clk1 = cstate->domain[nv_clk_src_hubk06];
+               clk1 = calc_div(priv, clk, clk1, freq, &div1P);
+       }
+
+       /* select the method which gets closest to target freq */
+       if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
+               info->dsrc = src0;
+               if (div0) {
+                       info->ddiv |= 0x80000000;
+                       info->ddiv |= div0 << 8;
+                       info->ddiv |= div0;
+               }
+               if (div1D) {
+                       info->mdiv |= 0x80000000;
+                       info->mdiv |= div1D;
+               }
+               info->ssel = info->coef = 0;
+               info->freq = clk0;
+       } else {
+               if (div1P) {
+                       info->mdiv |= 0x80000000;
+                       info->mdiv |= div1P << 8;
+               }
+               info->ssel = (1 << clk);
+               info->freq = clk1;
+       }
+
+       return 0;
+}
+
+static int
+nvc0_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
+{
+       struct nvc0_clock_priv *priv = (void *)clk;
+       int ret;
+
+       if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
+           (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
+           (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
+           (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
+           (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
+           (ret = calc_clk(priv, cstate, 0x09, nv_clk_src_copy)) ||
+           (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
+           (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
+               return ret;
+
+       return 0;
+}
+
+static void
+nvc0_clock_prog_0(struct nvc0_clock_priv *priv, int clk)
+{
+       struct nvc0_clock_info *info = &priv->eng[clk];
+       if (clk < 7 && !info->ssel) {
+               nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv);
+               nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
+       }
+}
+
+static void
+nvc0_clock_prog_1(struct nvc0_clock_priv *priv, int clk)
+{
+       nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
+       nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
+}
+
+static void
+nvc0_clock_prog_2(struct nvc0_clock_priv *priv, int clk)
+{
+       struct nvc0_clock_info *info = &priv->eng[clk];
+       const u32 addr = 0x137000 + (clk * 0x20);
+       if (clk <= 7) {
+               nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
+               nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
+               if (info->coef) {
+                       nv_wr32(priv, addr + 0x04, info->coef);
+                       nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
+                       nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
+                       nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
+               }
+       }
+}
+
+static void
+nvc0_clock_prog_3(struct nvc0_clock_priv *priv, int clk)
+{
+       struct nvc0_clock_info *info = &priv->eng[clk];
+       if (info->ssel) {
+               nv_mask(priv, 0x137100, (1 << clk), info->ssel);
+               nv_wait(priv, 0x137100, (1 << clk), info->ssel);
+       }
+}
+
+static void
+nvc0_clock_prog_4(struct nvc0_clock_priv *priv, int clk)
+{
+       struct nvc0_clock_info *info = &priv->eng[clk];
+       nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv);
+}
+
+static int
+nvc0_clock_prog(struct nouveau_clock *clk)
+{
+       struct nvc0_clock_priv *priv = (void *)clk;
+       struct {
+               void (*exec)(struct nvc0_clock_priv *, int);
+       } stage[] = {
+               { nvc0_clock_prog_0 }, /* div programming */
+               { nvc0_clock_prog_1 }, /* select div mode */
+               { nvc0_clock_prog_2 }, /* (maybe) program pll */
+               { nvc0_clock_prog_3 }, /* (maybe) select pll mode */
+               { nvc0_clock_prog_4 }, /* final divider */
+       };
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(stage); i++) {
+               for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
+                       if (!priv->eng[j].freq)
+                               continue;
+                       stage[i].exec(priv, j);
+               }
+       }
+
+       return 0;
+}
+
+static void
+nvc0_clock_tidy(struct nouveau_clock *clk)
+{
+       struct nvc0_clock_priv *priv = (void *)clk;
+       memset(priv->eng, 0x00, sizeof(priv->eng));
+}
+
+static struct nouveau_clocks
+nvc0_domain[] = {
+       { nv_clk_src_crystal, 0xff },
+       { nv_clk_src_href   , 0xff },
+       { nv_clk_src_hubk06 , 0x00 },
+       { nv_clk_src_hubk01 , 0x01 },
+       { nv_clk_src_copy   , 0x02 },
+       { nv_clk_src_gpc    , 0x03, 0, "core", 2000 },
+       { nv_clk_src_rop    , 0x04 },
+       { nv_clk_src_mem    , 0x05, 0, "memory", 1000 },
+       { nv_clk_src_vdec   , 0x06 },
+       { nv_clk_src_daemon , 0x0a },
+       { nv_clk_src_hubk07 , 0x0b },
+       { nv_clk_src_max }
 };
 
 static int
@@ -40,12 +437,15 @@ nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nvc0_clock_priv *priv;
        int ret;
 
-       ret = nouveau_clock_create(parent, engine, oclass, &priv);
+       ret = nouveau_clock_create(parent, engine, oclass, nvc0_domain, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
 
-       priv->base.pll_calc = nva3_clock_pll_calc;
+       priv->base.read = nvc0_clock_read;
+       priv->base.calc = nvc0_clock_calc;
+       priv->base.prog = nvc0_clock_prog;
+       priv->base.tidy = nvc0_clock_tidy;
        return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c
new file mode 100644 (file)
index 0000000..4c62e84
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/clock.h>
+#include <subdev/timer.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+#include "pll.h"
+
+struct nve0_clock_info {
+       u32 freq;
+       u32 ssel;
+       u32 mdiv;
+       u32 dsrc;
+       u32 ddiv;
+       u32 coef;
+};
+
+struct nve0_clock_priv {
+       struct nouveau_clock base;
+       struct nve0_clock_info eng[16];
+};
+
+static u32 read_div(struct nve0_clock_priv *, int, u32, u32);
+static u32 read_pll(struct nve0_clock_priv *, u32);
+
+static u32
+read_vco(struct nve0_clock_priv *priv, u32 dsrc)
+{
+       u32 ssrc = nv_rd32(priv, dsrc);
+       if (!(ssrc & 0x00000100))
+               return read_pll(priv, 0x00e800);
+       return read_pll(priv, 0x00e820);
+}
+
+static u32
+read_pll(struct nve0_clock_priv *priv, u32 pll)
+{
+       u32 ctrl = nv_rd32(priv, pll + 0x00);
+       u32 coef = nv_rd32(priv, pll + 0x04);
+       u32 P = (coef & 0x003f0000) >> 16;
+       u32 N = (coef & 0x0000ff00) >> 8;
+       u32 M = (coef & 0x000000ff) >> 0;
+       u32 sclk;
+       u16 fN = 0xf000;
+
+       if (!(ctrl & 0x00000001))
+               return 0;
+
+       switch (pll) {
+       case 0x00e800:
+       case 0x00e820:
+               sclk = nv_device(priv)->crystal;
+               P = 1;
+               break;
+       case 0x132000:
+               sclk = read_pll(priv, 0x132020);
+               P = (coef & 0x10000000) ? 2 : 1;
+               break;
+       case 0x132020:
+               sclk = read_div(priv, 0, 0x137320, 0x137330);
+               fN   = nv_rd32(priv, pll + 0x10) >> 16;
+               break;
+       case 0x137000:
+       case 0x137020:
+       case 0x137040:
+       case 0x1370e0:
+               sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
+               break;
+       default:
+               return 0;
+       }
+
+       if (P == 0)
+               P = 1;
+
+       sclk = (sclk * N) + (((u16)(fN + 4096) * sclk) >> 13);
+       return sclk / (M * P);
+}
+
+static u32
+read_div(struct nve0_clock_priv *priv, int doff, u32 dsrc, u32 dctl)
+{
+       u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
+       u32 sctl = nv_rd32(priv, dctl + (doff * 4));
+
+       switch (ssrc & 0x00000003) {
+       case 0:
+               if ((ssrc & 0x00030000) != 0x00030000)
+                       return nv_device(priv)->crystal;
+               return 108000;
+       case 2:
+               return 100000;
+       case 3:
+               if (sctl & 0x80000000) {
+                       u32 sclk = read_vco(priv, dsrc + (doff * 4));
+                       u32 sdiv = (sctl & 0x0000003f) + 2;
+                       return (sclk * 2) / sdiv;
+               }
+
+               return read_vco(priv, dsrc + (doff * 4));
+       default:
+               return 0;
+       }
+}
+
+static u32
+read_mem(struct nve0_clock_priv *priv)
+{
+       switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) {
+       case 1: return read_pll(priv, 0x132020);
+       case 2: return read_pll(priv, 0x132000);
+       default:
+               return 0;
+       }
+}
+
+static u32
+read_clk(struct nve0_clock_priv *priv, int clk)
+{
+       u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
+       u32 sclk, sdiv;
+
+       if (clk < 7) {
+               u32 ssel = nv_rd32(priv, 0x137100);
+               if (ssel & (1 << clk)) {
+                       sclk = read_pll(priv, 0x137000 + (clk * 0x20));
+                       sdiv = 1;
+               } else {
+                       sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+                       sdiv = 0;
+               }
+       } else {
+               u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04));
+               if ((ssrc & 0x00000003) == 0x00000003) {
+                       sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+                       if (ssrc & 0x00000100) {
+                               if (ssrc & 0x40000000)
+                                       sclk = read_pll(priv, 0x1370e0);
+                               sdiv = 1;
+                       } else {
+                               sdiv = 0;
+                       }
+               } else {
+                       sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+                       sdiv = 0;
+               }
+       }
+
+       if (sctl & 0x80000000) {
+               if (sdiv)
+                       sdiv = ((sctl & 0x00003f00) >> 8) + 2;
+               else
+                       sdiv = ((sctl & 0x0000003f) >> 0) + 2;
+               return (sclk * 2) / sdiv;
+       }
+
+       return sclk;
+}
+
+static int
+nve0_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
+{
+       struct nouveau_device *device = nv_device(clk);
+       struct nve0_clock_priv *priv = (void *)clk;
+
+       switch (src) {
+       case nv_clk_src_crystal:
+               return device->crystal;
+       case nv_clk_src_href:
+               return 100000;
+       case nv_clk_src_mem:
+               return read_mem(priv);
+       case nv_clk_src_gpc:
+               return read_clk(priv, 0x00);
+       case nv_clk_src_rop:
+               return read_clk(priv, 0x01);
+       case nv_clk_src_hubk07:
+               return read_clk(priv, 0x02);
+       case nv_clk_src_hubk06:
+               return read_clk(priv, 0x07);
+       case nv_clk_src_hubk01:
+               return read_clk(priv, 0x08);
+       case nv_clk_src_daemon:
+               return read_clk(priv, 0x0c);
+       case nv_clk_src_vdec:
+               return read_clk(priv, 0x0e);
+       default:
+               nv_error(clk, "invalid clock source %d\n", src);
+               return -EINVAL;
+       }
+}
+
+static u32
+calc_div(struct nve0_clock_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
+{
+       u32 div = min((ref * 2) / freq, (u32)65);
+       if (div < 2)
+               div = 2;
+
+       *ddiv = div - 2;
+       return (ref * 2) / div;
+}
+
+static u32
+calc_src(struct nve0_clock_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
+{
+       u32 sclk;
+
+       /* use one of the fixed frequencies if possible */
+       *ddiv = 0x00000000;
+       switch (freq) {
+       case  27000:
+       case 108000:
+               *dsrc = 0x00000000;
+               if (freq == 108000)
+                       *dsrc |= 0x00030000;
+               return freq;
+       case 100000:
+               *dsrc = 0x00000002;
+               return freq;
+       default:
+               *dsrc = 0x00000003;
+               break;
+       }
+
+       /* otherwise, calculate the closest divider */
+       sclk = read_vco(priv, 0x137160 + (clk * 4));
+       if (clk < 7)
+               sclk = calc_div(priv, clk, sclk, freq, ddiv);
+       return sclk;
+}
+
+static u32
+calc_pll(struct nve0_clock_priv *priv, int clk, u32 freq, u32 *coef)
+{
+       struct nouveau_bios *bios = nouveau_bios(priv);
+       struct nvbios_pll limits;
+       int N, M, P, ret;
+
+       ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
+       if (ret)
+               return 0;
+
+       limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
+       if (!limits.refclk)
+               return 0;
+
+       ret = nva3_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
+       if (ret <= 0)
+               return 0;
+
+       *coef = (P << 16) | (N << 8) | M;
+       return ret;
+}
+
+static int
+calc_clk(struct nve0_clock_priv *priv,
+        struct nouveau_cstate *cstate, int clk, int dom)
+{
+       struct nve0_clock_info *info = &priv->eng[clk];
+       u32 freq = cstate->domain[dom];
+       u32 src0, div0, div1D, div1P = 0;
+       u32 clk0, clk1 = 0;
+
+       /* invalid clock domain */
+       if (!freq)
+               return 0;
+
+       /* first possible path, using only dividers */
+       clk0 = calc_src(priv, clk, freq, &src0, &div0);
+       clk0 = calc_div(priv, clk, clk0, freq, &div1D);
+
+       /* see if we can get any closer using PLLs */
+       if (clk0 != freq && (0x0000ff87 & (1 << clk))) {
+               if (clk <= 7)
+                       clk1 = calc_pll(priv, clk, freq, &info->coef);
+               else
+                       clk1 = cstate->domain[nv_clk_src_hubk06];
+               clk1 = calc_div(priv, clk, clk1, freq, &div1P);
+       }
+
+       /* select the method which gets closest to target freq */
+       if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
+               info->dsrc = src0;
+               if (div0) {
+                       info->ddiv |= 0x80000000;
+                       info->ddiv |= div0 << 8;
+                       info->ddiv |= div0;
+               }
+               if (div1D) {
+                       info->mdiv |= 0x80000000;
+                       info->mdiv |= div1D;
+               }
+               info->ssel = 0;
+               info->freq = clk0;
+       } else {
+               if (div1P) {
+                       info->mdiv |= 0x80000000;
+                       info->mdiv |= div1P << 8;
+               }
+               info->ssel = (1 << clk);
+               info->dsrc = 0x40000100;
+               info->freq = clk1;
+       }
+
+       return 0;
+}
+
+static int
+nve0_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
+{
+       struct nve0_clock_priv *priv = (void *)clk;
+       int ret;
+
+       if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
+           (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
+           (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
+           (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
+           (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
+           (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
+           (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
+               return ret;
+
+       return 0;
+}
+
+static void
+nve0_clock_prog_0(struct nve0_clock_priv *priv, int clk)
+{
+       struct nve0_clock_info *info = &priv->eng[clk];
+       if (!info->ssel) {
+               nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv);
+               nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
+       }
+}
+
+static void
+nve0_clock_prog_1_0(struct nve0_clock_priv *priv, int clk)
+{
+       nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
+       nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
+}
+
+static void
+nve0_clock_prog_1_1(struct nve0_clock_priv *priv, int clk)
+{
+       nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000);
+}
+
+static void
+nve0_clock_prog_2(struct nve0_clock_priv *priv, int clk)
+{
+       struct nve0_clock_info *info = &priv->eng[clk];
+       const u32 addr = 0x137000 + (clk * 0x20);
+       nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
+       nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
+       if (info->coef) {
+               nv_wr32(priv, addr + 0x04, info->coef);
+               nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
+               nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
+               nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
+       }
+}
+
+static void
+nve0_clock_prog_3(struct nve0_clock_priv *priv, int clk)
+{
+       struct nve0_clock_info *info = &priv->eng[clk];
+       nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv);
+}
+
+static void
+nve0_clock_prog_4_0(struct nve0_clock_priv *priv, int clk)
+{
+       struct nve0_clock_info *info = &priv->eng[clk];
+       if (info->ssel) {
+               nv_mask(priv, 0x137100, (1 << clk), info->ssel);
+               nv_wait(priv, 0x137100, (1 << clk), info->ssel);
+       }
+}
+
+static void
+nve0_clock_prog_4_1(struct nve0_clock_priv *priv, int clk)
+{
+       struct nve0_clock_info *info = &priv->eng[clk];
+       if (info->ssel) {
+               nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000);
+               nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100);
+       }
+}
+
+static int
+nve0_clock_prog(struct nouveau_clock *clk)
+{
+       struct nve0_clock_priv *priv = (void *)clk;
+       struct {
+               u32 mask;
+               void (*exec)(struct nve0_clock_priv *, int);
+       } stage[] = {
+               { 0x007f, nve0_clock_prog_0   }, /* div programming */
+               { 0x007f, nve0_clock_prog_1_0 }, /* select div mode */
+               { 0xff80, nve0_clock_prog_1_1 },
+               { 0x00ff, nve0_clock_prog_2   }, /* (maybe) program pll */
+               { 0xff80, nve0_clock_prog_3   }, /* final divider */
+               { 0x007f, nve0_clock_prog_4_0 }, /* (maybe) select pll mode */
+               { 0xff80, nve0_clock_prog_4_1 },
+       };
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(stage); i++) {
+               for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
+                       if (!(stage[i].mask & (1 << j)))
+                               continue;
+                       if (!priv->eng[j].freq)
+                               continue;
+                       stage[i].exec(priv, j);
+               }
+       }
+
+       return 0;
+}
+
+static void
+nve0_clock_tidy(struct nouveau_clock *clk)
+{
+       struct nve0_clock_priv *priv = (void *)clk;
+       memset(priv->eng, 0x00, sizeof(priv->eng));
+}
+
+static struct nouveau_clocks
+nve0_domain[] = {
+       { nv_clk_src_crystal, 0xff },
+       { nv_clk_src_href   , 0xff },
+       { nv_clk_src_gpc    , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 },
+       { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
+       { nv_clk_src_rop    , 0x02, NVKM_CLK_DOM_FLAG_CORE },
+       { nv_clk_src_mem    , 0x03, 0, "memory", 1000 },
+       { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE },
+       { nv_clk_src_hubk01 , 0x05 },
+       { nv_clk_src_vdec   , 0x06 },
+       { nv_clk_src_daemon , 0x07 },
+       { nv_clk_src_max }
+};
+
+static int
+nve0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+               struct nouveau_oclass *oclass, void *data, u32 size,
+               struct nouveau_object **pobject)
+{
+       struct nve0_clock_priv *priv;
+       int ret;
+
+       ret = nouveau_clock_create(parent, engine, oclass, nve0_domain, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       priv->base.read = nve0_clock_read;
+       priv->base.calc = nve0_clock_calc;
+       priv->base.prog = nve0_clock_prog;
+       priv->base.tidy = nve0_clock_tidy;
+       return 0;
+}
+
+struct nouveau_oclass
+nve0_clock_oclass = {
+       .handle = NV_SUBDEV(CLOCK, 0xe0),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nve0_clock_ctor,
+               .dtor = _nouveau_clock_dtor,
+               .init = _nouveau_clock_init,
+               .fini = _nouveau_clock_fini,
+       },
+};
index cf1ed0d..b47d543 100644 (file)
@@ -38,7 +38,7 @@ getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk,
         * "clk" parameter in kHz
         * returns calculated clock
         */
-       int cv = nouveau_bios(subdev)->version.chip;
+       struct nouveau_bios *bios = nouveau_bios(subdev);
        int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq;
        int minM = info->vco1.min_m, maxM = info->vco1.max_m;
        int minN = info->vco1.min_n, maxN = info->vco1.max_n;
@@ -54,18 +54,21 @@ getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk,
 
        /* this division verified for nv20, nv18, nv28 (Haiku), and nv34 */
        /* possibly correlated with introduction of 27MHz crystal */
-       if (cv < 0x17 || cv == 0x1a || cv == 0x20) {
-               if (clk > 250000)
-                       maxM = 6;
-               if (clk > 340000)
-                       maxM = 2;
-       } else if (cv < 0x40) {
-               if (clk > 150000)
-                       maxM = 6;
-               if (clk > 200000)
-                       maxM = 4;
-               if (clk > 340000)
-                       maxM = 2;
+       if (bios->version.major < 0x60) {
+               int cv = bios->version.chip;
+               if (cv < 0x17 || cv == 0x1a || cv == 0x20) {
+                       if (clk > 250000)
+                               maxM = 6;
+                       if (clk > 340000)
+                               maxM = 2;
+               } else if (cv < 0x40) {
+                       if (clk > 150000)
+                               maxM = 6;
+                       if (clk > 200000)
+                               maxM = 4;
+                       if (clk > 340000)
+                               maxM = 2;
+               }
        }
 
        P = 1 << maxP;
@@ -227,10 +230,12 @@ nv04_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, u32 freq,
 {
        int ret;
 
-       if (!info->vco2.max_freq) {
+       if (!info->vco2.max_freq || !N2) {
                ret = getMNP_single(subdev, info, freq, N1, M1, P);
-               *N2 = 1;
-               *M2 = 1;
+               if (N2) {
+                       *N2 = 1;
+                       *M2 = 1;
+               }
        } else {
                ret = getMNP_double(subdev, info, freq, N1, M1, N2, M2, P);
        }
index 2fe1f71..8eca457 100644 (file)
@@ -45,6 +45,7 @@ nva3_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info,
        lM = max(lM, (int)info->vco1.min_m);
        hM = (info->refclk + info->vco1.min_inputfreq) / info->vco1.min_inputfreq;
        hM = min(hM, (int)info->vco1.max_m);
+       lM = min(lM, hM);
 
        for (M = lM; M <= hM; M++) {
                u32 tmp = freq * *P * M;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h b/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h
new file mode 100644 (file)
index 0000000..fb33f06
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __NVKM_CLK_SEQ_H__
+#define __NVKM_CLK_SEQ_H__
+
+#include <subdev/bus.h>
+#include <subdev/bus/hwsq.h>
+
+#define clk_init(s,p)       hwsq_init(&(s)->base, (p))
+#define clk_exec(s,e)       hwsq_exec(&(s)->base, (e))
+#define clk_have(s,r)       ((s)->r_##r.addr != 0x000000)
+#define clk_rd32(s,r)       hwsq_rd32(&(s)->base, &(s)->r_##r)
+#define clk_wr32(s,r,d)     hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
+#define clk_mask(s,r,m,d)   hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
+#define clk_setf(s,f,d)     hwsq_setf(&(s)->base, (f), (d))
+#define clk_wait(s,f,d)     hwsq_wait(&(s)->base, (f), (d))
+#define clk_nsec(s,n)       hwsq_nsec(&(s)->base, (n))
+
+#endif
index b22357d..27c8235 100644 (file)
@@ -168,7 +168,8 @@ setPLL_single(struct nouveau_devinit *devinit, u32 reg,
                /* downclock -- write new NM first */
                nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1);
 
-       if (chip_version < 0x17 && chip_version != 0x11)
+       if ((chip_version < 0x17 || chip_version == 0x1a) &&
+           chip_version != 0x11)
                /* wait a bit on older chips */
                msleep(64);
        nv_rd32(devinit, reg);
index 463b08f..8d274db 100644 (file)
@@ -38,12 +38,18 @@ static void
 nv10_devinit_meminit(struct nouveau_devinit *devinit)
 {
        struct nv10_devinit_priv *priv = (void *)devinit;
-       const int mem_width[] = { 0x10, 0x00, 0x20 };
-       const int mem_width_count = nv_device(priv)->chipset >= 0x17 ? 3 : 2;
+       static const int mem_width[] = { 0x10, 0x00, 0x20 };
+       int mem_width_count;
        uint32_t patt = 0xdeadbeef;
        struct io_mapping *fb;
        int i, j, k;
 
+       if (nv_device(priv)->card_type >= NV_11 &&
+           nv_device(priv)->chipset >= 0x17)
+               mem_width_count = 3;
+       else
+               mem_width_count = 2;
+
        /* Map the framebuffer aperture */
        fb = fbmem_init(nv_device(priv)->pdev);
        if (!fb) {
index 821cd75..f009d8a 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include "subdev/fb.h"
-#include "subdev/bios.h"
-#include "subdev/bios/bit.h"
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+
+#include "priv.h"
 
 int
 nouveau_fb_bios_memtype(struct nouveau_bios *bios)
@@ -106,9 +107,9 @@ _nouveau_fb_dtor(struct nouveau_object *object)
 
 int
 nouveau_fb_create_(struct nouveau_object *parent, struct nouveau_object *engine,
-                  struct nouveau_oclass *oclass, struct nouveau_oclass *ramcls,
-                  int length, void **pobject)
+                  struct nouveau_oclass *oclass, int length, void **pobject)
 {
+       struct nouveau_fb_impl *impl = (void *)oclass;
        static const char *name[] = {
                [NV_MEM_TYPE_UNKNOWN] = "unknown",
                [NV_MEM_TYPE_STOLEN ] = "stolen system memory",
@@ -132,8 +133,10 @@ nouveau_fb_create_(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       pfb->memtype_valid = impl->memtype;
+
        ret = nouveau_object_ctor(nv_object(pfb), nv_object(pfb),
-                                 ramcls, NULL, 0, &ram);
+                                 impl->ram, NULL, 0, &ram);
        if (ret) {
                nv_fatal(pfb, "error detecting memory configuration!!\n");
                return ret;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c
new file mode 100644 (file)
index 0000000..34f9605
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include <subdev/bios.h>
+#include "priv.h"
+
+int
+nouveau_gddr5_calc(struct nouveau_ram *ram)
+{
+       struct nouveau_bios *bios = nouveau_bios(ram);
+       int pd, lf, xd, vh, vr, vo;
+       int WL, CL, WR, at, dt, ds;
+       int rq = ram->freq < 1000000; /* XXX */
+
+       switch (!!ram->ramcfg.data * ram->ramcfg.version) {
+       case 0x11:
+               pd =  (nv_ro08(bios, ram->ramcfg.data + 0x01) & 0x80) >> 7;
+               lf =  (nv_ro08(bios, ram->ramcfg.data + 0x01) & 0x40) >> 6;
+               xd = !(nv_ro08(bios, ram->ramcfg.data + 0x01) & 0x20);
+               vh =  (nv_ro08(bios, ram->ramcfg.data + 0x02) & 0x10) >> 4;
+               vr =  (nv_ro08(bios, ram->ramcfg.data + 0x02) & 0x04) >> 2;
+               vo =   nv_ro08(bios, ram->ramcfg.data + 0x06) & 0xff;
+               break;
+       default:
+               return -ENOSYS;
+       }
+
+       switch (!!ram->timing.data * ram->timing.version) {
+       case 0x20:
+               WL = (nv_ro16(bios, ram->timing.data + 0x04) & 0x0f80) >> 7;
+               CL =  nv_ro08(bios, ram->timing.data + 0x04) & 0x1f;
+               WR =  nv_ro08(bios, ram->timing.data + 0x0a) & 0x7f;
+               at = (nv_ro08(bios, ram->timing.data + 0x2e) & 0xc0) >> 6;
+               dt =  nv_ro08(bios, ram->timing.data + 0x2e) & 0x03;
+               ds =  nv_ro08(bios, ram->timing.data + 0x2f) & 0x03;
+               break;
+       default:
+               return -ENOSYS;
+       }
+
+       if (WL < 1 || WL > 7 || CL < 5 || CL > 36 || WR < 4 || WR > 35)
+               return -EINVAL;
+       CL -= 5;
+       WR -= 4;
+
+       ram->mr[0] &= ~0xf7f;
+       ram->mr[0] |= (WR & 0x0f) << 8;
+       ram->mr[0] |= (CL & 0x0f) << 3;
+       ram->mr[0] |= (WL & 0x07) << 0;
+
+       ram->mr[1] &= ~0x0bf;
+       ram->mr[1] |= (xd & 0x01) << 7;
+       ram->mr[1] |= (at & 0x03) << 4;
+       ram->mr[1] |= (dt & 0x03) << 2;
+       ram->mr[1] |= (ds & 0x03) << 0;
+
+       ram->mr[3] &= ~0x020;
+       ram->mr[3] |= (rq & 0x01) << 5;
+
+       if (!vo)
+               vo = (ram->mr[6] & 0xff0) >> 4;
+       if (ram->mr[6] & 0x001)
+               pd = 1; /* binary driver does this.. bug? */
+       ram->mr[6] &= ~0xff1;
+       ram->mr[6] |= (vo & 0xff) << 4;
+       ram->mr[6] |= (pd & 0x01) << 0;
+
+       if (!(ram->mr[7] & 0x100))
+               vr = 0; /* binary driver does this.. bug? */
+       ram->mr[7] &= ~0x188;
+       ram->mr[7] |= (vr & 0x01) << 8;
+       ram->mr[7] |= (vh & 0x01) << 7;
+       ram->mr[7] |= (lf & 0x01) << 3;
+       return 0;
+}
index 1f103c7..8309fe3 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include "priv.h"
+#include "nv04.h"
 
 #define NV04_PFB_CFG0                                          0x00100200
 
-struct nv04_fb_priv {
-       struct nouveau_fb base;
-};
-
 bool
 nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
 {
@@ -57,30 +53,37 @@ nv04_fb_init(struct nouveau_object *object)
        return 0;
 }
 
-static int
+int
 nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
             struct nouveau_oclass *oclass, void *data, u32 size,
             struct nouveau_object **pobject)
 {
+       struct nv04_fb_impl *impl = (void *)oclass;
        struct nv04_fb_priv *priv;
        int ret;
 
-       ret = nouveau_fb_create(parent, engine, oclass, &nv04_ram_oclass, &priv);
+       ret = nouveau_fb_create(parent, engine, oclass, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
 
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
+       priv->base.tile.regions = impl->tile.regions;
+       priv->base.tile.init = impl->tile.init;
+       priv->base.tile.comp = impl->tile.comp;
+       priv->base.tile.fini = impl->tile.fini;
+       priv->base.tile.prog = impl->tile.prog;
        return 0;
 }
 
-struct nouveau_oclass
-nv04_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x04),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv04_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x04),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv04_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv04_ram_oclass,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h
new file mode 100644 (file)
index 0000000..06ce71f
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __NVKM_FB_NV04_H__
+#define __NVKM_FB_NV04_H__
+
+#include "priv.h"
+
+struct nv04_fb_priv {
+       struct nouveau_fb base;
+};
+
+int  nv04_fb_ctor(struct nouveau_object *, struct nouveau_object *,
+                 struct nouveau_oclass *, void *, u32,
+                 struct nouveau_object **);
+
+struct nv04_fb_impl {
+       struct nouveau_fb_impl base;
+       struct {
+               int regions;
+               void (*init)(struct nouveau_fb *, int i, u32 addr, u32 size,
+                            u32 pitch, u32 flags, struct nouveau_fb_tile *);
+               void (*comp)(struct nouveau_fb *, int i, u32 size, u32 flags,
+                            struct nouveau_fb_tile *);
+               void (*fini)(struct nouveau_fb *, int i,
+                            struct nouveau_fb_tile *);
+               void (*prog)(struct nouveau_fb *, int i,
+                            struct nouveau_fb_tile *);
+       } tile;
+};
+
+void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+                      u32 pitch, u32 flags, struct nouveau_fb_tile *);
+void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
+void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+                      u32 pitch, u32 flags, struct nouveau_fb_tile *);
+void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
+void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+int  nv30_fb_init(struct nouveau_object *);
+void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+                      u32 pitch, u32 flags, struct nouveau_fb_tile *);
+
+void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags,
+                      struct nouveau_fb_tile *);
+
+int  nv41_fb_init(struct nouveau_object *);
+void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+int  nv44_fb_init(struct nouveau_object *);
+void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+                      u32 pitch, u32 flags, struct nouveau_fb_tile *);
+
+#endif
index be069b5..ffb7ec6 100644 (file)
  *
  */
 
-#include "priv.h"
-
-struct nv10_fb_priv {
-       struct nouveau_fb base;
-};
+#include "nv04.h"
 
 void
 nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
@@ -57,34 +53,19 @@ nv10_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
        nv_rd32(pfb, 0x100240 + (i * 0x10));
 }
 
-static int
-nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv10_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv10_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 8;
-       priv->base.tile.init = nv10_fb_tile_init;
-       priv->base.tile.fini = nv10_fb_tile_fini;
-       priv->base.tile.prog = nv10_fb_tile_prog;
-       return 0;
-}
-
-struct nouveau_oclass
-nv10_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x10),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv10_fb_ctor,
+struct nouveau_oclass *
+nv10_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x10),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = _nouveau_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv10_ram_oclass,
+       .tile.regions = 8,
+       .tile.init = nv10_fb_tile_init,
+       .tile.fini = nv10_fb_tile_fini,
+       .tile.prog = nv10_fb_tile_prog,
+}.base.base;
index 57a2af0..9159a5c 100644 (file)
  *
  */
 
-#include "priv.h"
+#include "nv04.h"
 
-struct nv1a_fb_priv {
-       struct nouveau_fb base;
-};
-
-static int
-nv1a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv1a_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv1a_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 8;
-       priv->base.tile.init = nv10_fb_tile_init;
-       priv->base.tile.fini = nv10_fb_tile_fini;
-       priv->base.tile.prog = nv10_fb_tile_prog;
-       return 0;
-}
-
-struct nouveau_oclass
-nv1a_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x1a),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv1a_fb_ctor,
+struct nouveau_oclass *
+nv1a_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x1a),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = _nouveau_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv10_ram_oclass,
+       .tile.regions = 8,
+       .tile.init = nv10_fb_tile_init,
+       .tile.fini = nv10_fb_tile_fini,
+       .tile.prog = nv10_fb_tile_prog,
+}.base.base;
index b18c4e6..f003c1b 100644 (file)
  *
  */
 
-#include "priv.h"
-
-struct nv20_fb_priv {
-       struct nouveau_fb base;
-};
+#include "nv04.h"
 
 void
 nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
@@ -80,35 +76,20 @@ nv20_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
        nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp);
 }
 
-static int
-nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv20_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 8;
-       priv->base.tile.init = nv20_fb_tile_init;
-       priv->base.tile.comp = nv20_fb_tile_comp;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv20_fb_tile_prog;
-       return 0;
-}
-
-struct nouveau_oclass
-nv20_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x20),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv20_fb_ctor,
+struct nouveau_oclass *
+nv20_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x20),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = _nouveau_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv20_ram_oclass,
+       .tile.regions = 8,
+       .tile.init = nv20_fb_tile_init,
+       .tile.comp = nv20_fb_tile_comp,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv20_fb_tile_prog,
+}.base.base;
index 32ccabf..f34f422 100644 (file)
  *
  */
 
-#include "priv.h"
-
-struct nv25_fb_priv {
-       struct nouveau_fb base;
-};
+#include "nv04.h"
 
 static void
 nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
@@ -46,35 +42,20 @@ nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
        }
 }
 
-static int
-nv25_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv25_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 8;
-       priv->base.tile.init = nv20_fb_tile_init;
-       priv->base.tile.comp = nv25_fb_tile_comp;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv20_fb_tile_prog;
-       return 0;
-}
-
-struct nouveau_oclass
-nv25_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x25),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv25_fb_ctor,
+struct nouveau_oclass *
+nv25_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x25),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = _nouveau_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv20_ram_oclass,
+       .tile.regions = 8,
+       .tile.init = nv20_fb_tile_init,
+       .tile.comp = nv25_fb_tile_comp,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv20_fb_tile_prog,
+}.base.base;
index bef756d..69093f7 100644 (file)
  *
  */
 
-#include "priv.h"
-
-struct nv30_fb_priv {
-       struct nouveau_fb base;
-};
+#include "nv04.h"
 
 void
 nv30_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
@@ -67,7 +63,7 @@ nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
 }
 
 static int
-calc_bias(struct nv30_fb_priv *priv, int k, int i, int j)
+calc_bias(struct nv04_fb_priv *priv, int k, int i, int j)
 {
        struct nouveau_device *device = nv_device(priv);
        int b = (device->chipset > 0x30 ?
@@ -78,7 +74,7 @@ calc_bias(struct nv30_fb_priv *priv, int k, int i, int j)
 }
 
 static int
-calc_ref(struct nv30_fb_priv *priv, int l, int k, int i)
+calc_ref(struct nv04_fb_priv *priv, int l, int k, int i)
 {
        int j, x = 0;
 
@@ -95,7 +91,7 @@ int
 nv30_fb_init(struct nouveau_object *object)
 {
        struct nouveau_device *device = nv_device(object);
-       struct nv30_fb_priv *priv = (void *)object;
+       struct nv04_fb_priv *priv = (void *)object;
        int ret, i, j;
 
        ret = nouveau_fb_init(&priv->base);
@@ -124,35 +120,20 @@ nv30_fb_init(struct nouveau_object *object)
        return 0;
 }
 
-static int
-nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv30_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 8;
-       priv->base.tile.init = nv30_fb_tile_init;
-       priv->base.tile.comp = nv30_fb_tile_comp;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv20_fb_tile_prog;
-       return 0;
-}
-
-struct nouveau_oclass
-nv30_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x30),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv30_fb_ctor,
+struct nouveau_oclass *
+nv30_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x30),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv30_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv20_ram_oclass,
+       .tile.regions = 8,
+       .tile.init = nv30_fb_tile_init,
+       .tile.comp = nv30_fb_tile_comp,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv20_fb_tile_prog,
+}.base.base;
index 097d8e3..161b06e 100644 (file)
  *
  */
 
-#include "priv.h"
-
-struct nv35_fb_priv {
-       struct nouveau_fb base;
-};
+#include "nv04.h"
 
 static void
 nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
@@ -47,35 +43,20 @@ nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
        }
 }
 
-static int
-nv35_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv35_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 8;
-       priv->base.tile.init = nv30_fb_tile_init;
-       priv->base.tile.comp = nv35_fb_tile_comp;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv20_fb_tile_prog;
-       return 0;
-}
-
-struct nouveau_oclass
-nv35_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x35),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv35_fb_ctor,
+struct nouveau_oclass *
+nv35_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x35),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv30_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv20_ram_oclass,
+       .tile.regions = 8,
+       .tile.init = nv30_fb_tile_init,
+       .tile.comp = nv35_fb_tile_comp,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv20_fb_tile_prog,
+}.base.base;
index 9d6d9df..2dd3d0a 100644 (file)
  *
  */
 
-#include "priv.h"
-
-struct nv36_fb_priv {
-       struct nouveau_fb base;
-};
+#include "nv04.h"
 
 static void
 nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
@@ -47,35 +43,20 @@ nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
        }
 }
 
-static int
-nv36_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv36_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 8;
-       priv->base.tile.init = nv30_fb_tile_init;
-       priv->base.tile.comp = nv36_fb_tile_comp;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv20_fb_tile_prog;
-       return 0;
-}
-
-struct nouveau_oclass
-nv36_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x36),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv36_fb_ctor,
+struct nouveau_oclass *
+nv36_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x36),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv30_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv20_ram_oclass,
+       .tile.regions = 8,
+       .tile.init = nv30_fb_tile_init,
+       .tile.comp = nv36_fb_tile_comp,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv20_fb_tile_prog,
+}.base.base;
index 33b4393..95a115a 100644 (file)
  *
  */
 
-#include "priv.h"
-
-struct nv40_fb_priv {
-       struct nouveau_fb base;
-};
+#include "nv04.h"
 
 void
 nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
@@ -50,7 +46,7 @@ nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
 static int
 nv40_fb_init(struct nouveau_object *object)
 {
-       struct nv40_fb_priv *priv = (void *)object;
+       struct nv04_fb_priv *priv = (void *)object;
        int ret;
 
        ret = nouveau_fb_init(&priv->base);
@@ -61,36 +57,20 @@ nv40_fb_init(struct nouveau_object *object)
        return 0;
 }
 
-static int
-nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv40_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv40_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 8;
-       priv->base.tile.init = nv30_fb_tile_init;
-       priv->base.tile.comp = nv40_fb_tile_comp;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv20_fb_tile_prog;
-       return 0;
-}
-
-
-struct nouveau_oclass
-nv40_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x40),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv40_fb_ctor,
+struct nouveau_oclass *
+nv40_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x40),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv40_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv40_ram_oclass,
+       .tile.regions = 8,
+       .tile.init = nv30_fb_tile_init,
+       .tile.comp = nv40_fb_tile_comp,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h
new file mode 100644 (file)
index 0000000..581f808
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __NVKM_FB_NV40_H__
+#define __NVKM_FB_NV40_H__
+
+#include "priv.h"
+
+struct nv40_ram {
+       struct nouveau_ram base;
+       u32 ctrl;
+       u32 coef;
+};
+
+
+int  nv40_ram_calc(struct nouveau_fb *, u32);
+int  nv40_ram_prog(struct nouveau_fb *);
+void nv40_ram_tidy(struct nouveau_fb *);
+
+#endif
index 02cd837..b239a86 100644 (file)
  *
  */
 
-#include "priv.h"
-
-struct nv41_fb_priv {
-       struct nouveau_fb base;
-};
+#include "nv04.h"
 
 void
 nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
@@ -43,7 +39,7 @@ nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
 int
 nv41_fb_init(struct nouveau_object *object)
 {
-       struct nv41_fb_priv *priv = (void *)object;
+       struct nv04_fb_priv *priv = (void *)object;
        int ret;
 
        ret = nouveau_fb_init(&priv->base);
@@ -54,36 +50,20 @@ nv41_fb_init(struct nouveau_object *object)
        return 0;
 }
 
-static int
-nv41_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv41_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 12;
-       priv->base.tile.init = nv30_fb_tile_init;
-       priv->base.tile.comp = nv40_fb_tile_comp;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv41_fb_tile_prog;
-       return 0;
-}
-
-
-struct nouveau_oclass
-nv41_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x41),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv41_fb_ctor,
+struct nouveau_oclass *
+nv41_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x41),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv41_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv41_ram_oclass,
+       .tile.regions = 12,
+       .tile.init = nv30_fb_tile_init,
+       .tile.comp = nv40_fb_tile_comp,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv41_fb_tile_prog,
+}.base.base;
index c5246c2..d847820 100644 (file)
  *
  */
 
-#include "priv.h"
-
-struct nv44_fb_priv {
-       struct nouveau_fb base;
-};
+#include "nv04.h"
 
 static void
 nv44_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
@@ -52,7 +48,7 @@ nv44_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
 int
 nv44_fb_init(struct nouveau_object *object)
 {
-       struct nv44_fb_priv *priv = (void *)object;
+       struct nv04_fb_priv *priv = (void *)object;
        int ret;
 
        ret = nouveau_fb_init(&priv->base);
@@ -64,35 +60,19 @@ nv44_fb_init(struct nouveau_object *object)
        return 0;
 }
 
-static int
-nv44_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv44_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 12;
-       priv->base.tile.init = nv44_fb_tile_init;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv44_fb_tile_prog;
-       return 0;
-}
-
-
-struct nouveau_oclass
-nv44_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x44),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv44_fb_ctor,
+struct nouveau_oclass *
+nv44_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x44),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv44_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv44_ram_oclass,
+       .tile.regions = 12,
+       .tile.init = nv44_fb_tile_init,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv44_fb_tile_prog,
+}.base.base;
index e2b5790..a5b7751 100644 (file)
  *
  */
 
-#include "priv.h"
-
-struct nv46_fb_priv {
-       struct nouveau_fb base;
-};
+#include "nv04.h"
 
 void
 nv46_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
@@ -44,35 +40,19 @@ nv46_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
        tile->pitch = pitch;
 }
 
-static int
-nv46_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv46_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 15;
-       priv->base.tile.init = nv46_fb_tile_init;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv44_fb_tile_prog;
-       return 0;
-}
-
-
-struct nouveau_oclass
-nv46_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x46),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv46_fb_ctor,
+struct nouveau_oclass *
+nv46_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x46),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv44_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv44_ram_oclass,
+       .tile.regions = 15,
+       .tile.init = nv46_fb_tile_init,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv44_fb_tile_prog,
+}.base.base;
index fe6a227..3bea142 100644 (file)
  *
  */
 
-#include "priv.h"
+#include "nv04.h"
 
-struct nv47_fb_priv {
-       struct nouveau_fb base;
-};
-
-static int
-nv47_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv47_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 15;
-       priv->base.tile.init = nv30_fb_tile_init;
-       priv->base.tile.comp = nv40_fb_tile_comp;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv41_fb_tile_prog;
-       return 0;
-}
-
-
-struct nouveau_oclass
-nv47_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x47),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv47_fb_ctor,
+struct nouveau_oclass *
+nv47_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x47),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv41_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv41_ram_oclass,
+       .tile.regions = 15,
+       .tile.init = nv30_fb_tile_init,
+       .tile.comp = nv40_fb_tile_comp,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv41_fb_tile_prog,
+}.base.base;
index 5eca99b..666cbd5 100644 (file)
  *
  */
 
-#include "priv.h"
+#include "nv04.h"
 
-struct nv49_fb_priv {
-       struct nouveau_fb base;
-};
-
-static int
-nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv49_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv49_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 15;
-       priv->base.tile.init = nv30_fb_tile_init;
-       priv->base.tile.comp = nv40_fb_tile_comp;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv41_fb_tile_prog;
-       return 0;
-}
-
-
-struct nouveau_oclass
-nv49_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x49),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv49_fb_ctor,
+struct nouveau_oclass *
+nv49_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x49),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv41_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv49_ram_oclass,
+       .tile.regions = 15,
+       .tile.init = nv30_fb_tile_init,
+       .tile.comp = nv40_fb_tile_comp,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv41_fb_tile_prog,
+}.base.base;
index 1190b78..42e64f3 100644 (file)
  *
  */
 
-#include "priv.h"
+#include "nv04.h"
 
-struct nv4e_fb_priv {
-       struct nouveau_fb base;
-};
-
-static int
-nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv4e_fb_priv *priv;
-       int ret;
-
-       ret = nouveau_fb_create(parent, engine, oclass, &nv4e_ram_oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.memtype_valid = nv04_fb_memtype_valid;
-       priv->base.tile.regions = 12;
-       priv->base.tile.init = nv46_fb_tile_init;
-       priv->base.tile.fini = nv20_fb_tile_fini;
-       priv->base.tile.prog = nv44_fb_tile_prog;
-       return 0;
-}
-
-struct nouveau_oclass
-nv4e_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x4e),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv4e_fb_ctor,
+struct nouveau_oclass *
+nv4e_fb_oclass = &(struct nv04_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x4e),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_fb_ctor,
                .dtor = _nouveau_fb_dtor,
                .init = nv44_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv04_fb_memtype_valid,
+       .base.ram = &nv4e_ram_oclass,
+       .tile.regions = 12,
+       .tile.init = nv46_fb_tile_init,
+       .tile.fini = nv20_fb_tile_fini,
+       .tile.prog = nv44_fb_tile_prog,
+}.base.base;
index da614ec..cbc7f00 100644 (file)
 #include <core/engctx.h>
 #include <core/object.h>
 
-#include "priv.h"
 #include <subdev/bios.h>
 
-struct nv50_fb_priv {
-       struct nouveau_fb base;
-       struct page *r100c08_page;
-       dma_addr_t r100c08;
-};
+#include "nv50.h"
 
 int
 nv50_fb_memtype[0x80] = {
@@ -48,7 +43,7 @@ nv50_fb_memtype[0x80] = {
        1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0
 };
 
-static bool
+bool
 nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype)
 {
        return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0;
@@ -239,7 +234,7 @@ nv50_fb_intr(struct nouveau_subdev *subdev)
                pr_cont("0x%08x\n", st1);
 }
 
-static int
+int
 nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
             struct nouveau_oclass *oclass, void *data, u32 size,
             struct nouveau_object **pobject)
@@ -248,7 +243,7 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nv50_fb_priv *priv;
        int ret;
 
-       ret = nouveau_fb_create(parent, engine, oclass, &nv50_ram_oclass, &priv);
+       ret = nouveau_fb_create(parent, engine, oclass, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
@@ -264,12 +259,11 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                nv_warn(priv, "failed 0x100c08 page alloc\n");
        }
 
-       priv->base.memtype_valid = nv50_fb_memtype_valid;
        nv_subdev(priv)->intr = nv50_fb_intr;
        return 0;
 }
 
-static void
+void
 nv50_fb_dtor(struct nouveau_object *object)
 {
        struct nouveau_device *device = nv_device(object);
@@ -284,10 +278,10 @@ nv50_fb_dtor(struct nouveau_object *object)
        nouveau_fb_destroy(&priv->base);
 }
 
-static int
+int
 nv50_fb_init(struct nouveau_object *object)
 {
-       struct nouveau_device *device = nv_device(object);
+       struct nv50_fb_impl *impl = (void *)object->oclass;
        struct nv50_fb_priv *priv = (void *)object;
        int ret;
 
@@ -303,33 +297,20 @@ nv50_fb_init(struct nouveau_object *object)
 
        /* This is needed to get meaningful information from 100c90
         * on traps. No idea what these values mean exactly. */
-       switch (device->chipset) {
-       case 0x50:
-               nv_wr32(priv, 0x100c90, 0x000707ff);
-               break;
-       case 0xa3:
-       case 0xa5:
-       case 0xa8:
-               nv_wr32(priv, 0x100c90, 0x000d0fff);
-               break;
-       case 0xaf:
-               nv_wr32(priv, 0x100c90, 0x089d1fff);
-               break;
-       default:
-               nv_wr32(priv, 0x100c90, 0x001d07ff);
-               break;
-       }
-
+       nv_wr32(priv, 0x100c90, impl->trap);
        return 0;
 }
 
-struct nouveau_oclass
-nv50_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0x50),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv50_fb_oclass = &(struct nv50_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x50),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv50_fb_ctor,
                .dtor = nv50_fb_dtor,
                .init = nv50_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .base.memtype = nv50_fb_memtype_valid,
+       .base.ram = &nv50_ram_oclass,
+       .trap = 0x000707ff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h
new file mode 100644 (file)
index 0000000..c5e5a88
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __NVKM_FB_NV50_H__
+#define __NVKM_FB_NV50_H__
+
+#include "priv.h"
+
+struct nv50_fb_priv {
+       struct nouveau_fb base;
+       struct page *r100c08_page;
+       dma_addr_t r100c08;
+};
+
+int  nv50_fb_ctor(struct nouveau_object *, struct nouveau_object *,
+                 struct nouveau_oclass *, void *, u32,
+                 struct nouveau_object **);
+void nv50_fb_dtor(struct nouveau_object *);
+int  nv50_fb_init(struct nouveau_object *);
+
+struct nv50_fb_impl {
+       struct nouveau_fb_impl base;
+       u32 trap;
+};
+
+#define nv50_ram_create(p,e,o,d)                                               \
+       nv50_ram_create_((p), (e), (o), sizeof(**d), (void **)d)
+int  nv50_ram_create_(struct nouveau_object *, struct nouveau_object *,
+                     struct nouveau_oclass *, int, void **);
+int  nv50_ram_get(struct nouveau_fb *, u64 size, u32 align, u32 ncmin,
+                 u32 memtype, struct nouveau_mem **);
+void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
+void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *);
+extern int nv50_fb_memtype[0x80];
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c
new file mode 100644 (file)
index 0000000..cf0e767
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv50.h"
+
+struct nouveau_oclass *
+nv84_fb_oclass = &(struct nv50_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0x84),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_fb_ctor,
+               .dtor = nv50_fb_dtor,
+               .init = nv50_fb_init,
+               .fini = _nouveau_fb_fini,
+       },
+       .base.memtype = nv50_fb_memtype_valid,
+       .base.ram = &nv50_ram_oclass,
+       .trap = 0x001d07ff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c
new file mode 100644 (file)
index 0000000..dab6e1c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv50.h"
+
+struct nouveau_oclass *
+nva3_fb_oclass = &(struct nv50_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0xa3),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_fb_ctor,
+               .dtor = nv50_fb_dtor,
+               .init = nv50_fb_init,
+               .fini = _nouveau_fb_fini,
+       },
+       .base.memtype = nv50_fb_memtype_valid,
+       .base.ram = &nva3_ram_oclass,
+       .trap = 0x000d0fff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c
new file mode 100644 (file)
index 0000000..cba8e68
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv50.h"
+
+struct nouveau_oclass *
+nvaa_fb_oclass = &(struct nv50_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0xaa),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_fb_ctor,
+               .dtor = nv50_fb_dtor,
+               .init = nv50_fb_init,
+               .fini = _nouveau_fb_fini,
+       },
+       .base.memtype = nv50_fb_memtype_valid,
+       .base.ram = &nvaa_ram_oclass,
+       .trap = 0x001d07ff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c
new file mode 100644 (file)
index 0000000..5423faa
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv50.h"
+
+struct nouveau_oclass *
+nvaf_fb_oclass = &(struct nv50_fb_impl) {
+       .base.base.handle = NV_SUBDEV(FB, 0xaf),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_fb_ctor,
+               .dtor = nv50_fb_dtor,
+               .init = nv50_fb_init,
+               .fini = _nouveau_fb_fini,
+       },
+       .base.memtype = nv50_fb_memtype_valid,
+       .base.ram = &nvaa_ram_oclass,
+       .trap = 0x089d1fff,
+}.base.base;
index f35d76f..e5fc37c 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include "priv.h"
-
-struct nvc0_fb_priv {
-       struct nouveau_fb base;
-       struct page *r100c10_page;
-       dma_addr_t r100c10;
-};
+#include "nvc0.h"
 
 extern const u8 nvc0_pte_storage_type_map[256];
 
-static bool
+bool
 nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
 {
        u8 memtype = (tile_flags & 0x0000ff00) >> 8;
        return likely((nvc0_pte_storage_type_map[memtype] != 0xff));
 }
 
-static int
+int
 nvc0_fb_init(struct nouveau_object *object)
 {
        struct nvc0_fb_priv *priv = (void *)object;
@@ -54,7 +48,7 @@ nvc0_fb_init(struct nouveau_object *object)
        return 0;
 }
 
-static void
+void
 nvc0_fb_dtor(struct nouveau_object *object)
 {
        struct nouveau_device *device = nv_device(object);
@@ -69,7 +63,7 @@ nvc0_fb_dtor(struct nouveau_object *object)
        nouveau_fb_destroy(&priv->base);
 }
 
-static int
+int
 nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
             struct nouveau_oclass *oclass, void *data, u32 size,
             struct nouveau_object **pobject)
@@ -78,13 +72,11 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nvc0_fb_priv *priv;
        int ret;
 
-       ret = nouveau_fb_create(parent, engine, oclass, &nvc0_ram_oclass, &priv);
+       ret = nouveau_fb_create(parent, engine, oclass, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
 
-       priv->base.memtype_valid = nvc0_fb_memtype_valid;
-
        priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
        if (priv->r100c10_page) {
                priv->r100c10 = pci_map_page(device->pdev, priv->r100c10_page,
@@ -97,14 +89,15 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-
-struct nouveau_oclass
-nvc0_fb_oclass = {
-       .handle = NV_SUBDEV(FB, 0xc0),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nvc0_fb_oclass = &(struct nouveau_fb_impl) {
+       .base.handle = NV_SUBDEV(FB, 0xc0),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nvc0_fb_ctor,
                .dtor = nvc0_fb_dtor,
                .init = nvc0_fb_init,
                .fini = _nouveau_fb_fini,
        },
-};
+       .memtype = nvc0_fb_memtype_valid,
+       .ram = &nvc0_ram_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h
new file mode 100644 (file)
index 0000000..9e1931e
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __NVKM_RAM_NVC0_H__
+#define __NVKM_RAM_NVC0_H__
+
+#include "priv.h"
+#include "nv50.h"
+
+struct nvc0_fb_priv {
+       struct nouveau_fb base;
+       struct page *r100c10_page;
+       dma_addr_t r100c10;
+};
+
+int  nvc0_fb_ctor(struct nouveau_object *, struct nouveau_object *,
+                 struct nouveau_oclass *, void *, u32,
+                 struct nouveau_object **);
+void nvc0_fb_dtor(struct nouveau_object *);
+int  nvc0_fb_init(struct nouveau_object *);
+bool nvc0_fb_memtype_valid(struct nouveau_fb *, u32);
+
+
+#define nvc0_ram_create(p,e,o,d)                                               \
+       nvc0_ram_create_((p), (e), (o), sizeof(**d), (void **)d)
+int  nvc0_ram_create_(struct nouveau_object *, struct nouveau_object *,
+                     struct nouveau_oclass *, int, void **);
+int  nvc0_ram_get(struct nouveau_fb *, u64, u32, u32, u32,
+                 struct nouveau_mem **);
+void nvc0_ram_put(struct nouveau_fb *, struct nouveau_mem **);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c
new file mode 100644 (file)
index 0000000..595db50
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nvc0.h"
+
+struct nouveau_oclass *
+nve0_fb_oclass = &(struct nouveau_fb_impl) {
+       .base.handle = NV_SUBDEV(FB, 0xe0),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvc0_fb_ctor,
+               .dtor = nvc0_fb_dtor,
+               .init = nvc0_fb_init,
+               .fini = _nouveau_fb_fini,
+       },
+       .memtype = nvc0_fb_memtype_valid,
+       .ram = &nve0_ram_oclass,
+}.base;
index db9d6dd..4931252 100644 (file)
@@ -12,6 +12,8 @@
 #define nouveau_ram_fini(p,s)                                                  \
        nouveau_object_fini(&(p)->base, (s))
 
+#define nouveau_ram_create_(p,e,o,s,d)                                         \
+       nouveau_object_create_((p), (e), (o), 0, (s), (void **)d)
 #define _nouveau_ram_dtor nouveau_object_destroy
 #define _nouveau_ram_init nouveau_object_init
 #define _nouveau_ram_fini nouveau_object_fini
@@ -26,10 +28,16 @@ extern struct nouveau_oclass nv44_ram_oclass;
 extern struct nouveau_oclass nv49_ram_oclass;
 extern struct nouveau_oclass nv4e_ram_oclass;
 extern struct nouveau_oclass nv50_ram_oclass;
+extern struct nouveau_oclass nva3_ram_oclass;
+extern struct nouveau_oclass nvaa_ram_oclass;
 extern struct nouveau_oclass nvc0_ram_oclass;
+extern struct nouveau_oclass nve0_ram_oclass;
 
-#define nouveau_fb_create(p,e,c,r,d)                                           \
-       nouveau_fb_create_((p), (e), (c), (r), sizeof(**d), (void **)d)
+int nouveau_sddr3_calc(struct nouveau_ram *ram);
+int nouveau_gddr5_calc(struct nouveau_ram *ram);
+
+#define nouveau_fb_create(p,e,c,d)                                             \
+       nouveau_fb_create_((p), (e), (c), sizeof(**d), (void **)d)
 #define nouveau_fb_destroy(p) ({                                               \
        struct nouveau_fb *pfb = (p);                                          \
        _nouveau_fb_dtor(nv_object(pfb));                                      \
@@ -44,44 +52,21 @@ extern struct nouveau_oclass nvc0_ram_oclass;
 })
 
 int nouveau_fb_create_(struct nouveau_object *, struct nouveau_object *,
-                      struct nouveau_oclass *, struct nouveau_oclass *,
-                      int length, void **pobject);
+                      struct nouveau_oclass *, int, void **);
 void _nouveau_fb_dtor(struct nouveau_object *);
 int  _nouveau_fb_init(struct nouveau_object *);
 int  _nouveau_fb_fini(struct nouveau_object *, bool);
 
-struct nouveau_bios;
-int  nouveau_fb_bios_memtype(struct nouveau_bios *);
+struct nouveau_fb_impl {
+       struct nouveau_oclass base;
+       struct nouveau_oclass *ram;
+       bool (*memtype)(struct nouveau_fb *, u32);
+};
 
 bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
+bool nv50_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
 
-void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-                      u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-                      u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int  nv30_fb_init(struct nouveau_object *);
-void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-                      u32 pitch, u32 flags, struct nouveau_fb_tile *);
-
-void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags,
-                      struct nouveau_fb_tile *);
-
-int  nv41_fb_init(struct nouveau_object *);
-void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int  nv44_fb_init(struct nouveau_object *);
-void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-                      u32 pitch, u32 flags, struct nouveau_fb_tile *);
-
-void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *);
-extern int nv50_fb_memtype[0x80];
+struct nouveau_bios;
+int  nouveau_fb_bios_memtype(struct nouveau_bios *);
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h
new file mode 100644 (file)
index 0000000..0f57fcf
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef __NVKM_FBRAM_FUC_H__
+#define __NVKM_FBRAM_FUC_H__
+
+#include <subdev/pwr.h>
+
+struct ramfuc {
+       struct nouveau_memx *memx;
+       struct nouveau_fb *pfb;
+       int sequence;
+};
+
+struct ramfuc_reg {
+       int sequence;
+       bool force;
+       u32 addr[2];
+       u32 data;
+};
+
+static inline struct ramfuc_reg
+ramfuc_reg2(u32 addr1, u32 addr2)
+{
+       return (struct ramfuc_reg) {
+               .sequence = 0,
+               .addr = { addr1, addr2 },
+               .data = 0xdeadbeef,
+       };
+}
+
+static inline struct ramfuc_reg
+ramfuc_reg(u32 addr)
+{
+       return ramfuc_reg2(addr, addr);
+}
+
+static inline int
+ramfuc_init(struct ramfuc *ram, struct nouveau_fb *pfb)
+{
+       struct nouveau_pwr *ppwr = nouveau_pwr(pfb);
+       int ret;
+
+       ret = nouveau_memx_init(ppwr, &ram->memx);
+       if (ret)
+               return ret;
+
+       ram->sequence++;
+       ram->pfb = pfb;
+       return 0;
+}
+
+static inline int
+ramfuc_exec(struct ramfuc *ram, bool exec)
+{
+       int ret = 0;
+       if (ram->pfb) {
+               ret = nouveau_memx_fini(&ram->memx, exec);
+               ram->pfb = NULL;
+       }
+       return ret;
+}
+
+static inline u32
+ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg)
+{
+       if (reg->sequence != ram->sequence)
+               reg->data = nv_rd32(ram->pfb, reg->addr[0]);
+       return reg->data;
+}
+
+static inline void
+ramfuc_wr32(struct ramfuc *ram, struct ramfuc_reg *reg, u32 data)
+{
+       reg->sequence = ram->sequence;
+       reg->data = data;
+       if (reg->addr[0] != reg->addr[1])
+               nouveau_memx_wr32(ram->memx, reg->addr[1], reg->data);
+       nouveau_memx_wr32(ram->memx, reg->addr[0], reg->data);
+}
+
+static inline void
+ramfuc_nuke(struct ramfuc *ram, struct ramfuc_reg *reg)
+{
+       reg->force = true;
+}
+
+static inline u32
+ramfuc_mask(struct ramfuc *ram, struct ramfuc_reg *reg, u32 mask, u32 data)
+{
+       u32 temp = ramfuc_rd32(ram, reg);
+       if (temp != ((temp & ~mask) | data) || reg->force) {
+               ramfuc_wr32(ram, reg, (temp & ~mask) | data);
+               reg->force = false;
+       }
+       return temp;
+}
+
+static inline void
+ramfuc_wait(struct ramfuc *ram, u32 addr, u32 mask, u32 data, u32 nsec)
+{
+       nouveau_memx_wait(ram->memx, addr, mask, data, nsec);
+}
+
+static inline void
+ramfuc_nsec(struct ramfuc *ram, u32 nsec)
+{
+       nouveau_memx_nsec(ram->memx, nsec);
+}
+
+#define ram_init(s,p)       ramfuc_init(&(s)->base, (p))
+#define ram_exec(s,e)       ramfuc_exec(&(s)->base, (e))
+#define ram_have(s,r)       ((s)->r_##r.addr != 0x000000)
+#define ram_rd32(s,r)       ramfuc_rd32(&(s)->base, &(s)->r_##r)
+#define ram_wr32(s,r,d)     ramfuc_wr32(&(s)->base, &(s)->r_##r, (d))
+#define ram_nuke(s,r)       ramfuc_nuke(&(s)->base, &(s)->r_##r)
+#define ram_mask(s,r,m,d)   ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d))
+#define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n))
+#define ram_nsec(s,n)       ramfuc_nsec(&(s)->base, (n))
+
+#endif
index ee49ac4..7648beb 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include "priv.h"
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/init.h>
+#include <subdev/clock.h>
+#include <subdev/clock/pll.h>
+#include <subdev/timer.h>
+
+#include <engine/fifo.h>
+
+#include "nv40.h"
+
+int
+nv40_ram_calc(struct nouveau_fb *pfb, u32 freq)
+{
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nv40_ram *ram = (void *)pfb->ram;
+       struct nvbios_pll pll;
+       int N1, M1, N2, M2;
+       int log2P, ret;
+
+       ret = nvbios_pll_parse(bios, 0x04, &pll);
+       if (ret) {
+               nv_error(pfb, "mclk pll data not found\n");
+               return ret;
+       }
+
+       ret = nv04_pll_calc(nv_subdev(pfb), &pll, freq,
+                           &N1, &M1, &N2, &M2, &log2P);
+       if (ret < 0)
+               return ret;
+
+       ram->ctrl  = 0x80000000 | (log2P << 16);
+       ram->ctrl |= min(pll.bias_p + log2P, (int)pll.max_p) << 20;
+       if (N2 == M2) {
+               ram->ctrl |= 0x00000100;
+               ram->coef  = (N1 << 8) | M1;
+       } else {
+               ram->ctrl |= 0x40000000;
+               ram->coef  = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
+       }
+
+       return 0;
+}
+
+int
+nv40_ram_prog(struct nouveau_fb *pfb)
+{
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nv40_ram *ram = (void *)pfb->ram;
+       struct bit_entry M;
+       u32 crtc_mask = 0;
+       u8  sr1[2];
+       int i;
+
+       /* determine which CRTCs are active, fetch VGA_SR1 for each */
+       for (i = 0; i < 2; i++) {
+               u32 vbl = nv_rd32(pfb, 0x600808 + (i * 0x2000));
+               u32 cnt = 0;
+               do {
+                       if (vbl != nv_rd32(pfb, 0x600808 + (i * 0x2000))) {
+                               nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
+                               sr1[i] = nv_rd08(pfb, 0x0c03c5 + (i * 0x2000));
+                               if (!(sr1[i] & 0x20))
+                                       crtc_mask |= (1 << i);
+                               break;
+                       }
+                       udelay(1);
+               } while (cnt++ < 32);
+       }
+
+       /* wait for vblank start on active crtcs, disable memory access */
+       for (i = 0; i < 2; i++) {
+               if (!(crtc_mask & (1 << i)))
+                       continue;
+               nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000);
+               nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
+               nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
+               nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
+       }
+
+       /* prepare ram for reclocking */
+       nv_wr32(pfb, 0x1002d4, 0x00000001); /* precharge */
+       nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */
+       nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */
+       nv_mask(pfb, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
+       nv_wr32(pfb, 0x1002dc, 0x00000001); /* enable self-refresh */
+
+       /* change the PLL of each memory partition */
+       nv_mask(pfb, 0x00c040, 0x0000c000, 0x00000000);
+       switch (nv_device(pfb)->chipset) {
+       case 0x40:
+       case 0x45:
+       case 0x41:
+       case 0x42:
+       case 0x47:
+               nv_mask(pfb, 0x004044, 0xc0771100, ram->ctrl);
+               nv_mask(pfb, 0x00402c, 0xc0771100, ram->ctrl);
+               nv_wr32(pfb, 0x004048, ram->coef);
+               nv_wr32(pfb, 0x004030, ram->coef);
+       case 0x43:
+       case 0x49:
+       case 0x4b:
+               nv_mask(pfb, 0x004038, 0xc0771100, ram->ctrl);
+               nv_wr32(pfb, 0x00403c, ram->coef);
+       default:
+               nv_mask(pfb, 0x004020, 0xc0771100, ram->ctrl);
+               nv_wr32(pfb, 0x004024, ram->coef);
+               break;
+       }
+       udelay(100);
+       nv_mask(pfb, 0x00c040, 0x0000c000, 0x0000c000);
+
+       /* re-enable normal operation of memory controller */
+       nv_wr32(pfb, 0x1002dc, 0x00000000);
+       nv_mask(pfb, 0x100210, 0x80000000, 0x80000000);
+       udelay(100);
+
+       /* execute memory reset script from vbios */
+       if (!bit_entry(bios, 'M', &M)) {
+               struct nvbios_init init = {
+                       .subdev = nv_subdev(pfb),
+                       .bios = bios,
+                       .offset = nv_ro16(bios, M.offset + 0x00),
+                       .execute = 1,
+               };
+
+               nvbios_exec(&init);
+       }
+
+       /* make sure we're in vblank (hopefully the same one as before), and
+        * then re-enable crtc memory access
+        */
+       for (i = 0; i < 2; i++) {
+               if (!(crtc_mask & (1 << i)))
+                       continue;
+               nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
+               nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
+               nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i]);
+       }
+
+       return 0;
+}
+
+void
+nv40_ram_tidy(struct nouveau_fb *pfb)
+{
+}
 
 static int
 nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
@@ -30,7 +177,7 @@ nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
                struct nouveau_object **pobject)
 {
        struct nouveau_fb *pfb = nouveau_fb(parent);
-       struct nouveau_ram *ram;
+       struct nv40_ram *ram;
        u32 pbus1218 = nv_rd32(pfb, 0x001218);
        int ret;
 
@@ -40,15 +187,18 @@ nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        switch (pbus1218 & 0x00000300) {
-       case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
-       case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
-       case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
-       case 0x00000300: ram->type = NV_MEM_TYPE_DDR2; break;
+       case 0x00000000: ram->base.type = NV_MEM_TYPE_SDRAM; break;
+       case 0x00000100: ram->base.type = NV_MEM_TYPE_DDR1; break;
+       case 0x00000200: ram->base.type = NV_MEM_TYPE_GDDR3; break;
+       case 0x00000300: ram->base.type = NV_MEM_TYPE_DDR2; break;
        }
 
-       ram->size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
-       ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-       ram->tags  =  nv_rd32(pfb, 0x100320);
+       ram->base.size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
+       ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+       ram->base.tags  =  nv_rd32(pfb, 0x100320);
+       ram->base.calc = nv40_ram_calc;
+       ram->base.prog = nv40_ram_prog;
+       ram->base.tidy = nv40_ram_tidy;
        return 0;
 }
 
index 1dab7e1..d64498a 100644 (file)
@@ -22,7 +22,7 @@
  * Authors: Ben Skeggs
  */
 
-#include "priv.h"
+#include "nv40.h"
 
 static int
 nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
@@ -30,7 +30,7 @@ nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
                struct nouveau_object **pobject)
 {
        struct nouveau_fb *pfb = nouveau_fb(parent);
-       struct nouveau_ram *ram;
+       struct nv40_ram *ram;
        u32 pfb474 = nv_rd32(pfb, 0x100474);
        int ret;
 
@@ -40,15 +40,18 @@ nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        if (pfb474 & 0x00000004)
-               ram->type = NV_MEM_TYPE_GDDR3;
+               ram->base.type = NV_MEM_TYPE_GDDR3;
        if (pfb474 & 0x00000002)
-               ram->type = NV_MEM_TYPE_DDR2;
+               ram->base.type = NV_MEM_TYPE_DDR2;
        if (pfb474 & 0x00000001)
-               ram->type = NV_MEM_TYPE_DDR1;
+               ram->base.type = NV_MEM_TYPE_DDR1;
 
-       ram->size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
-       ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-       ram->tags  =  nv_rd32(pfb, 0x100320);
+       ram->base.size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
+       ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+       ram->base.tags  =  nv_rd32(pfb, 0x100320);
+       ram->base.calc = nv40_ram_calc;
+       ram->base.prog = nv40_ram_prog;
+       ram->base.tidy = nv40_ram_tidy;
        return 0;
 }
 
index 25fff84..089acac 100644 (file)
@@ -22,7 +22,7 @@
  * Authors: Ben Skeggs
  */
 
-#include "priv.h"
+#include "nv40.h"
 
 static int
 nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
@@ -30,7 +30,7 @@ nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
                struct nouveau_object **pobject)
 {
        struct nouveau_fb *pfb = nouveau_fb(parent);
-       struct nouveau_ram *ram;
+       struct nv40_ram *ram;
        u32 pfb474 = nv_rd32(pfb, 0x100474);
        int ret;
 
@@ -40,13 +40,16 @@ nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        if (pfb474 & 0x00000004)
-               ram->type = NV_MEM_TYPE_GDDR3;
+               ram->base.type = NV_MEM_TYPE_GDDR3;
        if (pfb474 & 0x00000002)
-               ram->type = NV_MEM_TYPE_DDR2;
+               ram->base.type = NV_MEM_TYPE_DDR2;
        if (pfb474 & 0x00000001)
-               ram->type = NV_MEM_TYPE_DDR1;
+               ram->base.type = NV_MEM_TYPE_DDR1;
 
-       ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+       ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+       ram->base.calc = nv40_ram_calc;
+       ram->base.prog = nv40_ram_prog;
+       ram->base.tidy = nv40_ram_tidy;
        return 0;
 }
 
index ab7ef0a..baa013a 100644 (file)
@@ -22,7 +22,7 @@
  * Authors: Ben Skeggs
  */
 
-#include "priv.h"
+#include "nv40.h"
 
 static int
 nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
@@ -30,7 +30,7 @@ nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
                struct nouveau_object **pobject)
 {
        struct nouveau_fb *pfb = nouveau_fb(parent);
-       struct nouveau_ram *ram;
+       struct nv40_ram *ram;
        u32 pfb914 = nv_rd32(pfb, 0x100914);
        int ret;
 
@@ -40,15 +40,18 @@ nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        switch (pfb914 & 0x00000003) {
-       case 0x00000000: ram->type = NV_MEM_TYPE_DDR1; break;
-       case 0x00000001: ram->type = NV_MEM_TYPE_DDR2; break;
-       case 0x00000002: ram->type = NV_MEM_TYPE_GDDR3; break;
+       case 0x00000000: ram->base.type = NV_MEM_TYPE_DDR1; break;
+       case 0x00000001: ram->base.type = NV_MEM_TYPE_DDR2; break;
+       case 0x00000002: ram->base.type = NV_MEM_TYPE_GDDR3; break;
        case 0x00000003: break;
        }
 
-       ram->size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
-       ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-       ram->tags  =  nv_rd32(pfb, 0x100320);
+       ram->base.size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
+       ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+       ram->base.tags  =  nv_rd32(pfb, 0x100320);
+       ram->base.calc = nv40_ram_calc;
+       ram->base.prog = nv40_ram_prog;
+       ram->base.tidy = nv40_ram_tidy;
        return 0;
 }
 
index 903baff..76762a1 100644 (file)
  */
 
 #include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/perf.h>
+#include <subdev/bios/timing.h>
+#include <subdev/clock/pll.h>
+#include <subdev/fb.h>
+
+#include <core/option.h>
 #include <core/mm.h>
-#include "priv.h"
+
+#include "ramseq.h"
+
+#include "nv50.h"
+
+struct nv50_ramseq {
+       struct hwsq base;
+       struct hwsq_reg r_0x002504;
+       struct hwsq_reg r_0x004008;
+       struct hwsq_reg r_0x00400c;
+       struct hwsq_reg r_0x00c040;
+       struct hwsq_reg r_0x100210;
+       struct hwsq_reg r_0x1002d0;
+       struct hwsq_reg r_0x1002d4;
+       struct hwsq_reg r_0x1002dc;
+       struct hwsq_reg r_0x100da0[8];
+       struct hwsq_reg r_0x100e20;
+       struct hwsq_reg r_0x100e24;
+       struct hwsq_reg r_0x611200;
+       struct hwsq_reg r_timing[9];
+       struct hwsq_reg r_mr[4];
+};
+
+struct nv50_ram {
+       struct nouveau_ram base;
+       struct nv50_ramseq hwsq;
+};
+
+#define QFX5800NVA0 1
+
+static int
+nv50_ram_calc(struct nouveau_fb *pfb, u32 freq)
+{
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nv50_ram *ram = (void *)pfb->ram;
+       struct nv50_ramseq *hwsq = &ram->hwsq;
+       struct nvbios_perfE perfE;
+       struct nvbios_pll mpll;
+       struct bit_entry M;
+       struct {
+               u32 data;
+               u8  size;
+       } ramcfg, timing;
+       u8  ver, hdr, cnt, strap;
+       u32 data;
+       int N1, M1, N2, M2, P;
+       int ret, i;
+
+       /* lookup closest matching performance table entry for frequency */
+       i = 0;
+       do {
+               ramcfg.data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt,
+                                          &ramcfg.size, &perfE);
+               if (!ramcfg.data || (ver < 0x25 || ver >= 0x40) ||
+                   (ramcfg.size < 2)) {
+                       nv_error(pfb, "invalid/missing perftab entry\n");
+                       return -EINVAL;
+               }
+       } while (perfE.memory < freq);
+
+       /* locate specific data set for the attached memory */
+       if (bit_entry(bios, 'M', &M) || M.version != 1 || M.length < 5) {
+               nv_error(pfb, "invalid/missing memory table\n");
+               return -EINVAL;
+       }
+
+       strap = (nv_rd32(pfb, 0x101000) & 0x0000003c) >> 2;
+       data = nv_ro16(bios, M.offset + 3);
+       if (data)
+               strap = nv_ro08(bios, data + strap);
+
+       if (strap >= cnt) {
+               nv_error(pfb, "invalid ramcfg strap\n");
+               return -EINVAL;
+       }
+
+       ramcfg.data += hdr + (strap * ramcfg.size);
+
+       /* lookup memory timings, if bios says they're present */
+       strap = nv_ro08(bios, ramcfg.data + 0x01);
+       if (strap != 0xff) {
+               timing.data = nvbios_timing_entry(bios, strap, &ver, &hdr);
+               if (!timing.data || ver != 0x10 || hdr < 0x12) {
+                       nv_error(pfb, "invalid/missing timing entry "
+                                "%02x %04x %02x %02x\n",
+                                strap, timing.data, ver, hdr);
+                       return -EINVAL;
+               }
+       } else {
+               timing.data = 0;
+       }
+
+       ret = ram_init(hwsq, nv_subdev(pfb));
+       if (ret)
+               return ret;
+
+       ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */
+       ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */
+       ram_wr32(hwsq, 0x611200, 0x00003300);
+       ram_wr32(hwsq, 0x002504, 0x00000001); /* block fifo */
+       ram_nsec(hwsq, 8000);
+       ram_setf(hwsq, 0x10, 0x00); /* disable fb */
+       ram_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
+
+       ram_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge */
+       ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
+       ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
+       ram_wr32(hwsq, 0x100210, 0x00000000); /* disable auto-refresh */
+       ram_wr32(hwsq, 0x1002dc, 0x00000001); /* enable self-refresh */
+
+       ret = nvbios_pll_parse(bios, 0x004008, &mpll);
+       mpll.vco2.max_freq = 0;
+       if (ret == 0) {
+               ret = nv04_pll_calc(nv_subdev(pfb), &mpll, freq,
+                                  &N1, &M1, &N2, &M2, &P);
+               if (ret == 0)
+                       ret = -EINVAL;
+       }
+
+       if (ret < 0)
+               return ret;
+
+       ram_mask(hwsq, 0x00c040, 0xc000c000, 0x0000c000);
+       ram_mask(hwsq, 0x004008, 0x00000200, 0x00000200);
+       ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1);
+       ram_mask(hwsq, 0x004008, 0x81ff0000, 0x80000000 | (mpll.bias_p << 19) |
+                                            (P << 22) | (P << 16));
+#if QFX5800NVA0
+       for (i = 0; i < 8; i++)
+               ram_mask(hwsq, 0x100da0[i], 0x00000000, 0x00000000); /*XXX*/
+#endif
+       ram_nsec(hwsq, 96000); /*XXX*/
+       ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000);
+
+       ram_wr32(hwsq, 0x1002dc, 0x00000000); /* disable self-refresh */
+       ram_wr32(hwsq, 0x100210, 0x80000000); /* enable auto-refresh */
+
+       ram_nsec(hwsq, 12000);
+
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_DDR2:
+               ram_nuke(hwsq, mr[0]); /* force update */
+               ram_mask(hwsq, mr[0], 0x000, 0x000);
+               break;
+       case NV_MEM_TYPE_GDDR3:
+               ram_mask(hwsq, mr[2], 0x000, 0x000);
+               ram_nuke(hwsq, mr[0]); /* force update */
+               ram_mask(hwsq, mr[0], 0x000, 0x000);
+               break;
+       default:
+               break;
+       }
+
+       ram_mask(hwsq, timing[3], 0x00000000, 0x00000000); /*XXX*/
+       ram_mask(hwsq, timing[1], 0x00000000, 0x00000000); /*XXX*/
+       ram_mask(hwsq, timing[6], 0x00000000, 0x00000000); /*XXX*/
+       ram_mask(hwsq, timing[7], 0x00000000, 0x00000000); /*XXX*/
+       ram_mask(hwsq, timing[8], 0x00000000, 0x00000000); /*XXX*/
+       ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/
+       ram_mask(hwsq, timing[2], 0x00000000, 0x00000000); /*XXX*/
+       ram_mask(hwsq, timing[4], 0x00000000, 0x00000000); /*XXX*/
+       ram_mask(hwsq, timing[5], 0x00000000, 0x00000000); /*XXX*/
+
+       ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/
+
+#if QFX5800NVA0
+       ram_nuke(hwsq, 0x100e24);
+       ram_mask(hwsq, 0x100e24, 0x00000000, 0x00000000);
+       ram_nuke(hwsq, 0x100e20);
+       ram_mask(hwsq, 0x100e20, 0x00000000, 0x00000000);
+#endif
+
+       ram_mask(hwsq, mr[0], 0x100, 0x100);
+       ram_mask(hwsq, mr[0], 0x100, 0x000);
+
+       ram_setf(hwsq, 0x10, 0x01); /* enable fb */
+       ram_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
+       ram_wr32(hwsq, 0x611200, 0x00003330);
+       ram_wr32(hwsq, 0x002504, 0x00000000); /* un-block fifo */
+       return 0;
+}
+
+static int
+nv50_ram_prog(struct nouveau_fb *pfb)
+{
+       struct nouveau_device *device = nv_device(pfb);
+       struct nv50_ram *ram = (void *)pfb->ram;
+       struct nv50_ramseq *hwsq = &ram->hwsq;
+
+       ram_exec(hwsq, nouveau_boolopt(device->cfgopt, "NvMemExec", false));
+       return 0;
+}
+
+static void
+nv50_ram_tidy(struct nouveau_fb *pfb)
+{
+       struct nv50_ram *ram = (void *)pfb->ram;
+       struct nv50_ramseq *hwsq = &ram->hwsq;
+       ram_exec(hwsq, false);
+}
 
 void
 __nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem)
@@ -57,7 +264,7 @@ nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
        kfree(mem);
 }
 
-static int
+int
 nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
             u32 memtype, struct nouveau_mem **pmem)
 {
@@ -160,77 +367,114 @@ nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram)
        return rblock_size;
 }
 
-static int
-nv50_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-               struct nouveau_oclass *oclass, void *data, u32 datasize,
-               struct nouveau_object **pobject)
+int
+nv50_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
+                struct nouveau_oclass *oclass, int length, void **pobject)
 {
-       struct nouveau_fb *pfb = nouveau_fb(parent);
-       struct nouveau_device *device = nv_device(pfb);
-       struct nouveau_bios *bios = nouveau_bios(device);
-       struct nouveau_ram *ram;
        const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
        const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
-       u32 size;
+       struct nouveau_bios *bios = nouveau_bios(parent);
+       struct nouveau_fb *pfb = nouveau_fb(parent);
+       struct nouveau_ram *ram;
        int ret;
 
-       ret = nouveau_ram_create(parent, engine, oclass, &ram);
-       *pobject = nv_object(ram);
+       ret = nouveau_ram_create_(parent, engine, oclass, length, pobject);
+       ram = *pobject;
        if (ret)
                return ret;
 
        ram->size = nv_rd32(pfb, 0x10020c);
-       ram->size = (ram->size & 0xffffff00) |
-                      ((ram->size & 0x000000ff) << 32);
-
-       size = (ram->size >> 12) - rsvd_head - rsvd_tail;
-       switch (device->chipset) {
-       case 0xaa:
-       case 0xac:
-       case 0xaf: /* IGPs, no reordering, no real VRAM */
-               ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1);
-               if (ret)
-                       return ret;
+       ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32);
 
-               ram->type   = NV_MEM_TYPE_STOLEN;
-               ram->stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
+       switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
+       case 0: ram->type = NV_MEM_TYPE_DDR1; break;
+       case 1:
+               if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
+                       ram->type = NV_MEM_TYPE_DDR3;
+               else
+                       ram->type = NV_MEM_TYPE_DDR2;
                break;
+       case 2: ram->type = NV_MEM_TYPE_GDDR3; break;
+       case 3: ram->type = NV_MEM_TYPE_GDDR4; break;
+       case 4: ram->type = NV_MEM_TYPE_GDDR5; break;
        default:
-               switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
-               case 0: ram->type = NV_MEM_TYPE_DDR1; break;
-               case 1:
-                       if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
-                               ram->type = NV_MEM_TYPE_DDR3;
-                       else
-                               ram->type = NV_MEM_TYPE_DDR2;
-                       break;
-               case 2: ram->type = NV_MEM_TYPE_GDDR3; break;
-               case 3: ram->type = NV_MEM_TYPE_GDDR4; break;
-               case 4: ram->type = NV_MEM_TYPE_GDDR5; break;
-               default:
-                       break;
-               }
-
-               ret = nouveau_mm_init(&pfb->vram, rsvd_head, size,
-                                     nv50_fb_vram_rblock(pfb, ram) >> 12);
-               if (ret)
-                       return ret;
-
-               ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
-               ram->tags  =  nv_rd32(pfb, 0x100320);
                break;
        }
 
+       ret = nouveau_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) -
+                             (rsvd_head + rsvd_tail),
+                             nv50_fb_vram_rblock(pfb, ram) >> 12);
+       if (ret)
+               return ret;
+
+       ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
+       ram->tags  =  nv_rd32(pfb, 0x100320);
        ram->get = nv50_ram_get;
        ram->put = nv50_ram_put;
        return 0;
 }
 
+static int
+nv50_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+             struct nouveau_oclass *oclass, void *data, u32 datasize,
+             struct nouveau_object **pobject)
+{
+       struct nv50_ram *ram;
+       int ret, i;
+
+       ret = nv50_ram_create(parent, engine, oclass, &ram);
+       *pobject = nv_object(ram);
+       if (ret)
+               return ret;
+
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_DDR2:
+       case NV_MEM_TYPE_GDDR3:
+               ram->base.calc = nv50_ram_calc;
+               ram->base.prog = nv50_ram_prog;
+               ram->base.tidy = nv50_ram_tidy;
+               break;
+       default:
+               nv_warn(ram, "reclocking of this ram type unsupported\n");
+               return 0;
+       }
+
+       ram->hwsq.r_0x002504 = hwsq_reg(0x002504);
+       ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040);
+       ram->hwsq.r_0x004008 = hwsq_reg(0x004008);
+       ram->hwsq.r_0x00400c = hwsq_reg(0x00400c);
+       ram->hwsq.r_0x100210 = hwsq_reg(0x100210);
+       ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0);
+       ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4);
+       ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc);
+       for (i = 0; i < 8; i++)
+               ram->hwsq.r_0x100da0[i] = hwsq_reg(0x100da0 + (i * 0x04));
+       ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20);
+       ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24);
+       ram->hwsq.r_0x611200 = hwsq_reg(0x611200);
+
+       for (i = 0; i < 9; i++)
+               ram->hwsq.r_timing[i] = hwsq_reg(0x100220 + (i * 0x04));
+
+       if (ram->base.ranks > 1) {
+               ram->hwsq.r_mr[0] = hwsq_reg2(0x1002c0, 0x1002c8);
+               ram->hwsq.r_mr[1] = hwsq_reg2(0x1002c4, 0x1002cc);
+               ram->hwsq.r_mr[2] = hwsq_reg2(0x1002e0, 0x1002e8);
+               ram->hwsq.r_mr[3] = hwsq_reg2(0x1002e4, 0x1002ec);
+       } else {
+               ram->hwsq.r_mr[0] = hwsq_reg(0x1002c0);
+               ram->hwsq.r_mr[1] = hwsq_reg(0x1002c4);
+               ram->hwsq.r_mr[2] = hwsq_reg(0x1002e0);
+               ram->hwsq.r_mr[3] = hwsq_reg(0x1002e4);
+       }
+
+       return 0;
+}
+
 struct nouveau_oclass
 nv50_ram_oclass = {
-       .handle = 0,
        .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv50_ram_create,
+               .ctor = nv50_ram_ctor,
                .dtor = _nouveau_ram_dtor,
                .init = _nouveau_ram_init,
                .fini = _nouveau_ram_fini,
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c
new file mode 100644 (file)
index 0000000..f6292cd
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/rammap.h>
+#include <subdev/bios/timing.h>
+
+#include <subdev/clock/nva3.h>
+#include <subdev/clock/pll.h>
+
+#include <core/option.h>
+
+#include "ramfuc.h"
+
+#include "nv50.h"
+
+struct nva3_ramfuc {
+       struct ramfuc base;
+       struct ramfuc_reg r_0x004000;
+       struct ramfuc_reg r_0x004004;
+       struct ramfuc_reg r_0x004018;
+       struct ramfuc_reg r_0x004128;
+       struct ramfuc_reg r_0x004168;
+       struct ramfuc_reg r_0x100200;
+       struct ramfuc_reg r_0x100210;
+       struct ramfuc_reg r_0x100220[9];
+       struct ramfuc_reg r_0x1002d0;
+       struct ramfuc_reg r_0x1002d4;
+       struct ramfuc_reg r_0x1002dc;
+       struct ramfuc_reg r_0x10053c;
+       struct ramfuc_reg r_0x1005a0;
+       struct ramfuc_reg r_0x1005a4;
+       struct ramfuc_reg r_0x100714;
+       struct ramfuc_reg r_0x100718;
+       struct ramfuc_reg r_0x10071c;
+       struct ramfuc_reg r_0x100760;
+       struct ramfuc_reg r_0x1007a0;
+       struct ramfuc_reg r_0x1007e0;
+       struct ramfuc_reg r_0x10f804;
+       struct ramfuc_reg r_0x1110e0;
+       struct ramfuc_reg r_0x111100;
+       struct ramfuc_reg r_0x111104;
+       struct ramfuc_reg r_0x611200;
+       struct ramfuc_reg r_mr[4];
+};
+
+struct nva3_ram {
+       struct nouveau_ram base;
+       struct nva3_ramfuc fuc;
+};
+
+static int
+nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
+{
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nva3_ram *ram = (void *)pfb->ram;
+       struct nva3_ramfuc *fuc = &ram->fuc;
+       struct nva3_clock_info mclk;
+       struct bit_entry M;
+       u8  ver, cnt, strap;
+       u32 data;
+       struct {
+               u32 data;
+               u8  size;
+       } rammap, ramcfg, timing;
+       u32 r004018, r100760, ctrl;
+       u32 unk714, unk718, unk71c;
+       int ret;
+
+       /* lookup memory config data relevant to the target frequency */
+       rammap.data = nvbios_rammap_match(bios, freq / 1000, &ver, &rammap.size,
+                                        &cnt, &ramcfg.size);
+       if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
+               nv_error(pfb, "invalid/missing rammap entry\n");
+               return -EINVAL;
+       }
+
+       /* locate specific data set for the attached memory */
+       if (bit_entry(bios, 'M', &M) || M.version != 2 || M.length < 3) {
+               nv_error(pfb, "invalid/missing memory table\n");
+               return -EINVAL;
+       }
+
+       strap = (nv_rd32(pfb, 0x101000) & 0x0000003c) >> 2;
+       data = nv_ro16(bios, M.offset + 1);
+       if (data)
+               strap = nv_ro08(bios, data + strap);
+
+       if (strap >= cnt) {
+               nv_error(pfb, "invalid ramcfg strap\n");
+               return -EINVAL;
+       }
+
+       ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size);
+       if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) {
+               nv_error(pfb, "invalid/missing ramcfg entry\n");
+               return -EINVAL;
+       }
+
+       /* lookup memory timings, if bios says they're present */
+       strap = nv_ro08(bios, ramcfg.data + 0x01);
+       if (strap != 0xff) {
+               timing.data = nvbios_timing_entry(bios, strap, &ver,
+                                                &timing.size);
+               if (!timing.data || ver != 0x10 || timing.size < 0x19) {
+                       nv_error(pfb, "invalid/missing timing entry\n");
+                       return -EINVAL;
+               }
+       } else {
+               timing.data = 0;
+       }
+
+       ret = nva3_clock_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk);
+       if (ret < 0) {
+               nv_error(pfb, "failed mclk calculation\n");
+               return ret;
+       }
+
+       ret = ram_init(fuc, pfb);
+       if (ret)
+               return ret;
+
+       /* XXX: where the fuck does 750MHz come from? */
+       if (freq <= 750000) {
+               r004018 = 0x10000000;
+               r100760 = 0x22222222;
+       } else {
+               r004018 = 0x00000000;
+               r100760 = 0x00000000;
+       }
+
+       ctrl = ram_rd32(fuc, 0x004000);
+       if (ctrl & 0x00000008) {
+               if (mclk.pll) {
+                       ram_mask(fuc, 0x004128, 0x00000101, 0x00000101);
+                       ram_wr32(fuc, 0x004004, mclk.pll);
+                       ram_wr32(fuc, 0x004000, (ctrl |= 0x00000001));
+                       ram_wr32(fuc, 0x004000, (ctrl &= 0xffffffef));
+                       ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000);
+                       ram_wr32(fuc, 0x004000, (ctrl |= 0x00000010));
+                       ram_wr32(fuc, 0x004018, 0x00005000 | r004018);
+                       ram_wr32(fuc, 0x004000, (ctrl |= 0x00000004));
+               }
+       } else {
+               u32 ssel = 0x00000101;
+               if (mclk.clk)
+                       ssel |= mclk.clk;
+               else
+                       ssel |= 0x00080000; /* 324MHz, shouldn't matter... */
+               ram_mask(fuc, 0x004168, 0x003f3141, ctrl);
+       }
+
+       if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) {
+               ram_mask(fuc, 0x111104, 0x00000600, 0x00000000);
+       } else {
+               ram_mask(fuc, 0x111100, 0x40000000, 0x40000000);
+               ram_mask(fuc, 0x111104, 0x00000180, 0x00000000);
+       }
+
+       if (!(nv_ro08(bios, rammap.data + 0x04) & 0x02))
+               ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
+       ram_wr32(fuc, 0x611200, 0x00003300);
+       if (!(nv_ro08(bios, ramcfg.data + 0x02) & 0x10))
+               ram_wr32(fuc, 0x111100, 0x4c020000); /*XXX*/
+
+       ram_wr32(fuc, 0x1002d4, 0x00000001);
+       ram_wr32(fuc, 0x1002d0, 0x00000001);
+       ram_wr32(fuc, 0x1002d0, 0x00000001);
+       ram_wr32(fuc, 0x100210, 0x00000000);
+       ram_wr32(fuc, 0x1002dc, 0x00000001);
+       ram_nsec(fuc, 2000);
+
+       ctrl = ram_rd32(fuc, 0x004000);
+       if (!(ctrl & 0x00000008) && mclk.pll) {
+               ram_wr32(fuc, 0x004000, (ctrl |=  0x00000008));
+               ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
+               ram_wr32(fuc, 0x004018, 0x00001000);
+               ram_wr32(fuc, 0x004000, (ctrl &= ~0x00000001));
+               ram_wr32(fuc, 0x004004, mclk.pll);
+               ram_wr32(fuc, 0x004000, (ctrl |=  0x00000001));
+               udelay(64);
+               ram_wr32(fuc, 0x004018, 0x00005000 | r004018);
+               udelay(20);
+       } else
+       if (!mclk.pll) {
+               ram_mask(fuc, 0x004168, 0x003f3040, mclk.clk);
+               ram_wr32(fuc, 0x004000, (ctrl |= 0x00000008));
+               ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
+               ram_wr32(fuc, 0x004018, 0x0000d000 | r004018);
+       }
+
+       if ( (nv_ro08(bios, rammap.data + 0x04) & 0x08)) {
+               u32 unk5a0 = (nv_ro16(bios, ramcfg.data + 0x05) << 8) |
+                             nv_ro08(bios, ramcfg.data + 0x05);
+               u32 unk5a4 = (nv_ro16(bios, ramcfg.data + 0x07));
+               u32 unk804 = (nv_ro08(bios, ramcfg.data + 0x09) & 0xf0) << 16 |
+                            (nv_ro08(bios, ramcfg.data + 0x03) & 0x0f) << 16 |
+                            (nv_ro08(bios, ramcfg.data + 0x09) & 0x0f) |
+                            0x80000000;
+               ram_wr32(fuc, 0x1005a0, unk5a0);
+               ram_wr32(fuc, 0x1005a4, unk5a4);
+               ram_wr32(fuc, 0x10f804, unk804);
+               ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000);
+       } else {
+               ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000);
+               ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
+               ram_mask(fuc, 0x100760, 0x22222222, r100760);
+               ram_mask(fuc, 0x1007a0, 0x22222222, r100760);
+               ram_mask(fuc, 0x1007e0, 0x22222222, r100760);
+       }
+
+       if (mclk.pll) {
+               ram_mask(fuc, 0x1110e0, 0x00088000, 0x00011000);
+               ram_wr32(fuc, 0x004000, (ctrl &= ~0x00000008));
+       }
+
+       /*XXX: LEAVE */
+       ram_wr32(fuc, 0x1002dc, 0x00000000);
+       ram_wr32(fuc, 0x1002d4, 0x00000001);
+       ram_wr32(fuc, 0x100210, 0x80000000);
+       ram_nsec(fuc, 1000);
+       ram_nsec(fuc, 1000);
+
+       ram_mask(fuc, mr[2], 0x00000000, 0x00000000);
+       ram_nsec(fuc, 1000);
+       ram_nuke(fuc, mr[0]);
+       ram_mask(fuc, mr[0], 0x00000000, 0x00000000);
+       ram_nsec(fuc, 1000);
+
+       ram_mask(fuc, 0x100220[3], 0x00000000, 0x00000000);
+       ram_mask(fuc, 0x100220[1], 0x00000000, 0x00000000);
+       ram_mask(fuc, 0x100220[6], 0x00000000, 0x00000000);
+       ram_mask(fuc, 0x100220[7], 0x00000000, 0x00000000);
+       ram_mask(fuc, 0x100220[2], 0x00000000, 0x00000000);
+       ram_mask(fuc, 0x100220[4], 0x00000000, 0x00000000);
+       ram_mask(fuc, 0x100220[5], 0x00000000, 0x00000000);
+       ram_mask(fuc, 0x100220[0], 0x00000000, 0x00000000);
+       ram_mask(fuc, 0x100220[8], 0x00000000, 0x00000000);
+
+       data = (nv_ro08(bios, ramcfg.data + 0x02) & 0x08) ? 0x00000000 : 0x00001000;
+       ram_mask(fuc, 0x100200, 0x00001000, data);
+
+       unk714 = ram_rd32(fuc, 0x100714) & ~0xf0000010;
+       unk718 = ram_rd32(fuc, 0x100718) & ~0x00000100;
+       unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100;
+       if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x20))
+               unk714 |= 0xf0000000;
+       if (!(nv_ro08(bios, ramcfg.data + 0x02) & 0x04))
+               unk714 |= 0x00000010;
+       ram_wr32(fuc, 0x100714, unk714);
+
+       if (nv_ro08(bios, ramcfg.data + 0x02) & 0x01)
+               unk71c |= 0x00000100;
+       ram_wr32(fuc, 0x10071c, unk71c);
+
+       if (nv_ro08(bios, ramcfg.data + 0x02) & 0x02)
+               unk718 |= 0x00000100;
+       ram_wr32(fuc, 0x100718, unk718);
+
+       if (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)
+               ram_wr32(fuc, 0x111100, 0x48000000); /*XXX*/
+
+       ram_mask(fuc, mr[0], 0x100, 0x100);
+       ram_nsec(fuc, 1000);
+       ram_mask(fuc, mr[0], 0x100, 0x000);
+       ram_nsec(fuc, 1000);
+
+       ram_nsec(fuc, 2000);
+       ram_nsec(fuc, 12000);
+
+       ram_wr32(fuc, 0x611200, 0x00003330);
+       if ( (nv_ro08(bios, rammap.data + 0x04) & 0x02))
+               ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
+       if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) {
+               ram_mask(fuc, 0x111104, 0x00000180, 0x00000180);
+               ram_mask(fuc, 0x111100, 0x40000000, 0x00000000);
+       } else {
+               ram_mask(fuc, 0x111104, 0x00000600, 0x00000600);
+       }
+
+       if (mclk.pll) {
+               ram_mask(fuc, 0x004168, 0x00000001, 0x00000000);
+               ram_mask(fuc, 0x004168, 0x00000100, 0x00000000);
+       } else {
+               ram_mask(fuc, 0x004000, 0x00000001, 0x00000000);
+               ram_mask(fuc, 0x004128, 0x00000001, 0x00000000);
+               ram_mask(fuc, 0x004128, 0x00000100, 0x00000000);
+       }
+
+       return 0;
+}
+
+static int
+nva3_ram_prog(struct nouveau_fb *pfb)
+{
+       struct nouveau_device *device = nv_device(pfb);
+       struct nva3_ram *ram = (void *)pfb->ram;
+       struct nva3_ramfuc *fuc = &ram->fuc;
+       ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", false));
+       return 0;
+}
+
+static void
+nva3_ram_tidy(struct nouveau_fb *pfb)
+{
+       struct nva3_ram *ram = (void *)pfb->ram;
+       struct nva3_ramfuc *fuc = &ram->fuc;
+       ram_exec(fuc, false);
+}
+
+static int
+nva3_ram_init(struct nouveau_object *object)
+{
+       struct nouveau_fb *pfb = (void *)object->parent;
+       struct nva3_ram   *ram = (void *)object;
+       int ret, i;
+
+       ret = nouveau_ram_init(&ram->base);
+       if (ret)
+               return ret;
+
+       /* prepare for ddr link training, and load training patterns */
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_DDR3: {
+               static const u32 pattern[16] = {
+                       0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
+                       0x00000000, 0x11111111, 0x44444444, 0xdddddddd,
+                       0x33333333, 0x55555555, 0x77777777, 0x66666666,
+                       0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb,
+               };
+
+               nv_wr32(pfb, 0x100538, 0x10001ff6); /*XXX*/
+               nv_wr32(pfb, 0x1005a8, 0x0000ffff);
+               nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001);
+               for (i = 0; i < 0x30; i++) {
+                       nv_wr32(pfb, 0x10f8c0, (i << 8) | i);
+                       nv_wr32(pfb, 0x10f8e0, (i << 8) | i);
+                       nv_wr32(pfb, 0x10f900, pattern[i % 16]);
+                       nv_wr32(pfb, 0x10f920, pattern[i % 16]);
+               }
+       }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int
+nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+             struct nouveau_oclass *oclass, void *data, u32 datasize,
+             struct nouveau_object **pobject)
+{
+       struct nva3_ram *ram;
+       int ret, i;
+
+       ret = nv50_ram_create(parent, engine, oclass, &ram);
+       *pobject = nv_object(ram);
+       if (ret)
+               return ret;
+
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_DDR3:
+               ram->base.calc = nva3_ram_calc;
+               ram->base.prog = nva3_ram_prog;
+               ram->base.tidy = nva3_ram_tidy;
+               break;
+       default:
+               nv_warn(ram, "reclocking of this ram type unsupported\n");
+               return 0;
+       }
+
+       ram->fuc.r_0x004000 = ramfuc_reg(0x004000);
+       ram->fuc.r_0x004004 = ramfuc_reg(0x004004);
+       ram->fuc.r_0x004018 = ramfuc_reg(0x004018);
+       ram->fuc.r_0x004128 = ramfuc_reg(0x004128);
+       ram->fuc.r_0x004168 = ramfuc_reg(0x004168);
+       ram->fuc.r_0x100200 = ramfuc_reg(0x100200);
+       ram->fuc.r_0x100210 = ramfuc_reg(0x100210);
+       for (i = 0; i < 9; i++)
+               ram->fuc.r_0x100220[i] = ramfuc_reg(0x100220 + (i * 4));
+       ram->fuc.r_0x1002d0 = ramfuc_reg(0x1002d0);
+       ram->fuc.r_0x1002d4 = ramfuc_reg(0x1002d4);
+       ram->fuc.r_0x1002dc = ramfuc_reg(0x1002dc);
+       ram->fuc.r_0x10053c = ramfuc_reg(0x10053c);
+       ram->fuc.r_0x1005a0 = ramfuc_reg(0x1005a0);
+       ram->fuc.r_0x1005a4 = ramfuc_reg(0x1005a4);
+       ram->fuc.r_0x100714 = ramfuc_reg(0x100714);
+       ram->fuc.r_0x100718 = ramfuc_reg(0x100718);
+       ram->fuc.r_0x10071c = ramfuc_reg(0x10071c);
+       ram->fuc.r_0x100760 = ramfuc_reg(0x100760);
+       ram->fuc.r_0x1007a0 = ramfuc_reg(0x1007a0);
+       ram->fuc.r_0x1007e0 = ramfuc_reg(0x1007e0);
+       ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804);
+       ram->fuc.r_0x1110e0 = ramfuc_reg(0x1110e0);
+       ram->fuc.r_0x111100 = ramfuc_reg(0x111100);
+       ram->fuc.r_0x111104 = ramfuc_reg(0x111104);
+       ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
+
+       if (ram->base.ranks > 1) {
+               ram->fuc.r_mr[0] = ramfuc_reg2(0x1002c0, 0x1002c8);
+               ram->fuc.r_mr[1] = ramfuc_reg2(0x1002c4, 0x1002cc);
+               ram->fuc.r_mr[2] = ramfuc_reg2(0x1002e0, 0x1002e8);
+               ram->fuc.r_mr[3] = ramfuc_reg2(0x1002e4, 0x1002ec);
+       } else {
+               ram->fuc.r_mr[0] = ramfuc_reg(0x1002c0);
+               ram->fuc.r_mr[1] = ramfuc_reg(0x1002c4);
+               ram->fuc.r_mr[2] = ramfuc_reg(0x1002e0);
+               ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4);
+       }
+
+       return 0;
+}
+
+struct nouveau_oclass
+nva3_ram_oclass = {
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nva3_ram_ctor,
+               .dtor = _nouveau_ram_dtor,
+               .init = nva3_ram_init,
+               .fini = _nouveau_ram_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c
new file mode 100644 (file)
index 0000000..00f2ca7
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv50.h"
+
+static int
+nvaa_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+             struct nouveau_oclass *oclass, void *data, u32 datasize,
+             struct nouveau_object **pobject)
+{
+       const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+       const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+       struct nouveau_fb *pfb = nouveau_fb(parent);
+       struct nouveau_ram *ram;
+       int ret;
+
+       ret = nouveau_ram_create(parent, engine, oclass, &ram);
+       *pobject = nv_object(ram);
+       if (ret)
+               return ret;
+
+       ram->size = nv_rd32(pfb, 0x10020c);
+       ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32);
+
+       ret = nouveau_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) -
+                             (rsvd_head + rsvd_tail), 1);
+       if (ret)
+               return ret;
+
+       ram->type   = NV_MEM_TYPE_STOLEN;
+       ram->stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
+       ram->get = nv50_ram_get;
+       ram->put = nv50_ram_put;
+       return 0;
+}
+
+struct nouveau_oclass
+nvaa_ram_oclass = {
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvaa_ram_ctor,
+               .dtor = _nouveau_ram_dtor,
+               .init = _nouveau_ram_init,
+               .fini = _nouveau_ram_fini,
+       },
+};
index cf97c4d..f464547 100644 (file)
  */
 
 #include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/rammap.h>
+#include <subdev/bios/timing.h>
 #include <subdev/ltcg.h>
 
-#include "priv.h"
+#include <subdev/clock.h>
+#include <subdev/clock/pll.h>
+
+#include <core/option.h>
+
+#include "ramfuc.h"
+
+#include "nvc0.h"
+
+struct nvc0_ramfuc {
+       struct ramfuc base;
+
+       struct ramfuc_reg r_0x10fe20;
+       struct ramfuc_reg r_0x10fe24;
+       struct ramfuc_reg r_0x137320;
+       struct ramfuc_reg r_0x137330;
+
+       struct ramfuc_reg r_0x132000;
+       struct ramfuc_reg r_0x132004;
+       struct ramfuc_reg r_0x132100;
+
+       struct ramfuc_reg r_0x137390;
+
+       struct ramfuc_reg r_0x10f290;
+       struct ramfuc_reg r_0x10f294;
+       struct ramfuc_reg r_0x10f298;
+       struct ramfuc_reg r_0x10f29c;
+       struct ramfuc_reg r_0x10f2a0;
+
+       struct ramfuc_reg r_0x10f300;
+       struct ramfuc_reg r_0x10f338;
+       struct ramfuc_reg r_0x10f340;
+       struct ramfuc_reg r_0x10f344;
+       struct ramfuc_reg r_0x10f348;
+
+       struct ramfuc_reg r_0x10f910;
+       struct ramfuc_reg r_0x10f914;
+
+       struct ramfuc_reg r_0x100b0c;
+       struct ramfuc_reg r_0x10f050;
+       struct ramfuc_reg r_0x10f090;
+       struct ramfuc_reg r_0x10f200;
+       struct ramfuc_reg r_0x10f210;
+       struct ramfuc_reg r_0x10f310;
+       struct ramfuc_reg r_0x10f314;
+       struct ramfuc_reg r_0x10f610;
+       struct ramfuc_reg r_0x10f614;
+       struct ramfuc_reg r_0x10f800;
+       struct ramfuc_reg r_0x10f808;
+       struct ramfuc_reg r_0x10f824;
+       struct ramfuc_reg r_0x10f830;
+       struct ramfuc_reg r_0x10f988;
+       struct ramfuc_reg r_0x10f98c;
+       struct ramfuc_reg r_0x10f990;
+       struct ramfuc_reg r_0x10f998;
+       struct ramfuc_reg r_0x10f9b0;
+       struct ramfuc_reg r_0x10f9b4;
+       struct ramfuc_reg r_0x10fb04;
+       struct ramfuc_reg r_0x10fb08;
+       struct ramfuc_reg r_0x137300;
+       struct ramfuc_reg r_0x137310;
+       struct ramfuc_reg r_0x137360;
+       struct ramfuc_reg r_0x1373ec;
+       struct ramfuc_reg r_0x1373f0;
+       struct ramfuc_reg r_0x1373f8;
+
+       struct ramfuc_reg r_0x61c140;
+       struct ramfuc_reg r_0x611200;
+
+       struct ramfuc_reg r_0x13d8f4;
+};
+
+struct nvc0_ram {
+       struct nouveau_ram base;
+       struct nvc0_ramfuc fuc;
+       struct nvbios_pll refpll;
+       struct nvbios_pll mempll;
+};
+
+static void
+nvc0_ram_train(struct nvc0_ramfuc *fuc, u32 magic)
+{
+       struct nvc0_ram *ram = container_of(fuc, typeof(*ram), fuc);
+       struct nouveau_fb *pfb = nouveau_fb(ram);
+       u32 part = nv_rd32(pfb, 0x022438), i;
+       u32 mask = nv_rd32(pfb, 0x022554);
+       u32 addr = 0x110974;
+
+       ram_wr32(fuc, 0x10f910, magic);
+       ram_wr32(fuc, 0x10f914, magic);
+
+       for (i = 0; (magic & 0x80000000) && i < part; addr += 0x1000, i++) {
+               if (mask & (1 << i))
+                       continue;
+               ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
+       }
+}
+
+static int
+nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
+{
+       struct nouveau_clock *clk = nouveau_clock(pfb);
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nvc0_ram *ram = (void *)pfb->ram;
+       struct nvc0_ramfuc *fuc = &ram->fuc;
+       struct bit_entry M;
+       u8  ver, cnt, strap;
+       u32 data;
+       struct {
+               u32 data;
+               u8  size;
+       } rammap, ramcfg, timing;
+       int ref, div, out;
+       int from, mode;
+       int N1, M1, P;
+       int ret;
+
+       /* lookup memory config data relevant to the target frequency */
+       rammap.data = nvbios_rammap_match(bios, freq / 1000, &ver, &rammap.size,
+                                        &cnt, &ramcfg.size);
+       if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
+               nv_error(pfb, "invalid/missing rammap entry\n");
+               return -EINVAL;
+       }
+
+       /* locate specific data set for the attached memory */
+       if (bit_entry(bios, 'M', &M) || M.version != 2 || M.length < 3) {
+               nv_error(pfb, "invalid/missing memory table\n");
+               return -EINVAL;
+       }
+
+       strap = (nv_rd32(pfb, 0x101000) & 0x0000003c) >> 2;
+       data = nv_ro16(bios, M.offset + 1);
+       if (data)
+               strap = nv_ro08(bios, data + strap);
+
+       if (strap >= cnt) {
+               nv_error(pfb, "invalid ramcfg strap\n");
+               return -EINVAL;
+       }
+
+       ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size);
+       if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) {
+               nv_error(pfb, "invalid/missing ramcfg entry\n");
+               return -EINVAL;
+       }
+
+       /* lookup memory timings, if bios says they're present */
+       strap = nv_ro08(bios, ramcfg.data + 0x01);
+       if (strap != 0xff) {
+               timing.data = nvbios_timing_entry(bios, strap, &ver,
+                                                &timing.size);
+               if (!timing.data || ver != 0x10 || timing.size < 0x19) {
+                       nv_error(pfb, "invalid/missing timing entry\n");
+                       return -EINVAL;
+               }
+       } else {
+               timing.data = 0;
+       }
+
+       ret = ram_init(fuc, pfb);
+       if (ret)
+               return ret;
+
+       /* determine current mclk configuration */
+       from = !!(ram_rd32(fuc, 0x1373f0) & 0x00000002); /*XXX: ok? */
+
+       /* determine target mclk configuration */
+       if (!(ram_rd32(fuc, 0x137300) & 0x00000100))
+               ref = clk->read(clk, nv_clk_src_sppll0);
+       else
+               ref = clk->read(clk, nv_clk_src_sppll1);
+       div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2;
+       out = (ref * 2) / (div + 2);
+       mode = freq != out;
+
+       ram_mask(fuc, 0x137360, 0x00000002, 0x00000000);
+
+       if ((ram_rd32(fuc, 0x132000) & 0x00000002) || 0 /*XXX*/) {
+               ram_nuke(fuc, 0x132000);
+               ram_mask(fuc, 0x132000, 0x00000002, 0x00000002);
+               ram_mask(fuc, 0x132000, 0x00000002, 0x00000000);
+       }
+
+       if (mode == 1) {
+               ram_nuke(fuc, 0x10fe20);
+               ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000002);
+               ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000000);
+       }
+
+// 0x00020034 // 0x0000000a
+       ram_wr32(fuc, 0x132100, 0x00000001);
+
+       if (mode == 1 && from == 0) {
+               /* calculate refpll */
+               ret = nva3_pll_calc(nv_subdev(pfb), &ram->refpll,
+                                   ram->mempll.refclk, &N1, NULL, &M1, &P);
+               if (ret <= 0) {
+                       nv_error(pfb, "unable to calc refpll\n");
+                       return ret ? ret : -ERANGE;
+               }
+
+               ram_wr32(fuc, 0x10fe20, 0x20010000);
+               ram_wr32(fuc, 0x137320, 0x00000003);
+               ram_wr32(fuc, 0x137330, 0x81200006);
+               ram_wr32(fuc, 0x10fe24, (P << 16) | (N1 << 8) | M1);
+               ram_wr32(fuc, 0x10fe20, 0x20010001);
+               ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
+
+               /* calculate mempll */
+               ret = nva3_pll_calc(nv_subdev(pfb), &ram->mempll, freq,
+                                  &N1, NULL, &M1, &P);
+               if (ret <= 0) {
+                       nv_error(pfb, "unable to calc refpll\n");
+                       return ret ? ret : -ERANGE;
+               }
+
+               ram_wr32(fuc, 0x10fe20, 0x20010005);
+               ram_wr32(fuc, 0x132004, (P << 16) | (N1 << 8) | M1);
+               ram_wr32(fuc, 0x132000, 0x18010101);
+               ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
+       } else
+       if (mode == 0) {
+               ram_wr32(fuc, 0x137300, 0x00000003);
+       }
+
+       if (from == 0) {
+               ram_nuke(fuc, 0x10fb04);
+               ram_mask(fuc, 0x10fb04, 0x0000ffff, 0x00000000);
+               ram_nuke(fuc, 0x10fb08);
+               ram_mask(fuc, 0x10fb08, 0x0000ffff, 0x00000000);
+               ram_wr32(fuc, 0x10f988, 0x2004ff00);
+               ram_wr32(fuc, 0x10f98c, 0x003fc040);
+               ram_wr32(fuc, 0x10f990, 0x20012001);
+               ram_wr32(fuc, 0x10f998, 0x00011a00);
+               ram_wr32(fuc, 0x13d8f4, 0x00000000);
+       } else {
+               ram_wr32(fuc, 0x10f988, 0x20010000);
+               ram_wr32(fuc, 0x10f98c, 0x00000000);
+               ram_wr32(fuc, 0x10f990, 0x20012001);
+               ram_wr32(fuc, 0x10f998, 0x00010a00);
+       }
+
+       if (from == 0) {
+// 0x00020039 // 0x000000ba
+       }
+
+// 0x0002003a // 0x00000002
+       ram_wr32(fuc, 0x100b0c, 0x00080012);
+// 0x00030014 // 0x00000000 // 0x02b5f070
+// 0x00030014 // 0x00010000 // 0x02b5f070
+       ram_wr32(fuc, 0x611200, 0x00003300);
+// 0x00020034 // 0x0000000a
+// 0x00030020 // 0x00000001 // 0x00000000
+
+       ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
+       ram_wr32(fuc, 0x10f210, 0x00000000);
+       ram_nsec(fuc, 1000);
+       if (mode == 0)
+               nvc0_ram_train(fuc, 0x000c1001);
+       ram_wr32(fuc, 0x10f310, 0x00000001);
+       ram_nsec(fuc, 1000);
+       ram_wr32(fuc, 0x10f090, 0x00000061);
+       ram_wr32(fuc, 0x10f090, 0xc000007f);
+       ram_nsec(fuc, 1000);
+
+       if (from == 0) {
+               ram_wr32(fuc, 0x10f824, 0x00007fd4);
+       } else {
+               ram_wr32(fuc, 0x1373ec, 0x00020404);
+       }
+
+       if (mode == 0) {
+               ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
+               ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000);
+               ram_wr32(fuc, 0x10f830, 0x41500010);
+               ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+               ram_mask(fuc, 0x132100, 0x00000100, 0x00000100);
+               ram_wr32(fuc, 0x10f050, 0xff000090);
+               ram_wr32(fuc, 0x1373ec, 0x00020f0f);
+               ram_wr32(fuc, 0x1373f0, 0x00000003);
+               ram_wr32(fuc, 0x137310, 0x81201616);
+               ram_wr32(fuc, 0x132100, 0x00000001);
+// 0x00020039 // 0x000000ba
+               ram_wr32(fuc, 0x10f830, 0x00300017);
+               ram_wr32(fuc, 0x1373f0, 0x00000001);
+               ram_wr32(fuc, 0x10f824, 0x00007e77);
+               ram_wr32(fuc, 0x132000, 0x18030001);
+               ram_wr32(fuc, 0x10f090, 0x4000007e);
+               ram_nsec(fuc, 2000);
+               ram_wr32(fuc, 0x10f314, 0x00000001);
+               ram_wr32(fuc, 0x10f210, 0x80000000);
+               ram_wr32(fuc, 0x10f338, 0x00300220);
+               ram_wr32(fuc, 0x10f300, 0x0000011d);
+               ram_nsec(fuc, 1000);
+               ram_wr32(fuc, 0x10f290, 0x02060505);
+               ram_wr32(fuc, 0x10f294, 0x34208288);
+               ram_wr32(fuc, 0x10f298, 0x44050411);
+               ram_wr32(fuc, 0x10f29c, 0x0000114c);
+               ram_wr32(fuc, 0x10f2a0, 0x42e10069);
+               ram_wr32(fuc, 0x10f614, 0x40044f77);
+               ram_wr32(fuc, 0x10f610, 0x40044f77);
+               ram_wr32(fuc, 0x10f344, 0x00600009);
+               ram_nsec(fuc, 1000);
+               ram_wr32(fuc, 0x10f348, 0x00700008);
+               ram_wr32(fuc, 0x61c140, 0x19240000);
+               ram_wr32(fuc, 0x10f830, 0x00300017);
+               nvc0_ram_train(fuc, 0x80021001);
+               nvc0_ram_train(fuc, 0x80081001);
+               ram_wr32(fuc, 0x10f340, 0x00500004);
+               ram_nsec(fuc, 1000);
+               ram_wr32(fuc, 0x10f830, 0x01300017);
+               ram_wr32(fuc, 0x10f830, 0x00300017);
+// 0x00030020 // 0x00000000 // 0x00000000
+// 0x00020034 // 0x0000000b
+               ram_wr32(fuc, 0x100b0c, 0x00080028);
+               ram_wr32(fuc, 0x611200, 0x00003330);
+       } else {
+               ram_wr32(fuc, 0x10f800, 0x00001800);
+               ram_wr32(fuc, 0x13d8f4, 0x00000000);
+               ram_wr32(fuc, 0x1373ec, 0x00020404);
+               ram_wr32(fuc, 0x1373f0, 0x00000003);
+               ram_wr32(fuc, 0x10f830, 0x40700010);
+               ram_wr32(fuc, 0x10f830, 0x40500010);
+               ram_wr32(fuc, 0x13d8f4, 0x00000000);
+               ram_wr32(fuc, 0x1373f8, 0x00000000);
+               ram_wr32(fuc, 0x132100, 0x00000101);
+               ram_wr32(fuc, 0x137310, 0x89201616);
+               ram_wr32(fuc, 0x10f050, 0xff000090);
+               ram_wr32(fuc, 0x1373ec, 0x00030404);
+               ram_wr32(fuc, 0x1373f0, 0x00000002);
+       // 0x00020039 // 0x00000011
+               ram_wr32(fuc, 0x132100, 0x00000001);
+               ram_wr32(fuc, 0x1373f8, 0x00002000);
+               ram_nsec(fuc, 2000);
+               ram_wr32(fuc, 0x10f808, 0x7aaa0050);
+               ram_wr32(fuc, 0x10f830, 0x00500010);
+               ram_wr32(fuc, 0x10f200, 0x00ce1000);
+               ram_wr32(fuc, 0x10f090, 0x4000007e);
+               ram_nsec(fuc, 2000);
+               ram_wr32(fuc, 0x10f314, 0x00000001);
+               ram_wr32(fuc, 0x10f210, 0x80000000);
+               ram_wr32(fuc, 0x10f338, 0x00300200);
+               ram_wr32(fuc, 0x10f300, 0x0000084d);
+               ram_nsec(fuc, 1000);
+               ram_wr32(fuc, 0x10f290, 0x0b343825);
+               ram_wr32(fuc, 0x10f294, 0x3483028e);
+               ram_wr32(fuc, 0x10f298, 0x440c0600);
+               ram_wr32(fuc, 0x10f29c, 0x0000214c);
+               ram_wr32(fuc, 0x10f2a0, 0x42e20069);
+               ram_wr32(fuc, 0x10f200, 0x00ce0000);
+               ram_wr32(fuc, 0x10f614, 0x60044e77);
+               ram_wr32(fuc, 0x10f610, 0x60044e77);
+               ram_wr32(fuc, 0x10f340, 0x00500000);
+               ram_nsec(fuc, 1000);
+               ram_wr32(fuc, 0x10f344, 0x00600228);
+               ram_nsec(fuc, 1000);
+               ram_wr32(fuc, 0x10f348, 0x00700000);
+               ram_wr32(fuc, 0x13d8f4, 0x00000000);
+               ram_wr32(fuc, 0x61c140, 0x09a40000);
+
+               nvc0_ram_train(fuc, 0x800e1008);
+
+               ram_nsec(fuc, 1000);
+               ram_wr32(fuc, 0x10f800, 0x00001804);
+       // 0x00030020 // 0x00000000 // 0x00000000
+       // 0x00020034 // 0x0000000b
+               ram_wr32(fuc, 0x13d8f4, 0x00000000);
+               ram_wr32(fuc, 0x100b0c, 0x00080028);
+               ram_wr32(fuc, 0x611200, 0x00003330);
+               ram_nsec(fuc, 100000);
+               ram_wr32(fuc, 0x10f9b0, 0x05313f41);
+               ram_wr32(fuc, 0x10f9b4, 0x00002f50);
+
+               nvc0_ram_train(fuc, 0x010c1001);
+       }
+
+       ram_mask(fuc, 0x10f200, 0x00000800, 0x00000800);
+// 0x00020016 // 0x00000000
+
+       if (mode == 0)
+               ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+       return 0;
+}
+
+static int
+nvc0_ram_prog(struct nouveau_fb *pfb)
+{
+       struct nouveau_device *device = nv_device(pfb);
+       struct nvc0_ram *ram = (void *)pfb->ram;
+       struct nvc0_ramfuc *fuc = &ram->fuc;
+       ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", false));
+       return 0;
+}
+
+static void
+nvc0_ram_tidy(struct nouveau_fb *pfb)
+{
+       struct nvc0_ram *ram = (void *)pfb->ram;
+       struct nvc0_ramfuc *fuc = &ram->fuc;
+       ram_exec(fuc, false);
+}
 
 extern const u8 nvc0_pte_storage_type_map[256];
 
@@ -110,10 +515,9 @@ nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
        return 0;
 }
 
-static int
-nvc0_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-               struct nouveau_oclass *oclass, void *data, u32 size,
-               struct nouveau_object **pobject)
+int
+nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
+                struct nouveau_oclass *oclass, int size, void **pobject)
 {
        struct nouveau_fb *pfb = nouveau_fb(parent);
        struct nouveau_bios *bios = nouveau_bios(pfb);
@@ -127,8 +531,8 @@ nvc0_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
        bool uniform = true;
        int ret, part;
 
-       ret = nouveau_ram_create(parent, engine, oclass, &ram);
-       *pobject = nv_object(ram);
+       ret = nouveau_ram_create_(parent, engine, oclass, size, pobject);
+       ram = *pobject;
        if (ret)
                return ret;
 
@@ -182,13 +586,158 @@ nvc0_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
+static int
+nvc0_ram_init(struct nouveau_object *object)
+{
+       struct nouveau_fb *pfb = (void *)object->parent;
+       struct nvc0_ram   *ram = (void *)object;
+       int ret, i;
+
+       ret = nouveau_ram_init(&ram->base);
+       if (ret)
+               return ret;
+
+       /* prepare for ddr link training, and load training patterns */
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_GDDR5: {
+               static const u8  train0[] = {
+                       0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc,
+                       0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
+               };
+               static const u32 train1[] = {
+                       0x00000000, 0xffffffff,
+                       0x55555555, 0xaaaaaaaa,
+                       0x33333333, 0xcccccccc,
+                       0xf0f0f0f0, 0x0f0f0f0f,
+                       0x00ff00ff, 0xff00ff00,
+                       0x0000ffff, 0xffff0000,
+               };
+
+               for (i = 0; i < 0x30; i++) {
+                       nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8));
+                       nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8));
+                       nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]);
+                       nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]);
+                       nv_wr32(pfb, 0x10f918,              train1[i % 12]);
+                       nv_wr32(pfb, 0x10f91c,              train1[i % 12]);
+                       nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]);
+                       nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]);
+                       nv_wr32(pfb, 0x10f918,              train1[i % 12]);
+                       nv_wr32(pfb, 0x10f91c,              train1[i % 12]);
+               }
+       }       break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int
+nvc0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+             struct nouveau_oclass *oclass, void *data, u32 size,
+             struct nouveau_object **pobject)
+{
+       struct nouveau_bios *bios = nouveau_bios(parent);
+       struct nvc0_ram *ram;
+       int ret;
+
+       ret = nvc0_ram_create(parent, engine, oclass, &ram);
+       *pobject = nv_object(ram);
+       if (ret)
+               return ret;
+
+       ret = nvbios_pll_parse(bios, 0x0c, &ram->refpll);
+       if (ret) {
+               nv_error(ram, "mclk refpll data not found\n");
+               return ret;
+       }
+
+       ret = nvbios_pll_parse(bios, 0x04, &ram->mempll);
+       if (ret) {
+               nv_error(ram, "mclk pll data not found\n");
+               return ret;
+       }
+
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_GDDR5:
+               ram->base.calc = nvc0_ram_calc;
+               ram->base.prog = nvc0_ram_prog;
+               ram->base.tidy = nvc0_ram_tidy;
+               break;
+       default:
+               nv_warn(ram, "reclocking of this ram type unsupported\n");
+               return 0;
+       }
+
+       ram->fuc.r_0x10fe20 = ramfuc_reg(0x10fe20);
+       ram->fuc.r_0x10fe24 = ramfuc_reg(0x10fe24);
+       ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
+       ram->fuc.r_0x137330 = ramfuc_reg(0x137330);
+
+       ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
+       ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
+       ram->fuc.r_0x132100 = ramfuc_reg(0x132100);
+
+       ram->fuc.r_0x137390 = ramfuc_reg(0x137390);
+
+       ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
+       ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
+       ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
+       ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
+       ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
+
+       ram->fuc.r_0x10f300 = ramfuc_reg(0x10f300);
+       ram->fuc.r_0x10f338 = ramfuc_reg(0x10f338);
+       ram->fuc.r_0x10f340 = ramfuc_reg(0x10f340);
+       ram->fuc.r_0x10f344 = ramfuc_reg(0x10f344);
+       ram->fuc.r_0x10f348 = ramfuc_reg(0x10f348);
+
+       ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
+       ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
+
+       ram->fuc.r_0x100b0c = ramfuc_reg(0x100b0c);
+       ram->fuc.r_0x10f050 = ramfuc_reg(0x10f050);
+       ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
+       ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
+       ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
+       ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
+       ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
+       ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
+       ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
+       ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
+       ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
+       ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
+       ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
+       ram->fuc.r_0x10f988 = ramfuc_reg(0x10f988);
+       ram->fuc.r_0x10f98c = ramfuc_reg(0x10f98c);
+       ram->fuc.r_0x10f990 = ramfuc_reg(0x10f990);
+       ram->fuc.r_0x10f998 = ramfuc_reg(0x10f998);
+       ram->fuc.r_0x10f9b0 = ramfuc_reg(0x10f9b0);
+       ram->fuc.r_0x10f9b4 = ramfuc_reg(0x10f9b4);
+       ram->fuc.r_0x10fb04 = ramfuc_reg(0x10fb04);
+       ram->fuc.r_0x10fb08 = ramfuc_reg(0x10fb08);
+       ram->fuc.r_0x137310 = ramfuc_reg(0x137300);
+       ram->fuc.r_0x137310 = ramfuc_reg(0x137310);
+       ram->fuc.r_0x137360 = ramfuc_reg(0x137360);
+       ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
+       ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
+       ram->fuc.r_0x1373f8 = ramfuc_reg(0x1373f8);
+
+       ram->fuc.r_0x61c140 = ramfuc_reg(0x61c140);
+       ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
+
+       ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4);
+       return 0;
+}
+
 struct nouveau_oclass
 nvc0_ram_oclass = {
        .handle = 0,
        .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nvc0_ram_create,
+               .ctor = nvc0_ram_ctor,
                .dtor = _nouveau_ram_dtor,
-               .init = _nouveau_ram_init,
+               .init = nvc0_ram_init,
                .fini = _nouveau_ram_fini,
        }
 };
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c
new file mode 100644 (file)
index 0000000..bc86cfd
--- /dev/null
@@ -0,0 +1,1264 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/gpio.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/rammap.h>
+#include <subdev/bios/timing.h>
+
+#include <subdev/clock.h>
+#include <subdev/clock/pll.h>
+
+#include <subdev/timer.h>
+
+#include <core/option.h>
+
+#include "nvc0.h"
+
+#include "ramfuc.h"
+
+struct nve0_ramfuc {
+       struct ramfuc base;
+
+       struct nvbios_pll refpll;
+       struct nvbios_pll mempll;
+
+       struct ramfuc_reg r_gpioMV;
+       u32 r_funcMV[2];
+       struct ramfuc_reg r_gpio2E;
+       u32 r_func2E[2];
+       struct ramfuc_reg r_gpiotrig;
+
+       struct ramfuc_reg r_0x132020;
+       struct ramfuc_reg r_0x132028;
+       struct ramfuc_reg r_0x132024;
+       struct ramfuc_reg r_0x132030;
+       struct ramfuc_reg r_0x132034;
+       struct ramfuc_reg r_0x132000;
+       struct ramfuc_reg r_0x132004;
+       struct ramfuc_reg r_0x132040;
+
+       struct ramfuc_reg r_0x10f248;
+       struct ramfuc_reg r_0x10f290;
+       struct ramfuc_reg r_0x10f294;
+       struct ramfuc_reg r_0x10f298;
+       struct ramfuc_reg r_0x10f29c;
+       struct ramfuc_reg r_0x10f2a0;
+       struct ramfuc_reg r_0x10f2a4;
+       struct ramfuc_reg r_0x10f2a8;
+       struct ramfuc_reg r_0x10f2ac;
+       struct ramfuc_reg r_0x10f2cc;
+       struct ramfuc_reg r_0x10f2e8;
+       struct ramfuc_reg r_0x10f250;
+       struct ramfuc_reg r_0x10f24c;
+       struct ramfuc_reg r_0x10fec4;
+       struct ramfuc_reg r_0x10fec8;
+       struct ramfuc_reg r_0x10f604;
+       struct ramfuc_reg r_0x10f614;
+       struct ramfuc_reg r_0x10f610;
+       struct ramfuc_reg r_0x100770;
+       struct ramfuc_reg r_0x100778;
+       struct ramfuc_reg r_0x10f224;
+
+       struct ramfuc_reg r_0x10f870;
+       struct ramfuc_reg r_0x10f698;
+       struct ramfuc_reg r_0x10f694;
+       struct ramfuc_reg r_0x10f6b8;
+       struct ramfuc_reg r_0x10f808;
+       struct ramfuc_reg r_0x10f670;
+       struct ramfuc_reg r_0x10f60c;
+       struct ramfuc_reg r_0x10f830;
+       struct ramfuc_reg r_0x1373ec;
+       struct ramfuc_reg r_0x10f800;
+       struct ramfuc_reg r_0x10f82c;
+
+       struct ramfuc_reg r_0x10f978;
+       struct ramfuc_reg r_0x10f910;
+       struct ramfuc_reg r_0x10f914;
+
+       struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */
+
+       struct ramfuc_reg r_0x62c000;
+       struct ramfuc_reg r_0x10f200;
+       struct ramfuc_reg r_0x10f210;
+       struct ramfuc_reg r_0x10f310;
+       struct ramfuc_reg r_0x10f314;
+       struct ramfuc_reg r_0x10f318;
+       struct ramfuc_reg r_0x10f090;
+       struct ramfuc_reg r_0x10f69c;
+       struct ramfuc_reg r_0x10f824;
+       struct ramfuc_reg r_0x1373f0;
+       struct ramfuc_reg r_0x1373f4;
+       struct ramfuc_reg r_0x137320;
+       struct ramfuc_reg r_0x10f65c;
+       struct ramfuc_reg r_0x10f6bc;
+       struct ramfuc_reg r_0x100710;
+       struct ramfuc_reg r_0x10f750;
+};
+
+struct nve0_ram {
+       struct nouveau_ram base;
+       struct nve0_ramfuc fuc;
+       int from;
+       int mode;
+       int N1, fN1, M1, P1;
+       int N2, M2, P2;
+};
+
+/*******************************************************************************
+ * GDDR5
+ ******************************************************************************/
+static void
+train(struct nve0_ramfuc *fuc, u32 magic)
+{
+       struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
+       struct nouveau_fb *pfb = nouveau_fb(ram);
+       const int mc = nv_rd32(pfb, 0x02243c);
+       int i;
+
+       ram_mask(fuc, 0x10f910, 0xbc0e0000, magic);
+       ram_mask(fuc, 0x10f914, 0xbc0e0000, magic);
+       for (i = 0; i < mc; i++) {
+               const u32 addr = 0x110974 + (i * 0x1000);
+               ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
+       }
+}
+
+static void
+r1373f4_init(struct nve0_ramfuc *fuc)
+{
+       struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
+       const u32 mcoef = ((--ram->P2 << 28) | (ram->N2 << 8) | ram->M2);
+       const u32 rcoef = ((  ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
+       const u32 runk0 = ram->fN1 << 16;
+       const u32 runk1 = ram->fN1;
+
+       if (ram->from == 2) {
+               ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100);
+               ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010);
+       } else {
+               ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
+       }
+
+       ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
+       ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
+
+       /* (re)program refpll, if required */
+       if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef ||
+           (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) {
+               ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+               ram_mask(fuc, 0x132020, 0x00000001, 0x00000000);
+               ram_wr32(fuc, 0x137320, 0x00000000);
+               ram_mask(fuc, 0x132030, 0xffff0000, runk0);
+               ram_mask(fuc, 0x132034, 0x0000ffff, runk1);
+               ram_wr32(fuc, 0x132024, rcoef);
+               ram_mask(fuc, 0x132028, 0x00080000, 0x00080000);
+               ram_mask(fuc, 0x132020, 0x00000001, 0x00000001);
+               ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
+               ram_mask(fuc, 0x132028, 0x00080000, 0x00000000);
+       }
+
+       /* (re)program mempll, if required */
+       if (ram->mode == 2) {
+               ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
+               ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+               ram_mask(fuc, 0x132004, 0x103fffff, mcoef);
+               ram_mask(fuc, 0x132000, 0x00000001, 0x00000001);
+               ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
+               ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100);
+       } else {
+               ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010100);
+       }
+
+       ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010);
+}
+
+static void
+r1373f4_fini(struct nve0_ramfuc *fuc, u32 ramcfg)
+{
+       struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
+       struct nouveau_bios *bios = nouveau_bios(ram);
+       u8 v0 = (nv_ro08(bios, ramcfg + 0x03) & 0xc0) >> 6;
+       u8 v1 = (nv_ro08(bios, ramcfg + 0x03) & 0x30) >> 4;
+       u32 tmp;
+
+       tmp = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
+       ram_wr32(fuc, 0x1373ec, tmp | (v1 << 16));
+       ram_mask(fuc, 0x1373f0, (~ram->mode & 3), 0x00000000);
+       if (ram->mode == 2) {
+               ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000002);
+               ram_mask(fuc, 0x1373f4, 0x00001100, 0x000000000);
+       } else {
+               ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000001);
+               ram_mask(fuc, 0x1373f4, 0x00010000, 0x000000000);
+       }
+       ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4);
+}
+
+static int
+nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
+{
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nve0_ram *ram = (void *)pfb->ram;
+       struct nve0_ramfuc *fuc = &ram->fuc;
+       const u32 rammap = ram->base.rammap.data;
+       const u32 ramcfg = ram->base.ramcfg.data;
+       const u32 timing = ram->base.timing.data;
+       int vc = !(nv_ro08(bios, ramcfg + 0x02) & 0x08);
+       int mv = 1; /*XXX*/
+       u32 mask, data;
+
+       ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
+       ram_wr32(fuc, 0x62c000, 0x0f0f0000);
+
+       /* MR1: turn termination on early, for some reason.. */
+       if ((ram->base.mr[1] & 0x03c) != 0x030)
+               ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c);
+
+       if (vc == 1 && ram_have(fuc, gpio2E)) {
+               u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
+               if (temp != ram_rd32(fuc, gpio2E)) {
+                       ram_wr32(fuc, gpiotrig, 1);
+                       ram_nsec(fuc, 20000);
+               }
+       }
+
+       ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
+
+       ram_mask(fuc, 0x10f914, 0x01020000, 0x000c0000);
+       ram_mask(fuc, 0x10f910, 0x01020000, 0x000c0000);
+
+       ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
+       ram_nsec(fuc, 1000);
+       ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+       ram_nsec(fuc, 1000);
+
+       ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+       ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+       ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+       ram_wr32(fuc, 0x10f090, 0x00000061);
+       ram_wr32(fuc, 0x10f090, 0xc000007f);
+       ram_nsec(fuc, 1000);
+
+       ram_wr32(fuc, 0x10f698, 0x00000000);
+       ram_wr32(fuc, 0x10f69c, 0x00000000);
+
+       /*XXX: there does appear to be some kind of condition here, simply
+        *     modifying these bits in the vbios from the default pl0
+        *     entries shows no change.  however, the data does appear to
+        *     be correct and may be required for the transition back
+        */
+       mask = 0x800f07e0;
+       data = 0x00030000;
+       if (ram_rd32(fuc, 0x10f978) & 0x00800000)
+               data |= 0x00040000;
+
+       if (1) {
+               data |= 0x800807e0;
+               switch (nv_ro08(bios, ramcfg + 0x03) & 0xc0) {
+               case 0xc0: data &= ~0x00000040; break;
+               case 0x80: data &= ~0x00000100; break;
+               case 0x40: data &= ~0x80000000; break;
+               case 0x00: data &= ~0x00000400; break;
+               }
+
+               switch (nv_ro08(bios, ramcfg + 0x03) & 0x30) {
+               case 0x30: data &= ~0x00000020; break;
+               case 0x20: data &= ~0x00000080; break;
+               case 0x10: data &= ~0x00080000; break;
+               case 0x00: data &= ~0x00000200; break;
+               }
+       }
+
+       if (nv_ro08(bios, ramcfg + 0x02) & 0x80)
+               mask |= 0x03000000;
+       if (nv_ro08(bios, ramcfg + 0x02) & 0x40)
+               mask |= 0x00002000;
+       if (nv_ro08(bios, ramcfg + 0x07) & 0x10)
+               mask |= 0x00004000;
+       if (nv_ro08(bios, ramcfg + 0x07) & 0x08)
+               mask |= 0x00000003;
+       else {
+               mask |= 0x34000000;
+               if (ram_rd32(fuc, 0x10f978) & 0x00800000)
+                       mask |= 0x40000000;
+       }
+       ram_mask(fuc, 0x10f824, mask, data);
+
+       ram_mask(fuc, 0x132040, 0x00010000, 0x00000000);
+
+       if (ram->from == 2 && ram->mode != 2) {
+               ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
+               ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000);
+               ram_mask(fuc, 0x10f800, 0x00000000, 0x00000004);
+               ram_mask(fuc, 0x10f830, 0x00008000, 0x01040010);
+               ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+               r1373f4_init(fuc);
+               ram_mask(fuc, 0x1373f0, 0x00000002, 0x00000001);
+               r1373f4_fini(fuc, ramcfg);
+               ram_mask(fuc, 0x10f830, 0x00c00000, 0x00240001);
+       } else
+       if (ram->from != 2 && ram->mode != 2) {
+               r1373f4_init(fuc);
+               r1373f4_fini(fuc, ramcfg);
+       }
+
+       if (ram_have(fuc, gpioMV)) {
+               u32 temp  = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]);
+               if (temp != ram_rd32(fuc, gpioMV)) {
+                       ram_wr32(fuc, gpiotrig, 1);
+                       ram_nsec(fuc, 64000);
+               }
+       }
+
+       if ( (nv_ro08(bios, ramcfg + 0x02) & 0x40) ||
+            (nv_ro08(bios, ramcfg + 0x07) & 0x10)) {
+               ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
+               ram_nsec(fuc, 20000);
+       }
+
+       if (ram->from != 2 && ram->mode == 2) {
+               ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
+               ram_mask(fuc, 0x1373f0, 0x00000000, 0x00000002);
+               ram_mask(fuc, 0x10f830, 0x00800001, 0x00408010);
+               r1373f4_init(fuc);
+               r1373f4_fini(fuc, ramcfg);
+               ram_mask(fuc, 0x10f808, 0x00000000, 0x00080000);
+               ram_mask(fuc, 0x10f200, 0x00808000, 0x00800000);
+       } else
+       if (ram->from == 2 && ram->mode == 2) {
+               ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
+               r1373f4_init(fuc);
+               r1373f4_fini(fuc, ramcfg);
+       }
+
+       if (ram->mode != 2) /*XXX*/ {
+               if (nv_ro08(bios, ramcfg + 0x07) & 0x40)
+                       ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
+       }
+
+       data = (nv_ro08(bios, rammap + 0x11) & 0x0c) >> 2;
+       ram_wr32(fuc, 0x10f65c, 0x00000011 * data);
+       ram_wr32(fuc, 0x10f6b8, 0x01010101 * nv_ro08(bios, ramcfg + 0x09));
+       ram_wr32(fuc, 0x10f6bc, 0x01010101 * nv_ro08(bios, ramcfg + 0x09));
+
+       data = nv_ro08(bios, ramcfg + 0x04);
+       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x08)) {
+               ram_wr32(fuc, 0x10f698, 0x01010101 * data);
+               ram_wr32(fuc, 0x10f69c, 0x01010101 * data);
+       }
+
+       if (ram->mode != 2) {
+               u32 temp = ram_rd32(fuc, 0x10f694) & ~0xff00ff00;
+               ram_wr32(fuc, 0x10f694, temp | (0x01000100 * data));
+       }
+
+       if (ram->mode == 2 && (nv_ro08(bios, ramcfg + 0x08) & 0x10))
+               data = 0x00000080;
+       else
+               data = 0x00000000;
+       ram_mask(fuc, 0x10f60c, 0x00000080, data);
+
+       mask = 0x00070000;
+       data = 0x00000000;
+       if (!(nv_ro08(bios, ramcfg + 0x02) & 0x80))
+               data |= 0x03000000;
+       if (!(nv_ro08(bios, ramcfg + 0x02) & 0x40))
+               data |= 0x00002000;
+       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x10))
+               data |= 0x00004000;
+       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x08))
+               data |= 0x00000003;
+       else
+               data |= 0x74000000;
+       ram_mask(fuc, 0x10f824, mask, data);
+
+       if (nv_ro08(bios, ramcfg + 0x01) & 0x08)
+               data = 0x00000000;
+       else
+               data = 0x00001000;
+       ram_mask(fuc, 0x10f200, 0x00001000, data);
+
+       if (ram_rd32(fuc, 0x10f670) & 0x80000000) {
+               ram_nsec(fuc, 10000);
+               ram_mask(fuc, 0x10f670, 0x80000000, 0x00000000);
+       }
+
+       if (nv_ro08(bios, ramcfg + 0x08) & 0x01)
+               data = 0x00100000;
+       else
+               data = 0x00000000;
+       ram_mask(fuc, 0x10f82c, 0x00100000, data);
+
+       data = 0x00000000;
+       if (nv_ro08(bios, ramcfg + 0x08) & 0x08)
+               data |= 0x00002000;
+       if (nv_ro08(bios, ramcfg + 0x08) & 0x04)
+               data |= 0x00001000;
+       if (nv_ro08(bios, ramcfg + 0x08) & 0x02)
+               data |= 0x00004000;
+       ram_mask(fuc, 0x10f830, 0x00007000, data);
+
+       /* PFB timing */
+       ram_mask(fuc, 0x10f248, 0xffffffff, nv_ro32(bios, timing + 0x28));
+       ram_mask(fuc, 0x10f290, 0xffffffff, nv_ro32(bios, timing + 0x00));
+       ram_mask(fuc, 0x10f294, 0xffffffff, nv_ro32(bios, timing + 0x04));
+       ram_mask(fuc, 0x10f298, 0xffffffff, nv_ro32(bios, timing + 0x08));
+       ram_mask(fuc, 0x10f29c, 0xffffffff, nv_ro32(bios, timing + 0x0c));
+       ram_mask(fuc, 0x10f2a0, 0xffffffff, nv_ro32(bios, timing + 0x10));
+       ram_mask(fuc, 0x10f2a4, 0xffffffff, nv_ro32(bios, timing + 0x14));
+       ram_mask(fuc, 0x10f2a8, 0xffffffff, nv_ro32(bios, timing + 0x18));
+       ram_mask(fuc, 0x10f2ac, 0xffffffff, nv_ro32(bios, timing + 0x1c));
+       ram_mask(fuc, 0x10f2cc, 0xffffffff, nv_ro32(bios, timing + 0x20));
+       ram_mask(fuc, 0x10f2e8, 0xffffffff, nv_ro32(bios, timing + 0x24));
+
+       data = (nv_ro08(bios, ramcfg + 0x02) & 0x03) << 8;
+       if (nv_ro08(bios, ramcfg + 0x01) & 0x10)
+               data |= 0x70000000;
+       ram_mask(fuc, 0x10f604, 0x70000300, data);
+
+       data = (nv_ro08(bios, timing + 0x30) & 0x07) << 28;
+       if (nv_ro08(bios, ramcfg + 0x01) & 0x01)
+               data |= 0x00000100;
+       ram_mask(fuc, 0x10f614, 0x70000000, data);
+
+       data = (nv_ro08(bios, timing + 0x30) & 0x07) << 28;
+       if (nv_ro08(bios, ramcfg + 0x01) & 0x02)
+               data |= 0x00000100;
+       ram_mask(fuc, 0x10f610, 0x70000000, data);
+
+       mask = 0x33f00000;
+       data = 0x00000000;
+       if (!(nv_ro08(bios, ramcfg + 0x01) & 0x04))
+               data |= 0x20200000;
+       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x80))
+               data |= 0x12800000;
+       /*XXX: see note above about there probably being some condition
+        *     for the 10f824 stuff that uses ramcfg 3...
+        */
+       if ( (nv_ro08(bios, ramcfg + 0x03) & 0xf0)) {
+               if (nv_ro08(bios, rammap + 0x08) & 0x0c) {
+                       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x80))
+                               mask |= 0x00000020;
+                       else
+                               data |= 0x00000020;
+                       mask |= 0x00000004;
+               }
+       } else {
+               mask |= 0x40000020;
+               data |= 0x00000004;
+       }
+
+       ram_mask(fuc, 0x10f808, mask, data);
+
+       data = nv_ro08(bios, ramcfg + 0x03) & 0x0f;
+       ram_wr32(fuc, 0x10f870, 0x11111111 * data);
+
+       data = nv_ro08(bios, ramcfg + 0x02) & 0x03;
+       if (nv_ro08(bios, ramcfg + 0x01) & 0x10)
+               data |= 0x00000004;
+       if ((nv_rd32(bios, 0x100770) & 0x00000004) != (data & 0x00000004)) {
+               ram_wr32(fuc, 0x10f750, 0x04000009);
+               ram_wr32(fuc, 0x100710, 0x00000000);
+               ram_wait(fuc, 0x100710, 0x80000000, 0x80000000, 200000);
+       }
+       ram_mask(fuc, 0x100770, 0x00000007, data);
+
+       data = (nv_ro08(bios, timing + 0x30) & 0x07) << 8;
+       if (nv_ro08(bios, ramcfg + 0x01) & 0x01)
+               data |= 0x80000000;
+       ram_mask(fuc, 0x100778, 0x00000700, data);
+
+       data = nv_ro16(bios, timing + 0x2c);
+       ram_mask(fuc, 0x10f250, 0x000003f0, (data & 0x003f) <<  4);
+       ram_mask(fuc, 0x10f24c, 0x7f000000, (data & 0x1fc0) << 18);
+
+       data = nv_ro08(bios, timing + 0x30);
+       ram_mask(fuc, 0x10f224, 0x001f0000, (data & 0xf8) << 13);
+
+       data = nv_ro16(bios, timing + 0x31);
+       ram_mask(fuc, 0x10fec4, 0x041e0f07, (data & 0x0800) << 15 |
+                                           (data & 0x0780) << 10 |
+                                           (data & 0x0078) <<  5 |
+                                           (data & 0x0007));
+       ram_mask(fuc, 0x10fec8, 0x00000027, (data & 0x8000) >> 10 |
+                                           (data & 0x7000) >> 12);
+
+       ram_wr32(fuc, 0x10f090, 0x4000007e);
+       ram_nsec(fuc, 1000);
+       ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+       ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+       ram_nsec(fuc, 2000);
+       ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
+
+       if ((nv_ro08(bios, ramcfg + 0x08) & 0x10) && (ram->mode == 2) /*XXX*/) {
+               u32 temp = ram_mask(fuc, 0x10f294, 0xff000000, 0x24000000);
+               train(fuc, 0xa4010000); /*XXX*/
+               ram_nsec(fuc, 1000);
+               ram_wr32(fuc, 0x10f294, temp);
+       }
+
+       ram_mask(fuc, mr[3], 0xfff, ram->base.mr[3]);
+       ram_wr32(fuc, mr[0], ram->base.mr[0]);
+       ram_mask(fuc, mr[8], 0xfff, ram->base.mr[8]);
+       ram_nsec(fuc, 1000);
+       ram_mask(fuc, mr[1], 0xfff, ram->base.mr[1]);
+       ram_mask(fuc, mr[5], 0xfff, ram->base.mr[5]);
+       ram_mask(fuc, mr[6], 0xfff, ram->base.mr[6]);
+       ram_mask(fuc, mr[7], 0xfff, ram->base.mr[7]);
+
+       if (vc == 0 && ram_have(fuc, gpio2E)) {
+               u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
+               if (temp != ram_rd32(fuc, gpio2E)) {
+                       ram_wr32(fuc, gpiotrig, 1);
+                       ram_nsec(fuc, 20000);
+               }
+       }
+
+       ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+       ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
+       ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+       ram_nsec(fuc, 1000);
+
+       data  = ram_rd32(fuc, 0x10f978);
+       data &= ~0x00046144;
+       data |=  0x0000000b;
+       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x08)) {
+               if (!(nv_ro08(bios, ramcfg + 0x07) & 0x04))
+                       data |= 0x0000200c;
+               else
+                       data |= 0x00000000;
+       } else {
+               data |= 0x00040044;
+       }
+       ram_wr32(fuc, 0x10f978, data);
+
+       if (ram->mode == 1) {
+               data = ram_rd32(fuc, 0x10f830) | 0x00000001;
+               ram_wr32(fuc, 0x10f830, data);
+       }
+
+       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x08)) {
+               data = 0x88020000;
+               if ( (nv_ro08(bios, ramcfg + 0x07) & 0x04))
+                       data |= 0x10000000;
+               if (!(nv_ro08(bios, rammap + 0x08) & 0x10))
+                       data |= 0x00080000;
+       } else {
+               data = 0xa40e0000;
+       }
+       train(fuc, data);
+       ram_nsec(fuc, 1000);
+
+       if (ram->mode == 2) { /*XXX*/
+               ram_mask(fuc, 0x10f800, 0x00000004, 0x00000004);
+       }
+
+       /* MR5: (re)enable LP3 if necessary
+        * XXX: need to find the switch, keeping off for now
+        */
+       ram_mask(fuc, mr[5], 0x00000004, 0x00000000);
+
+       if (ram->mode != 2) {
+               ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
+               ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+       }
+
+       if (nv_ro08(bios, ramcfg + 0x07) & 0x02) {
+               ram_mask(fuc, 0x10f910, 0x80020000, 0x01000000);
+               ram_mask(fuc, 0x10f914, 0x80020000, 0x01000000);
+       }
+
+       ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
+
+       if (nv_ro08(bios, rammap + 0x08) & 0x01)
+               data = 0x00000800;
+       else
+               data = 0x00000000;
+       ram_mask(fuc, 0x10f200, 0x00000800, data);
+       return 0;
+}
+
+/*******************************************************************************
+ * DDR3
+ ******************************************************************************/
+
+static int
+nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
+{
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nve0_ram *ram = (void *)pfb->ram;
+       struct nve0_ramfuc *fuc = &ram->fuc;
+       const u32 rcoef = ((  ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
+       const u32 runk0 = ram->fN1 << 16;
+       const u32 runk1 = ram->fN1;
+       const u32 rammap = ram->base.rammap.data;
+       const u32 ramcfg = ram->base.ramcfg.data;
+       const u32 timing = ram->base.timing.data;
+       int vc = !(nv_ro08(bios, ramcfg + 0x02) & 0x08);
+       int mv = 1; /*XXX*/
+       u32 mask, data;
+
+       ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
+       ram_wr32(fuc, 0x62c000, 0x0f0f0000);
+
+       if (vc == 1 && ram_have(fuc, gpio2E)) {
+               u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
+               if (temp != ram_rd32(fuc, gpio2E)) {
+                       ram_wr32(fuc, gpiotrig, 1);
+                       ram_nsec(fuc, 20000);
+               }
+       }
+
+       ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
+       if ((nv_ro08(bios, ramcfg + 0x03) & 0xf0))
+               ram_mask(fuc, 0x10f808, 0x04000000, 0x04000000);
+
+       ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+       ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
+       ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+       ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+       ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+       ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+       ram_nsec(fuc, 1000);
+
+       ram_wr32(fuc, 0x10f090, 0x00000060);
+       ram_wr32(fuc, 0x10f090, 0xc000007e);
+
+       /*XXX: there does appear to be some kind of condition here, simply
+        *     modifying these bits in the vbios from the default pl0
+        *     entries shows no change.  however, the data does appear to
+        *     be correct and may be required for the transition back
+        */
+       mask = 0x00010000;
+       data = 0x00010000;
+
+       if (1) {
+               mask |= 0x800807e0;
+               data |= 0x800807e0;
+               switch (nv_ro08(bios, ramcfg + 0x03) & 0xc0) {
+               case 0xc0: data &= ~0x00000040; break;
+               case 0x80: data &= ~0x00000100; break;
+               case 0x40: data &= ~0x80000000; break;
+               case 0x00: data &= ~0x00000400; break;
+               }
+
+               switch (nv_ro08(bios, ramcfg + 0x03) & 0x30) {
+               case 0x30: data &= ~0x00000020; break;
+               case 0x20: data &= ~0x00000080; break;
+               case 0x10: data &= ~0x00080000; break;
+               case 0x00: data &= ~0x00000200; break;
+               }
+       }
+
+       if (nv_ro08(bios, ramcfg + 0x02) & 0x80)
+               mask |= 0x03000000;
+       if (nv_ro08(bios, ramcfg + 0x02) & 0x40)
+               mask |= 0x00002000;
+       if (nv_ro08(bios, ramcfg + 0x07) & 0x10)
+               mask |= 0x00004000;
+       if (nv_ro08(bios, ramcfg + 0x07) & 0x08)
+               mask |= 0x00000003;
+       else
+               mask |= 0x14000000;
+       ram_mask(fuc, 0x10f824, mask, data);
+
+       ram_mask(fuc, 0x132040, 0x00010000, 0x00000000);
+
+       ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
+       data  = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
+       data |= (nv_ro08(bios, ramcfg + 0x03) & 0x30) << 12;
+       ram_wr32(fuc, 0x1373ec, data);
+       ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
+       ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
+
+       /* (re)program refpll, if required */
+       if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef ||
+           (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) {
+               ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+               ram_mask(fuc, 0x132020, 0x00000001, 0x00000000);
+               ram_wr32(fuc, 0x137320, 0x00000000);
+               ram_mask(fuc, 0x132030, 0xffff0000, runk0);
+               ram_mask(fuc, 0x132034, 0x0000ffff, runk1);
+               ram_wr32(fuc, 0x132024, rcoef);
+               ram_mask(fuc, 0x132028, 0x00080000, 0x00080000);
+               ram_mask(fuc, 0x132020, 0x00000001, 0x00000001);
+               ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
+               ram_mask(fuc, 0x132028, 0x00080000, 0x00000000);
+       }
+
+       ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000010);
+       ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000001);
+       ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
+
+       if (ram_have(fuc, gpioMV)) {
+               u32 temp  = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]);
+               if (temp != ram_rd32(fuc, gpioMV)) {
+                       ram_wr32(fuc, gpiotrig, 1);
+                       ram_nsec(fuc, 64000);
+               }
+       }
+
+       if ( (nv_ro08(bios, ramcfg + 0x02) & 0x40) ||
+            (nv_ro08(bios, ramcfg + 0x07) & 0x10)) {
+               ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
+               ram_nsec(fuc, 20000);
+       }
+
+       if (ram->mode != 2) /*XXX*/ {
+               if (nv_ro08(bios, ramcfg + 0x07) & 0x40)
+                       ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
+       }
+
+       data = (nv_ro08(bios, rammap + 0x11) & 0x0c) >> 2;
+       ram_wr32(fuc, 0x10f65c, 0x00000011 * data);
+       ram_wr32(fuc, 0x10f6b8, 0x01010101 * nv_ro08(bios, ramcfg + 0x09));
+       ram_wr32(fuc, 0x10f6bc, 0x01010101 * nv_ro08(bios, ramcfg + 0x09));
+
+       mask = 0x00010000;
+       data = 0x00000000;
+       if (!(nv_ro08(bios, ramcfg + 0x02) & 0x80))
+               data |= 0x03000000;
+       if (!(nv_ro08(bios, ramcfg + 0x02) & 0x40))
+               data |= 0x00002000;
+       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x10))
+               data |= 0x00004000;
+       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x08))
+               data |= 0x00000003;
+       else
+               data |= 0x14000000;
+       ram_mask(fuc, 0x10f824, mask, data);
+       ram_nsec(fuc, 1000);
+
+       if (nv_ro08(bios, ramcfg + 0x08) & 0x01)
+               data = 0x00100000;
+       else
+               data = 0x00000000;
+       ram_mask(fuc, 0x10f82c, 0x00100000, data);
+
+       /* PFB timing */
+       ram_mask(fuc, 0x10f248, 0xffffffff, nv_ro32(bios, timing + 0x28));
+       ram_mask(fuc, 0x10f290, 0xffffffff, nv_ro32(bios, timing + 0x00));
+       ram_mask(fuc, 0x10f294, 0xffffffff, nv_ro32(bios, timing + 0x04));
+       ram_mask(fuc, 0x10f298, 0xffffffff, nv_ro32(bios, timing + 0x08));
+       ram_mask(fuc, 0x10f29c, 0xffffffff, nv_ro32(bios, timing + 0x0c));
+       ram_mask(fuc, 0x10f2a0, 0xffffffff, nv_ro32(bios, timing + 0x10));
+       ram_mask(fuc, 0x10f2a4, 0xffffffff, nv_ro32(bios, timing + 0x14));
+       ram_mask(fuc, 0x10f2a8, 0xffffffff, nv_ro32(bios, timing + 0x18));
+       ram_mask(fuc, 0x10f2ac, 0xffffffff, nv_ro32(bios, timing + 0x1c));
+       ram_mask(fuc, 0x10f2cc, 0xffffffff, nv_ro32(bios, timing + 0x20));
+       ram_mask(fuc, 0x10f2e8, 0xffffffff, nv_ro32(bios, timing + 0x24));
+
+       mask = 0x33f00000;
+       data = 0x00000000;
+       if (!(nv_ro08(bios, ramcfg + 0x01) & 0x04))
+               data |= 0x20200000;
+       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x80))
+               data |= 0x12800000;
+       /*XXX: see note above about there probably being some condition
+        *     for the 10f824 stuff that uses ramcfg 3...
+        */
+       if ( (nv_ro08(bios, ramcfg + 0x03) & 0xf0)) {
+               if (nv_ro08(bios, rammap + 0x08) & 0x0c) {
+                       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x80))
+                               mask |= 0x00000020;
+                       else
+                               data |= 0x00000020;
+                       mask |= 0x08000004;
+               }
+               data |= 0x04000000;
+       } else {
+               mask |= 0x44000020;
+               data |= 0x08000004;
+       }
+
+       ram_mask(fuc, 0x10f808, mask, data);
+
+       data = nv_ro08(bios, ramcfg + 0x03) & 0x0f;
+       ram_wr32(fuc, 0x10f870, 0x11111111 * data);
+
+       data = nv_ro16(bios, timing + 0x2c);
+       ram_mask(fuc, 0x10f250, 0x000003f0, (data & 0x003f) <<  4);
+
+       if (((nv_ro32(bios, timing + 0x2c) & 0x00001fc0) >>  6) >
+           ((nv_ro32(bios, timing + 0x28) & 0x7f000000) >> 24))
+               data = (nv_ro32(bios, timing + 0x2c) & 0x00001fc0) >>  6;
+       else
+               data = (nv_ro32(bios, timing + 0x28) & 0x1f000000) >> 24;
+       ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
+
+       data = nv_ro08(bios, timing + 0x30);
+       ram_mask(fuc, 0x10f224, 0x001f0000, (data & 0xf8) << 13);
+
+       ram_wr32(fuc, 0x10f090, 0x4000007f);
+       ram_nsec(fuc, 1000);
+
+       ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+       ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+       ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
+       ram_nsec(fuc, 1000);
+
+       ram_nuke(fuc, mr[0]);
+       ram_mask(fuc, mr[0], 0x100, 0x100);
+       ram_mask(fuc, mr[0], 0x100, 0x000);
+
+       ram_mask(fuc, mr[2], 0xfff, ram->base.mr[2]);
+       ram_wr32(fuc, mr[0], ram->base.mr[0]);
+       ram_nsec(fuc, 1000);
+
+       ram_nuke(fuc, mr[0]);
+       ram_mask(fuc, mr[0], 0x100, 0x100);
+       ram_mask(fuc, mr[0], 0x100, 0x000);
+
+       if (vc == 0 && ram_have(fuc, gpio2E)) {
+               u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
+               if (temp != ram_rd32(fuc, gpio2E)) {
+                       ram_wr32(fuc, gpiotrig, 1);
+                       ram_nsec(fuc, 20000);
+               }
+       }
+
+       if (ram->mode != 2) {
+               ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
+               ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+       }
+
+       ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+       ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
+       ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+       ram_nsec(fuc, 1000);
+
+       ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
+
+       if (nv_ro08(bios, rammap + 0x08) & 0x01)
+               data = 0x00000800;
+       else
+               data = 0x00000000;
+       ram_mask(fuc, 0x10f200, 0x00000800, data);
+       return 0;
+}
+
+/*******************************************************************************
+ * main hooks
+ ******************************************************************************/
+
+static int
+nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
+{
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nve0_ram *ram = (void *)pfb->ram;
+       struct nve0_ramfuc *fuc = &ram->fuc;
+       struct bit_entry M;
+       int ret, refclk, strap, i;
+       u32 data;
+       u8  cnt;
+
+       /* lookup memory config data relevant to the target frequency */
+       ram->base.rammap.data = nvbios_rammap_match(bios, freq / 1000,
+                                                  &ram->base.rammap.version,
+                                                  &ram->base.rammap.size, &cnt,
+                                                  &ram->base.ramcfg.size);
+       if (!ram->base.rammap.data || ram->base.rammap.version != 0x11 ||
+            ram->base.rammap.size < 0x09) {
+               nv_error(pfb, "invalid/missing rammap entry\n");
+               return -EINVAL;
+       }
+
+       /* locate specific data set for the attached memory */
+       if (bit_entry(bios, 'M', &M) || M.version != 2 || M.length < 3) {
+               nv_error(pfb, "invalid/missing memory table\n");
+               return -EINVAL;
+       }
+
+       strap = (nv_rd32(pfb, 0x101000) & 0x0000003c) >> 2;
+       data = nv_ro16(bios, M.offset + 1);
+       if (data)
+               strap = nv_ro08(bios, data + strap);
+
+       if (strap >= cnt) {
+               nv_error(pfb, "invalid ramcfg strap\n");
+               return -EINVAL;
+       }
+
+       ram->base.ramcfg.version = ram->base.rammap.version;
+       ram->base.ramcfg.data = ram->base.rammap.data + ram->base.rammap.size +
+                              (ram->base.ramcfg.size * strap);
+       if (!ram->base.ramcfg.data || ram->base.ramcfg.version != 0x11 ||
+            ram->base.ramcfg.size < 0x08) {
+               nv_error(pfb, "invalid/missing ramcfg entry\n");
+               return -EINVAL;
+       }
+
+       /* lookup memory timings, if bios says they're present */
+       strap = nv_ro08(bios, ram->base.ramcfg.data + 0x00);
+       if (strap != 0xff) {
+               ram->base.timing.data =
+                       nvbios_timing_entry(bios, strap,
+                                          &ram->base.timing.version,
+                                          &ram->base.timing.size);
+               if (!ram->base.timing.data ||
+                    ram->base.timing.version != 0x20 ||
+                    ram->base.timing.size < 0x33) {
+                       nv_error(pfb, "invalid/missing timing entry\n");
+                       return -EINVAL;
+               }
+       } else {
+               ram->base.timing.data = 0;
+       }
+
+       ret = ram_init(fuc, pfb);
+       if (ret)
+               return ret;
+
+       ram->mode = (freq > fuc->refpll.vco1.max_freq) ? 2 : 1;
+       ram->from = ram_rd32(fuc, 0x1373f4) & 0x0000000f;
+
+       /* XXX: this is *not* what nvidia do.  on fermi nvidia generally
+        * select, based on some unknown condition, one of the two possible
+        * reference frequencies listed in the vbios table for mempll and
+        * program refpll to that frequency.
+        *
+        * so far, i've seen very weird values being chosen by nvidia on
+        * kepler boards, no idea how/why they're chosen.
+        */
+       refclk = freq;
+       if (ram->mode == 2)
+               refclk = fuc->mempll.refclk;
+
+       /* calculate refpll coefficients */
+       ret = nva3_pll_calc(nv_subdev(pfb), &fuc->refpll, refclk, &ram->N1,
+                          &ram->fN1, &ram->M1, &ram->P1);
+       fuc->mempll.refclk = ret;
+       if (ret <= 0) {
+               nv_error(pfb, "unable to calc refpll\n");
+               return -EINVAL;
+       }
+
+       /* calculate mempll coefficients, if we're using it */
+       if (ram->mode == 2) {
+               /* post-divider doesn't work... the reg takes the values but
+                * appears to completely ignore it.  there *is* a bit at
+                * bit 28 that appears to divide the clock by 2 if set.
+                */
+               fuc->mempll.min_p = 1;
+               fuc->mempll.max_p = 2;
+
+               ret = nva3_pll_calc(nv_subdev(pfb), &fuc->mempll, freq,
+                                  &ram->N2, NULL, &ram->M2, &ram->P2);
+               if (ret <= 0) {
+                       nv_error(pfb, "unable to calc mempll\n");
+                       return -EINVAL;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(fuc->r_mr); i++) {
+               if (ram_have(fuc, mr[i]))
+                       ram->base.mr[i] = ram_rd32(fuc, mr[i]);
+       }
+
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_DDR3:
+               ret = nouveau_sddr3_calc(&ram->base);
+               if (ret == 0)
+                       ret = nve0_ram_calc_sddr3(pfb, freq);
+               break;
+       case NV_MEM_TYPE_GDDR5:
+               ret = nouveau_gddr5_calc(&ram->base);
+               if (ret == 0)
+                       ret = nve0_ram_calc_gddr5(pfb, freq);
+               break;
+       default:
+               ret = -ENOSYS;
+               break;
+       }
+
+       return ret;
+}
+
+static int
+nve0_ram_prog(struct nouveau_fb *pfb)
+{
+       struct nouveau_device *device = nv_device(pfb);
+       struct nve0_ram *ram = (void *)pfb->ram;
+       struct nve0_ramfuc *fuc = &ram->fuc;
+       ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", false));
+       return 0;
+}
+
+static void
+nve0_ram_tidy(struct nouveau_fb *pfb)
+{
+       struct nve0_ram *ram = (void *)pfb->ram;
+       struct nve0_ramfuc *fuc = &ram->fuc;
+       ram_exec(fuc, false);
+}
+
+static int
+nve0_ram_init(struct nouveau_object *object)
+{
+       struct nouveau_fb *pfb = (void *)object->parent;
+       struct nve0_ram *ram   = (void *)object;
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       static const u8  train0[] = {
+               0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
+               0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
+       };
+       static const u32 train1[] = {
+               0x00000000, 0xffffffff,
+               0x55555555, 0xaaaaaaaa,
+               0x33333333, 0xcccccccc,
+               0xf0f0f0f0, 0x0f0f0f0f,
+               0x00ff00ff, 0xff00ff00,
+               0x0000ffff, 0xffff0000,
+       };
+       u8  ver, hdr, cnt, len, snr, ssz;
+       u32 data, save;
+       int ret, i;
+
+       ret = nouveau_ram_init(&ram->base);
+       if (ret)
+               return ret;
+
+       /* run a bunch of tables from rammap table.  there's actually
+        * individual pointers for each rammap entry too, but, nvidia
+        * seem to just run the last two entries' scripts early on in
+        * their init, and never again.. we'll just run 'em all once
+        * for now.
+        *
+        * i strongly suspect that each script is for a separate mode
+        * (likely selected by 0x10f65c's lower bits?), and the
+        * binary driver skips the one that's already been setup by
+        * the init tables.
+        */
+       data = nvbios_rammap_table(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
+       if (!data || hdr < 0x15)
+               return -EINVAL;
+
+       cnt  = nv_ro08(bios, data + 0x14); /* guess at count */
+       data = nv_ro32(bios, data + 0x10); /* guess u32... */
+       save = nv_rd32(pfb, 0x10f65c);
+       for (i = 0; i < cnt; i++) {
+               nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4);
+               nvbios_exec(&(struct nvbios_init) {
+                               .subdev = nv_subdev(pfb),
+                               .bios = bios,
+                               .offset = nv_ro32(bios, data), /* guess u32 */
+                               .execute = 1,
+                           });
+               data += 4;
+       }
+       nv_wr32(pfb, 0x10f65c, save);
+
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_GDDR5:
+               for (i = 0; i < 0x30; i++) {
+                       nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8));
+                       nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]);
+                       nv_wr32(pfb, 0x10f918,              train1[i % 12]);
+                       nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]);
+                       nv_wr32(pfb, 0x10f918,              train1[i % 12]);
+
+                       nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8));
+                       nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]);
+                       nv_wr32(pfb, 0x10f91c,              train1[i % 12]);
+                       nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]);
+                       nv_wr32(pfb, 0x10f91c,              train1[i % 12]);
+               }
+
+               for (i = 0; i < 0x100; i++) {
+                       nv_wr32(pfb, 0x10f968, i);
+                       nv_wr32(pfb, 0x10f900, train1[2 + (i & 1)]);
+               }
+
+               for (i = 0; i < 0x100; i++) {
+                       nv_wr32(pfb, 0x10f96c, i);
+                       nv_wr32(pfb, 0x10f900, train1[2 + (i & 1)]);
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int
+nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+             struct nouveau_oclass *oclass, void *data, u32 size,
+             struct nouveau_object **pobject)
+{
+       struct nouveau_fb *pfb = nouveau_fb(parent);
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nouveau_gpio *gpio = nouveau_gpio(pfb);
+       struct dcb_gpio_func func;
+       struct nve0_ram *ram;
+       int ret;
+
+       ret = nvc0_ram_create(parent, engine, oclass, &ram);
+       *pobject = nv_object(ram);
+       if (ret)
+               return ret;
+
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_DDR3:
+       case NV_MEM_TYPE_GDDR5:
+               ram->base.calc = nve0_ram_calc;
+               ram->base.prog = nve0_ram_prog;
+               ram->base.tidy = nve0_ram_tidy;
+               break;
+       default:
+               nv_warn(pfb, "reclocking of this RAM type is unsupported\n");
+               break;
+       }
+
+       // parse bios data for both pll's
+       ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
+       if (ret) {
+               nv_error(pfb, "mclk refpll data not found\n");
+               return ret;
+       }
+
+       ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll);
+       if (ret) {
+               nv_error(pfb, "mclk pll data not found\n");
+               return ret;
+       }
+
+       ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
+       if (ret == 0) {
+               ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
+               ram->fuc.r_funcMV[0] = (func.log[0] ^ 2) << 12;
+               ram->fuc.r_funcMV[1] = (func.log[1] ^ 2) << 12;
+       }
+
+       ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+       if (ret == 0) {
+               ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (func.line * 0x04));
+               ram->fuc.r_func2E[0] = (func.log[0] ^ 2) << 12;
+               ram->fuc.r_func2E[1] = (func.log[1] ^ 2) << 12;
+       }
+
+       ram->fuc.r_gpiotrig = ramfuc_reg(0x00d604);
+
+       ram->fuc.r_0x132020 = ramfuc_reg(0x132020);
+       ram->fuc.r_0x132028 = ramfuc_reg(0x132028);
+       ram->fuc.r_0x132024 = ramfuc_reg(0x132024);
+       ram->fuc.r_0x132030 = ramfuc_reg(0x132030);
+       ram->fuc.r_0x132034 = ramfuc_reg(0x132034);
+       ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
+       ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
+       ram->fuc.r_0x132040 = ramfuc_reg(0x132040);
+
+       ram->fuc.r_0x10f248 = ramfuc_reg(0x10f248);
+       ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
+       ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
+       ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
+       ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
+       ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
+       ram->fuc.r_0x10f2a4 = ramfuc_reg(0x10f2a4);
+       ram->fuc.r_0x10f2a8 = ramfuc_reg(0x10f2a8);
+       ram->fuc.r_0x10f2ac = ramfuc_reg(0x10f2ac);
+       ram->fuc.r_0x10f2cc = ramfuc_reg(0x10f2cc);
+       ram->fuc.r_0x10f2e8 = ramfuc_reg(0x10f2e8);
+       ram->fuc.r_0x10f250 = ramfuc_reg(0x10f250);
+       ram->fuc.r_0x10f24c = ramfuc_reg(0x10f24c);
+       ram->fuc.r_0x10fec4 = ramfuc_reg(0x10fec4);
+       ram->fuc.r_0x10fec8 = ramfuc_reg(0x10fec8);
+       ram->fuc.r_0x10f604 = ramfuc_reg(0x10f604);
+       ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
+       ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
+       ram->fuc.r_0x100770 = ramfuc_reg(0x100770);
+       ram->fuc.r_0x100778 = ramfuc_reg(0x100778);
+       ram->fuc.r_0x10f224 = ramfuc_reg(0x10f224);
+
+       ram->fuc.r_0x10f870 = ramfuc_reg(0x10f870);
+       ram->fuc.r_0x10f698 = ramfuc_reg(0x10f698);
+       ram->fuc.r_0x10f694 = ramfuc_reg(0x10f694);
+       ram->fuc.r_0x10f6b8 = ramfuc_reg(0x10f6b8);
+       ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
+       ram->fuc.r_0x10f670 = ramfuc_reg(0x10f670);
+       ram->fuc.r_0x10f60c = ramfuc_reg(0x10f60c);
+       ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
+       ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
+       ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
+       ram->fuc.r_0x10f82c = ramfuc_reg(0x10f82c);
+
+       ram->fuc.r_0x10f978 = ramfuc_reg(0x10f978);
+       ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
+       ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
+
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_GDDR5:
+               ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
+               ram->fuc.r_mr[1] = ramfuc_reg(0x10f330);
+               ram->fuc.r_mr[2] = ramfuc_reg(0x10f334);
+               ram->fuc.r_mr[3] = ramfuc_reg(0x10f338);
+               ram->fuc.r_mr[4] = ramfuc_reg(0x10f33c);
+               ram->fuc.r_mr[5] = ramfuc_reg(0x10f340);
+               ram->fuc.r_mr[6] = ramfuc_reg(0x10f344);
+               ram->fuc.r_mr[7] = ramfuc_reg(0x10f348);
+               ram->fuc.r_mr[8] = ramfuc_reg(0x10f354);
+               ram->fuc.r_mr[15] = ramfuc_reg(0x10f34c);
+               break;
+       case NV_MEM_TYPE_DDR3:
+               ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
+               ram->fuc.r_mr[2] = ramfuc_reg(0x10f320);
+               break;
+       default:
+               break;
+       }
+
+       ram->fuc.r_0x62c000 = ramfuc_reg(0x62c000);
+       ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
+       ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
+       ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
+       ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
+       ram->fuc.r_0x10f318 = ramfuc_reg(0x10f318);
+       ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
+       ram->fuc.r_0x10f69c = ramfuc_reg(0x10f69c);
+       ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
+       ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
+       ram->fuc.r_0x1373f4 = ramfuc_reg(0x1373f4);
+       ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
+       ram->fuc.r_0x10f65c = ramfuc_reg(0x10f65c);
+       ram->fuc.r_0x10f6bc = ramfuc_reg(0x10f6bc);
+       ram->fuc.r_0x100710 = ramfuc_reg(0x100710);
+       ram->fuc.r_0x10f750 = ramfuc_reg(0x10f750);
+       return 0;
+}
+
+struct nouveau_oclass
+nve0_ram_oclass = {
+       .handle = 0,
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nve0_ram_ctor,
+               .dtor = _nouveau_ram_dtor,
+               .init = nve0_ram_init,
+               .fini = _nouveau_ram_fini,
+       }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h b/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h
new file mode 100644 (file)
index 0000000..571077e
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __NVKM_FBRAM_SEQ_H__
+#define __NVKM_FBRAM_SEQ_H__
+
+#include <subdev/bus.h>
+#include <subdev/bus/hwsq.h>
+
+#define ram_init(s,p)       hwsq_init(&(s)->base, (p))
+#define ram_exec(s,e)       hwsq_exec(&(s)->base, (e))
+#define ram_have(s,r)       ((s)->r_##r.addr != 0x000000)
+#define ram_rd32(s,r)       hwsq_rd32(&(s)->base, &(s)->r_##r)
+#define ram_wr32(s,r,d)     hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
+#define ram_nuke(s,r)       hwsq_nuke(&(s)->base, &(s)->r_##r)
+#define ram_mask(s,r,m,d)   hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
+#define ram_setf(s,f,d)     hwsq_setf(&(s)->base, (f), (d))
+#define ram_wait(s,f,d)     hwsq_wait(&(s)->base, (f), (d))
+#define ram_nsec(s,n)       hwsq_nsec(&(s)->base, (n))
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c
new file mode 100644 (file)
index 0000000..ebd4cd9
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include <subdev/bios.h>
+#include "priv.h"
+
+struct ramxlat {
+       int id;
+       u8 enc;
+};
+
+static inline int
+ramxlat(const struct ramxlat *xlat, int id)
+{
+       while (xlat->id >= 0) {
+               if (xlat->id == id)
+                       return xlat->enc;
+               xlat++;
+       }
+       return -EINVAL;
+}
+
+static const struct ramxlat
+ramddr3_cl[] = {
+       { 5, 2 }, { 6, 4 }, { 7, 6 }, { 8, 8 }, { 9, 10 }, { 10, 12 },
+       { 11, 14 },
+       /* the below are mentioned in some, but not all, ddr3 docs */
+       { 12, 1 }, { 13, 3 }, { 14, 5 },
+       { -1 }
+};
+
+static const struct ramxlat
+ramddr3_wr[] = {
+       { 5, 1 }, { 6, 2 }, { 7, 3 }, { 8, 4 }, { 10, 5 }, { 12, 6 },
+       /* the below are mentioned in some, but not all, ddr3 docs */
+       { 14, 7 }, { 16, 0 },
+       { -1 }
+};
+
+static const struct ramxlat
+ramddr3_cwl[] = {
+       { 5, 0 }, { 6, 1 }, { 7, 2 }, { 8, 3 },
+       /* the below are mentioned in some, but not all, ddr3 docs */
+       { 9, 4 },
+       { -1 }
+};
+
+int
+nouveau_sddr3_calc(struct nouveau_ram *ram)
+{
+       struct nouveau_bios *bios = nouveau_bios(ram);
+       int WL, CL, WR;
+
+       switch (!!ram->timing.data * ram->timing.version) {
+       case 0x20:
+               WL = (nv_ro16(bios, ram->timing.data + 0x04) & 0x0f80) >> 7;
+               CL =  nv_ro08(bios, ram->timing.data + 0x04) & 0x1f;
+               WR =  nv_ro08(bios, ram->timing.data + 0x0a) & 0x7f;
+               break;
+       default:
+               return -ENOSYS;
+       }
+
+       WL = ramxlat(ramddr3_cwl, WL);
+       CL = ramxlat(ramddr3_cl, CL);
+       WR = ramxlat(ramddr3_wr, WR);
+       if (WL < 0 || CL < 0 || WR < 0)
+               return -EINVAL;
+
+       ram->mr[0] &= ~0xe74;
+       ram->mr[0] |= (WR & 0x07) << 9;
+       ram->mr[0] |= (CL & 0x0e) << 3;
+       ram->mr[0] |= (CL & 0x01) << 2;
+
+       ram->mr[2] &= ~0x038;
+       ram->mr[2] |= (WL & 0x07) << 3;
+       return 0;
+}
index d422acc..f572c28 100644 (file)
@@ -67,7 +67,7 @@ nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
                }
        }
 
-       return -EINVAL;
+       return -ENOENT;
 }
 
 static int
index 2895c19..041fd5e 100644 (file)
@@ -195,7 +195,7 @@ nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
 
 static int
 nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
-                    struct i2c_board_info *info,
+                    struct nouveau_i2c_board_info *info,
                     bool (*match)(struct nouveau_i2c_port *,
                                   struct i2c_board_info *))
 {
@@ -208,12 +208,29 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
        }
 
        nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index);
-       for (i = 0; info[i].addr; i++) {
-               if (nv_probe_i2c(port, info[i].addr) &&
-                   (!match || match(port, &info[i]))) {
-                       nv_info(i2c, "detected %s: %s\n", what, info[i].type);
+       for (i = 0; info[i].dev.addr; i++) {
+               u8 orig_udelay = 0;
+
+               if ((port->adapter.algo == &i2c_bit_algo) &&
+                   (info[i].udelay != 0)) {
+                       struct i2c_algo_bit_data *algo = port->adapter.algo_data;
+                       nv_debug(i2c, "using custom udelay %d instead of %d\n",
+                                info[i].udelay, algo->udelay);
+                       orig_udelay = algo->udelay;
+                       algo->udelay = info[i].udelay;
+               }
+
+               if (nv_probe_i2c(port, info[i].dev.addr) &&
+                   (!match || match(port, &info[i].dev))) {
+                       nv_info(i2c, "detected %s: %s\n", what,
+                               info[i].dev.type);
                        return i;
                }
+
+               if (orig_udelay) {
+                       struct i2c_algo_bit_data *algo = port->adapter.algo_data;
+                       algo->udelay = orig_udelay;
+               }
        }
 
        nv_debug(i2c, "no devices found.\n");
index d8bb48f..b4b9943 100644 (file)
 #include <subdev/mc.h>
 #include <core/option.h>
 
+static inline u32
+nouveau_mc_intr_mask(struct nouveau_mc *pmc)
+{
+       u32 intr = nv_rd32(pmc, 0x000100);
+       if (intr == 0xffffffff) /* likely fallen off the bus */
+               intr = 0x00000000;
+       return intr;
+}
+
 static irqreturn_t
 nouveau_mc_intr(int irq, void *arg)
 {
        struct nouveau_mc *pmc = arg;
-       const struct nouveau_mc_intr *map = pmc->intr_map;
+       const struct nouveau_mc_oclass *oclass = (void *)nv_object(pmc)->oclass;
+       const struct nouveau_mc_intr *map = oclass->intr;
        struct nouveau_subdev *unit;
-       u32 stat, intr;
-
-       intr = stat = nv_rd32(pmc, 0x000100);
-       if (intr == 0xffffffff)
-               return IRQ_NONE;
-       while (stat && map->stat) {
-               if (stat & map->stat) {
-                       unit = nouveau_subdev(pmc, map->unit);
-                       if (unit && unit->intr)
-                               unit->intr(unit);
-                       intr &= ~map->stat;
-               }
-               map++;
-       }
+       u32 intr;
 
+       nv_wr32(pmc, 0x000140, 0x00000000);
+       nv_rd32(pmc, 0x000140);
+       intr = nouveau_mc_intr_mask(pmc);
        if (pmc->use_msi)
-               nv_wr08(pmc->base.base.parent, 0x00088068, 0xff);
+               oclass->msi_rearm(pmc);
 
        if (intr) {
-               nv_error(pmc, "unknown intr 0x%08x\n", stat);
+               u32 stat = intr = nouveau_mc_intr_mask(pmc);
+               while (map->stat) {
+                       if (intr & map->stat) {
+                               unit = nouveau_subdev(pmc, map->unit);
+                               if (unit && unit->intr)
+                                       unit->intr(unit);
+                               stat &= ~map->stat;
+                       }
+                       map++;
+               }
+
+               if (stat)
+                       nv_error(pmc, "unknown intr 0x%08x\n", stat);
        }
 
-       return stat ? IRQ_HANDLED : IRQ_NONE;
+       nv_wr32(pmc, 0x000140, 0x00000001);
+       return intr ? IRQ_HANDLED : IRQ_NONE;
 }
 
 int
@@ -88,37 +101,42 @@ _nouveau_mc_dtor(struct nouveau_object *object)
 
 int
 nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
-                  struct nouveau_oclass *oclass,
-                  const struct nouveau_mc_intr *intr_map,
-                  int length, void **pobject)
+                  struct nouveau_oclass *bclass, int length, void **pobject)
 {
+       const struct nouveau_mc_oclass *oclass = (void *)bclass;
        struct nouveau_device *device = nv_device(parent);
        struct nouveau_mc *pmc;
        int ret;
 
-       ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PMC",
+       ret = nouveau_subdev_create_(parent, engine, bclass, 0, "PMC",
                                     "master", length, pobject);
        pmc = *pobject;
        if (ret)
                return ret;
 
-       pmc->intr_map = intr_map;
-
        switch (device->pdev->device & 0x0ff0) {
-       case 0x00f0: /* BR02? */
-       case 0x02e0: /* BR02? */
-               pmc->use_msi = false;
+       case 0x00f0:
+       case 0x02e0:
+               /* BR02? NFI how these would be handled yet exactly */
                break;
        default:
-               pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", true);
+               switch (device->chipset) {
+               case 0xaa: break; /* reported broken, nv also disable it */
+               default:
+                       pmc->use_msi = true;
+                       break;
+               }
+       }
+
+       pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", pmc->use_msi);
+       if (pmc->use_msi && oclass->msi_rearm) {
+               pmc->use_msi = pci_enable_msi(device->pdev) == 0;
                if (pmc->use_msi) {
-                       pmc->use_msi = pci_enable_msi(device->pdev) == 0;
-                       if (pmc->use_msi) {
-                               nv_info(pmc, "MSI interrupts enabled\n");
-                               nv_wr08(device, 0x00088068, 0xff);
-                       }
+                       nv_info(pmc, "MSI interrupts enabled\n");
+                       oclass->msi_rearm(pmc);
                }
-               break;
+       } else {
+               pmc->use_msi = false;
        }
 
        ret = request_irq(device->pdev->irq, nouveau_mc_intr,
index 64aa4ed..2d787e4 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/mc.h>
-
-struct nv04_mc_priv {
-       struct nouveau_mc base;
-};
+#include "nv04.h"
 
 const struct nouveau_mc_intr
 nv04_mc_intr[] = {
        { 0x00000001, NVDEV_ENGINE_MPEG },      /* NV17- MPEG/ME */
        { 0x00000100, NVDEV_ENGINE_FIFO },
        { 0x00001000, NVDEV_ENGINE_GR },
+       { 0x00010000, NVDEV_ENGINE_DISP },
        { 0x00020000, NVDEV_ENGINE_VP },        /* NV40- */
        { 0x00100000, NVDEV_SUBDEV_TIMER },
        { 0x01000000, NVDEV_ENGINE_DISP },      /* NV04- PCRTC0 */
@@ -42,7 +39,18 @@ nv04_mc_intr[] = {
        {}
 };
 
-static int
+int
+nv04_mc_init(struct nouveau_object *object)
+{
+       struct nv04_mc_priv *priv = (void *)object;
+
+       nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
+       nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */
+
+       return nouveau_mc_init(&priv->base);
+}
+
+int
 nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
             struct nouveau_oclass *oclass, void *data, u32 size,
             struct nouveau_object **pobject)
@@ -50,7 +58,7 @@ nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nv04_mc_priv *priv;
        int ret;
 
-       ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv);
+       ret = nouveau_mc_create(parent, engine, oclass, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
@@ -58,24 +66,14 @@ nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-int
-nv04_mc_init(struct nouveau_object *object)
-{
-       struct nv04_mc_priv *priv = (void *)object;
-
-       nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
-       nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */
-
-       return nouveau_mc_init(&priv->base);
-}
-
-struct nouveau_oclass
-nv04_mc_oclass = {
-       .handle = NV_SUBDEV(MC, 0x04),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv04_mc_oclass = &(struct nouveau_mc_oclass) {
+       .base.handle = NV_SUBDEV(MC, 0x04),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv04_mc_ctor,
                .dtor = _nouveau_mc_dtor,
                .init = nv04_mc_init,
                .fini = _nouveau_mc_fini,
        },
-};
+       .intr = nv04_mc_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
new file mode 100644 (file)
index 0000000..b0d5c31
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __NVKM_MC_NV04_H__
+#define __NVKM_MC_NV04_H__
+
+#include <subdev/mc.h>
+
+struct nv04_mc_priv {
+       struct nouveau_mc base;
+};
+
+int  nv04_mc_ctor(struct nouveau_object *, struct nouveau_object *,
+                 struct nouveau_oclass *, void *, u32,
+                 struct nouveau_object **);
+
+extern const struct nouveau_mc_intr nv04_mc_intr[];
+int  nv04_mc_init(struct nouveau_object *);
+void nv40_mc_msi_rearm(struct nouveau_mc *);
+int  nv50_mc_init(struct nouveau_object *);
+extern const struct nouveau_mc_intr nv50_mc_intr[];
+extern const struct nouveau_mc_intr nvc0_mc_intr[];
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c
new file mode 100644 (file)
index 0000000..5b1faec
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv04.h"
+
+void
+nv40_mc_msi_rearm(struct nouveau_mc *pmc)
+{
+       struct nv04_mc_priv *priv = (void *)pmc;
+       nv_wr08(priv, 0x088068, 0xff);
+}
+
+struct nouveau_oclass *
+nv40_mc_oclass = &(struct nouveau_mc_oclass) {
+       .base.handle = NV_SUBDEV(MC, 0x40),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_mc_ctor,
+               .dtor = _nouveau_mc_dtor,
+               .init = nv04_mc_init,
+               .fini = _nouveau_mc_fini,
+       },
+       .intr = nv04_mc_intr,
+       .msi_rearm = nv40_mc_msi_rearm,
+}.base;
index d989178..3bfee5c 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/mc.h>
-
-struct nv44_mc_priv {
-       struct nouveau_mc base;
-};
-
-static int
-nv44_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv44_mc_priv *priv;
-       int ret;
-
-       ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       return 0;
-}
+#include "nv04.h"
 
 static int
 nv44_mc_init(struct nouveau_object *object)
 {
-       struct nv44_mc_priv *priv = (void *)object;
+       struct nv04_mc_priv *priv = (void *)object;
        u32 tmp = nv_rd32(priv, 0x10020c);
 
        nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
@@ -60,13 +40,15 @@ nv44_mc_init(struct nouveau_object *object)
        return nouveau_mc_init(&priv->base);
 }
 
-struct nouveau_oclass
-nv44_mc_oclass = {
-       .handle = NV_SUBDEV(MC, 0x44),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv44_mc_ctor,
+struct nouveau_oclass *
+nv44_mc_oclass = &(struct nouveau_mc_oclass) {
+       .base.handle = NV_SUBDEV(MC, 0x44),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_mc_ctor,
                .dtor = _nouveau_mc_dtor,
                .init = nv44_mc_init,
                .fini = _nouveau_mc_fini,
        },
-};
+       .intr = nv04_mc_intr,
+       .msi_rearm = nv40_mc_msi_rearm,
+}.base;
index 2b1afe2..e8822a9 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/mc.h>
+#include "nv04.h"
 
-struct nv50_mc_priv {
-       struct nouveau_mc base;
-};
-
-static const struct nouveau_mc_intr
+const struct nouveau_mc_intr
 nv50_mc_intr[] = {
        { 0x00000001, NVDEV_ENGINE_MPEG },
        { 0x00000100, NVDEV_ENGINE_FIFO },
@@ -45,37 +41,30 @@ nv50_mc_intr[] = {
        {},
 };
 
-static int
-nv50_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
+static void
+nv50_mc_msi_rearm(struct nouveau_mc *pmc)
 {
-       struct nv50_mc_priv *priv;
-       int ret;
-
-       ret = nouveau_mc_create(parent, engine, oclass, nv50_mc_intr, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       return 0;
+       struct nouveau_device *device = nv_device(pmc);
+       pci_write_config_byte(device->pdev, 0x68, 0xff);
 }
 
 int
 nv50_mc_init(struct nouveau_object *object)
 {
-       struct nv50_mc_priv *priv = (void *)object;
+       struct nv04_mc_priv *priv = (void *)object;
        nv_wr32(priv, 0x000200, 0xffffffff); /* everything on */
        return nouveau_mc_init(&priv->base);
 }
 
-struct nouveau_oclass
-nv50_mc_oclass = {
-       .handle = NV_SUBDEV(MC, 0x50),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv50_mc_ctor,
+struct nouveau_oclass *
+nv50_mc_oclass = &(struct nouveau_mc_oclass) {
+       .base.handle = NV_SUBDEV(MC, 0x50),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_mc_ctor,
                .dtor = _nouveau_mc_dtor,
                .init = nv50_mc_init,
                .fini = _nouveau_mc_fini,
        },
-};
+       .intr = nv50_mc_intr,
+       .msi_rearm = nv50_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c
new file mode 100644 (file)
index 0000000..5f45411
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv04.h"
+
+struct nouveau_oclass *
+nv94_mc_oclass = &(struct nouveau_mc_oclass) {
+       .base.handle = NV_SUBDEV(MC, 0x94),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_mc_ctor,
+               .dtor = _nouveau_mc_dtor,
+               .init = nv50_mc_init,
+               .fini = _nouveau_mc_fini,
+       },
+       .intr = nv50_mc_intr,
+       .msi_rearm = nv40_mc_msi_rearm,
+}.base;
index 0671041..f8a6f18 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/mc.h>
-
-struct nv98_mc_priv {
-       struct nouveau_mc base;
-};
+#include "nv04.h"
 
 static const struct nouveau_mc_intr
 nv98_mc_intr[] = {
@@ -36,6 +32,7 @@ nv98_mc_intr[] = {
        { 0x00004000, NVDEV_ENGINE_CRYPT },     /* NV84:NVA3 */
        { 0x00008000, NVDEV_ENGINE_BSP },
        { 0x00020000, NVDEV_ENGINE_VP },
+       { 0x00040000, NVDEV_SUBDEV_PWR },       /* NVA3:NVC0 */
        { 0x00080000, NVDEV_SUBDEV_THERM },     /* NVA3:NVC0 */
        { 0x00100000, NVDEV_SUBDEV_TIMER },
        { 0x00200000, NVDEV_SUBDEV_GPIO },
@@ -47,29 +44,15 @@ nv98_mc_intr[] = {
        {},
 };
 
-static int
-nv98_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
-{
-       struct nv98_mc_priv *priv;
-       int ret;
-
-       ret = nouveau_mc_create(parent, engine, oclass, nv98_mc_intr, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-struct nouveau_oclass
-nv98_mc_oclass = {
-       .handle = NV_SUBDEV(MC, 0x98),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv98_mc_ctor,
+struct nouveau_oclass *
+nv98_mc_oclass = &(struct nouveau_mc_oclass) {
+       .base.handle = NV_SUBDEV(MC, 0x98),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_mc_ctor,
                .dtor = _nouveau_mc_dtor,
                .init = nv50_mc_init,
                .fini = _nouveau_mc_fini,
        },
-};
+       .intr = nv98_mc_intr,
+       .msi_rearm = nv40_mc_msi_rearm,
+}.base;
index 104175c..c02b476 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/mc.h>
+#include "nv04.h"
 
-struct nvc0_mc_priv {
-       struct nouveau_mc base;
-};
-
-static const struct nouveau_mc_intr
+const struct nouveau_mc_intr
 nvc0_mc_intr[] = {
        { 0x00000001, NVDEV_ENGINE_PPP },
        { 0x00000020, NVDEV_ENGINE_COPY0 },
@@ -41,6 +37,7 @@ nvc0_mc_intr[] = {
        { 0x00020000, NVDEV_ENGINE_VP },
        { 0x00100000, NVDEV_SUBDEV_TIMER },
        { 0x00200000, NVDEV_SUBDEV_GPIO },
+       { 0x01000000, NVDEV_SUBDEV_PWR },
        { 0x02000000, NVDEV_SUBDEV_LTCG },
        { 0x04000000, NVDEV_ENGINE_DISP },
        { 0x10000000, NVDEV_SUBDEV_BUS },
@@ -49,29 +46,22 @@ nvc0_mc_intr[] = {
        {},
 };
 
-static int
-nvc0_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-            struct nouveau_oclass *oclass, void *data, u32 size,
-            struct nouveau_object **pobject)
+static void
+nvc0_mc_msi_rearm(struct nouveau_mc *pmc)
 {
-       struct nvc0_mc_priv *priv;
-       int ret;
-
-       ret = nouveau_mc_create(parent, engine, oclass, nvc0_mc_intr, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       return 0;
+       struct nv04_mc_priv *priv = (void *)pmc;
+       nv_wr32(priv, 0x088704, 0x00000000);
 }
 
-struct nouveau_oclass
-nvc0_mc_oclass = {
-       .handle = NV_SUBDEV(MC, 0xc0),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nvc0_mc_ctor,
+struct nouveau_oclass *
+nvc0_mc_oclass = &(struct nouveau_mc_oclass) {
+       .base.handle = NV_SUBDEV(MC, 0xc0),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_mc_ctor,
                .dtor = _nouveau_mc_dtor,
                .init = nv50_mc_init,
                .fini = _nouveau_mc_fini,
        },
-};
+       .intr = nvc0_mc_intr,
+       .msi_rearm = nvc0_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c
new file mode 100644 (file)
index 0000000..837e545
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv04.h"
+
+struct nouveau_oclass *
+nvc3_mc_oclass = &(struct nouveau_mc_oclass) {
+       .base.handle = NV_SUBDEV(MC, 0xc3),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_mc_ctor,
+               .dtor = _nouveau_mc_dtor,
+               .init = nv50_mc_init,
+               .fini = _nouveau_mc_fini,
+       },
+       .intr = nvc0_mc_intr,
+       .msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
new file mode 100644 (file)
index 0000000..9908f1f
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/pwr.h>
+#include <subdev/timer.h>
+
+static int
+nouveau_pwr_send(struct nouveau_pwr *ppwr, u32 reply[2],
+                u32 process, u32 message, u32 data0, u32 data1)
+{
+       struct nouveau_subdev *subdev = nv_subdev(ppwr);
+       u32 addr;
+
+       /* we currently only support a single process at a time waiting
+        * on a synchronous reply, take the PPWR mutex and tell the
+        * receive handler what we're waiting for
+        */
+       if (reply) {
+               mutex_lock(&subdev->mutex);
+               ppwr->recv.message = message;
+               ppwr->recv.process = process;
+       }
+
+       /* wait for a free slot in the fifo */
+       addr  = nv_rd32(ppwr, 0x10a4a0);
+       if (!nv_wait_ne(ppwr, 0x10a4b0, 0xffffffff, addr ^ 8))
+               return -EBUSY;
+
+       /* acquire data segment access */
+       do {
+               nv_wr32(ppwr, 0x10a580, 0x00000001);
+       } while (nv_rd32(ppwr, 0x10a580) != 0x00000001);
+
+       /* write the packet */
+       nv_wr32(ppwr, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) +
+                               ppwr->send.base));
+       nv_wr32(ppwr, 0x10a1c4, process);
+       nv_wr32(ppwr, 0x10a1c4, message);
+       nv_wr32(ppwr, 0x10a1c4, data0);
+       nv_wr32(ppwr, 0x10a1c4, data1);
+       nv_wr32(ppwr, 0x10a4a0, (addr + 1) & 0x0f);
+
+       /* release data segment access */
+       nv_wr32(ppwr, 0x10a580, 0x00000000);
+
+       /* wait for reply, if requested */
+       if (reply) {
+               wait_event(ppwr->recv.wait, (ppwr->recv.process == 0));
+               reply[0] = ppwr->recv.data[0];
+               reply[1] = ppwr->recv.data[1];
+               mutex_unlock(&subdev->mutex);
+       }
+
+       return 0;
+}
+
+static void
+nouveau_pwr_recv(struct work_struct *work)
+{
+       struct nouveau_pwr *ppwr =
+               container_of(work, struct nouveau_pwr, recv.work);
+       u32 process, message, data0, data1;
+
+       /* nothing to do if GET == PUT */
+       u32 addr =  nv_rd32(ppwr, 0x10a4cc);
+       if (addr == nv_rd32(ppwr, 0x10a4c8))
+               return;
+
+       /* acquire data segment access */
+       do {
+               nv_wr32(ppwr, 0x10a580, 0x00000002);
+       } while (nv_rd32(ppwr, 0x10a580) != 0x00000002);
+
+       /* read the packet */
+       nv_wr32(ppwr, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) +
+                               ppwr->recv.base));
+       process = nv_rd32(ppwr, 0x10a1c4);
+       message = nv_rd32(ppwr, 0x10a1c4);
+       data0   = nv_rd32(ppwr, 0x10a1c4);
+       data1   = nv_rd32(ppwr, 0x10a1c4);
+       nv_wr32(ppwr, 0x10a4cc, (addr + 1) & 0x0f);
+
+       /* release data segment access */
+       nv_wr32(ppwr, 0x10a580, 0x00000000);
+
+       /* wake process if it's waiting on a synchronous reply */
+       if (ppwr->recv.process) {
+               if (process == ppwr->recv.process &&
+                   message == ppwr->recv.message) {
+                       ppwr->recv.data[0] = data0;
+                       ppwr->recv.data[1] = data1;
+                       ppwr->recv.process = 0;
+                       wake_up(&ppwr->recv.wait);
+                       return;
+               }
+       }
+
+       /* right now there's no other expected responses from the engine,
+        * so assume that any unexpected message is an error.
+        */
+       nv_warn(ppwr, "%c%c%c%c 0x%08x 0x%08x 0x%08x 0x%08x\n",
+               (char)((process & 0x000000ff) >>  0),
+               (char)((process & 0x0000ff00) >>  8),
+               (char)((process & 0x00ff0000) >> 16),
+               (char)((process & 0xff000000) >> 24),
+               process, message, data0, data1);
+}
+
+static void
+nouveau_pwr_intr(struct nouveau_subdev *subdev)
+{
+       struct nouveau_pwr *ppwr = (void *)subdev;
+       u32 disp = nv_rd32(ppwr, 0x10a01c);
+       u32 intr = nv_rd32(ppwr, 0x10a008) & disp & ~(disp >> 16);
+
+       if (intr & 0x00000020) {
+               u32 stat = nv_rd32(ppwr, 0x10a16c);
+               if (stat & 0x80000000) {
+                       nv_error(ppwr, "UAS fault at 0x%06x addr 0x%08x\n",
+                                stat & 0x00ffffff, nv_rd32(ppwr, 0x10a168));
+                       nv_wr32(ppwr, 0x10a16c, 0x00000000);
+                       intr &= ~0x00000020;
+               }
+       }
+
+       if (intr & 0x00000040) {
+               schedule_work(&ppwr->recv.work);
+               nv_wr32(ppwr, 0x10a004, 0x00000040);
+               intr &= ~0x00000040;
+       }
+
+       if (intr & 0x00000080) {
+               nv_info(ppwr, "wr32 0x%06x 0x%08x\n", nv_rd32(ppwr, 0x10a7a0),
+                                                     nv_rd32(ppwr, 0x10a7a4));
+               nv_wr32(ppwr, 0x10a004, 0x00000080);
+               intr &= ~0x00000080;
+       }
+
+       if (intr) {
+               nv_error(ppwr, "intr 0x%08x\n", intr);
+               nv_wr32(ppwr, 0x10a004, intr);
+       }
+}
+
+int
+_nouveau_pwr_fini(struct nouveau_object *object, bool suspend)
+{
+       struct nouveau_pwr *ppwr = (void *)object;
+
+       nv_wr32(ppwr, 0x10a014, 0x00000060);
+       flush_work(&ppwr->recv.work);
+
+       return nouveau_subdev_fini(&ppwr->base, suspend);
+}
+
+int
+_nouveau_pwr_init(struct nouveau_object *object)
+{
+       struct nouveau_pwr *ppwr = (void *)object;
+       int ret, i;
+
+       ret = nouveau_subdev_init(&ppwr->base);
+       if (ret)
+               return ret;
+
+       nv_subdev(ppwr)->intr = nouveau_pwr_intr;
+       ppwr->message = nouveau_pwr_send;
+
+       /* prevent previous ucode from running, wait for idle, reset */
+       nv_wr32(ppwr, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */
+       nv_wait(ppwr, 0x10a04c, 0xffffffff, 0x00000000);
+       nv_mask(ppwr, 0x000200, 0x00002000, 0x00000000);
+       nv_mask(ppwr, 0x000200, 0x00002000, 0x00002000);
+
+       /* upload data segment */
+       nv_wr32(ppwr, 0x10a1c0, 0x01000000);
+       for (i = 0; i < ppwr->data.size / 4; i++)
+               nv_wr32(ppwr, 0x10a1c4, ppwr->data.data[i]);
+
+       /* upload code segment */
+       nv_wr32(ppwr, 0x10a180, 0x01000000);
+       for (i = 0; i < ppwr->code.size / 4; i++) {
+               if ((i & 0x3f) == 0)
+                       nv_wr32(ppwr, 0x10a188, i >> 6);
+               nv_wr32(ppwr, 0x10a184, ppwr->code.data[i]);
+       }
+
+       /* start it running */
+       nv_wr32(ppwr, 0x10a10c, 0x00000000);
+       nv_wr32(ppwr, 0x10a104, 0x00000000);
+       nv_wr32(ppwr, 0x10a100, 0x00000002);
+
+       /* wait for valid host->pwr ring configuration */
+       if (!nv_wait_ne(ppwr, 0x10a4d0, 0xffffffff, 0x00000000))
+               return -EBUSY;
+       ppwr->send.base = nv_rd32(ppwr, 0x10a4d0) & 0x0000ffff;
+       ppwr->send.size = nv_rd32(ppwr, 0x10a4d0) >> 16;
+
+       /* wait for valid pwr->host ring configuration */
+       if (!nv_wait_ne(ppwr, 0x10a4dc, 0xffffffff, 0x00000000))
+               return -EBUSY;
+       ppwr->recv.base = nv_rd32(ppwr, 0x10a4dc) & 0x0000ffff;
+       ppwr->recv.size = nv_rd32(ppwr, 0x10a4dc) >> 16;
+
+       nv_wr32(ppwr, 0x10a010, 0x000000e0);
+       return 0;
+}
+
+int
+nouveau_pwr_create_(struct nouveau_object *parent,
+                   struct nouveau_object *engine,
+                   struct nouveau_oclass *oclass, int length, void **pobject)
+{
+       struct nouveau_pwr *ppwr;
+       int ret;
+
+       ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PPWR",
+                                    "pwr", length, pobject);
+       ppwr = *pobject;
+       if (ret)
+               return ret;
+
+       INIT_WORK(&ppwr->recv.work, nouveau_pwr_recv);
+       init_waitqueue_head(&ppwr->recv.wait);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc
new file mode 100644 (file)
index 0000000..2284ecb
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_PROC
+process(PROC_HOST, #host_init, #host_recv)
+#endif
+
+/******************************************************************************
+ * HOST data segment
+ *****************************************************************************/
+#ifdef INCLUDE_DATA
+// HOST (R)FIFO packet format
+.equ #fifo_process 0x00
+.equ #fifo_message 0x04
+.equ #fifo_data0   0x08
+.equ #fifo_data1   0x0c
+
+// HOST HOST->PWR queue description
+.equ #fifo_qlen 4 // log2(size of queue entry in bytes)
+.equ #fifo_qnum 3 // log2(max number of entries in queue)
+.equ #fifo_qmaskb (1 << #fifo_qnum) // max number of entries in queue
+.equ #fifo_qmaskp (#fifo_qmaskb - 1)
+.equ #fifo_qmaskf ((#fifo_qmaskb << 1) - 1)
+.equ #fifo_qsize  (1 << (#fifo_qlen + #fifo_qnum))
+fifo_queue: .skip 128 // #fifo_qsize
+
+// HOST PWR->HOST queue description
+.equ #rfifo_qlen 4 // log2(size of queue entry in bytes)
+.equ #rfifo_qnum 3 // log2(max number of entries in queue)
+.equ #rfifo_qmaskb (1 << #rfifo_qnum) // max number of entries in queue
+.equ #rfifo_qmaskp (#rfifo_qmaskb - 1)
+.equ #rfifo_qmaskf ((#rfifo_qmaskb << 1) - 1)
+.equ #rfifo_qsize  (1 << (#rfifo_qlen + #rfifo_qnum))
+rfifo_queue: .skip 128 // #rfifo_qsize
+#endif
+
+/******************************************************************************
+ * HOST code segment
+ *****************************************************************************/
+#ifdef INCLUDE_CODE
+// HOST->PWR comms - dequeue message(s) for process(es) from FIFO
+//
+// $r15 - current (host)
+// $r0  - zero
+host_send:
+       nv_iord($r1, NV_PPWR_FIFO_GET(0))
+       nv_iord($r2, NV_PPWR_FIFO_PUT(0))
+       cmp b32 $r1 $r2
+       bra e #host_send_done
+               // calculate address of message
+               and $r14 $r1 #fifo_qmaskp
+               shl b32 $r14 $r14 #fifo_qlen
+               add b32 $r14 #fifo_queue
+
+               // read message data, and pass to appropriate process
+               ld b32 $r11 D[$r14 + #fifo_data1]
+               ld b32 $r12 D[$r14 + #fifo_data0]
+               ld b32 $r13 D[$r14 + #fifo_message]
+               ld b32 $r14 D[$r14 + #fifo_process]
+               call(send)
+
+               // increment GET
+               add b32 $r1 0x1
+               and $r14 $r1 #fifo_qmaskf
+               nv_iowr(NV_PPWR_FIFO_GET(0), $r1)
+               bra #host_send
+       host_send_done:
+       ret
+
+// PWR->HOST comms - enqueue message for HOST to RFIFO
+//
+// $r15 - current (host)
+// $r14 - process
+// $r13 - message
+// $r12 - message data 0
+// $r11 - message data 1
+// $r0  - zero
+host_recv:
+       // message from intr handler == HOST->PWR comms pending
+       mov $r1 (PROC_KERN & 0x0000ffff)
+       sethi $r1 (PROC_KERN & 0xffff0000)
+       cmp b32 $r14 $r1
+       bra e #host_send
+
+       // wait for space in RFIFO
+       host_recv_wait:
+       nv_iord($r1, NV_PPWR_RFIFO_GET)
+       nv_iord($r2, NV_PPWR_RFIFO_PUT)
+       xor $r1 #rfifo_qmaskb
+       cmp b32 $r1 $r2
+       bra e #host_recv_wait
+
+       and $r3 $r2 #rfifo_qmaskp
+       shl b32 $r3 #rfifo_qlen
+       add b32 $r3 #rfifo_queue
+
+       // enqueue message
+       st b32 D[$r3 + #fifo_data1] $r11
+       st b32 D[$r3 + #fifo_data0] $r12
+       st b32 D[$r3 + #fifo_message] $r13
+       st b32 D[$r3 + #fifo_process] $r14
+
+       add b32 $r2 0x1
+       and $r2 #rfifo_qmaskf
+       nv_iowr(NV_PPWR_RFIFO_PUT, $r2)
+
+       // notify host of pending message
+       mov $r2 NV_PPWR_INTR_TRIGGER_USER0
+       nv_iowr(NV_PPWR_INTR_TRIGGER, $r2)
+       ret
+
+// $r15 - current (host)
+// $r0  - zero
+host_init:
+       // store each fifo's base/size in H2D/D2H scratch regs
+       mov $r1 #fifo_qsize
+       shl b32 $r1 16
+       or $r1 #fifo_queue
+       nv_iowr(NV_PPWR_H2D, $r1);
+
+       mov $r1 #rfifo_qsize
+       shl b32 $r1 16
+       or $r1 #rfifo_queue
+       nv_iowr(NV_PPWR_D2H, $r1);
+
+       // enable fifo subintr for first fifo
+       mov $r1 1
+       nv_iowr(NV_PPWR_FIFO_INTR_EN, $r1)
+       ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc
new file mode 100644 (file)
index 0000000..98f1c37
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_PROC
+process(PROC_IDLE, #idle, #idle_recv)
+#endif
+
+/******************************************************************************
+ * IDLE data segment
+ *****************************************************************************/
+#ifdef INCLUDE_DATA
+#endif
+
+/******************************************************************************
+ * IDLE code segment
+ *****************************************************************************/
+#ifdef INCLUDE_CODE
+// description
+//
+// $r15 - current (idle)
+// $r14 - message
+// $r0  - zero
+idle_recv:
+       ret
+
+// description
+//
+// $r15 - current (idle)
+// $r0  - zero
+idle:
+       // set our "no interrupt has occurred during our execution" flag
+       bset $flags $p0
+
+       // count IDLE invocations for debugging purposes
+       nv_iord($r1, NV_PPWR_DSCRATCH(1))
+       add b32 $r1 1
+       nv_iowr(NV_PPWR_DSCRATCH(1), $r1)
+
+       // keep looping while there's pending messages for any process
+       idle_loop:
+       mov $r1 #proc_list_head
+       bclr $flags $p2
+       idle_proc:
+               // process the process' messages until there's none left
+               idle_proc_exec:
+                       push $r1
+                       mov b32 $r14 $r1
+                       call(recv)
+                       pop $r1
+                       bra not $p1 #idle_proc_next
+                       bset $flags $p2
+                       bra #idle_proc_exec
+               // next process!
+               idle_proc_next:
+               add b32 $r1 #proc_size
+               cmp b32 $r1 $r15
+               bra ne #idle_proc
+       bra $p2 #idle_loop
+
+       // sleep if no interrupts have occurred
+       sleep $p0
+       bra #idle
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc
new file mode 100644 (file)
index 0000000..0a7b05f
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/******************************************************************************
+ * kernel data segment
+ *****************************************************************************/
+#ifdef INCLUDE_PROC
+proc_kern:
+process(PROC_KERN, 0, 0)
+proc_list_head:
+#endif
+
+#ifdef INCLUDE_DATA
+proc_list_tail:
+time_prev: .b32 0
+time_next: .b32 0
+#endif
+
+/******************************************************************************
+ * kernel code segment
+ *****************************************************************************/
+#ifdef INCLUDE_CODE
+       bra #init
+
+// read nv register
+//
+// $r15 - current
+// $r14 - addr
+// $r13 - data (return)
+// $r0  - zero
+rd32:
+       nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
+       mov $r14 NV_PPWR_MMIO_CTRL_OP_RD
+       sethi $r14 NV_PPWR_MMIO_CTRL_TRIGGER
+       nv_iowr(NV_PPWR_MMIO_CTRL, $r14)
+       rd32_wait:
+               nv_iord($r14, NV_PPWR_MMIO_CTRL)
+               and $r14 NV_PPWR_MMIO_CTRL_STATUS
+               bra nz #rd32_wait
+       nv_iord($r13, NV_PPWR_MMIO_DATA)
+       ret
+
+// write nv register
+//
+// $r15 - current
+// $r14 - addr
+// $r13 - data
+// $r0  - zero
+wr32:
+       nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
+       nv_iowr(NV_PPWR_MMIO_DATA, $r13)
+       mov $r14 NV_PPWR_MMIO_CTRL_OP_WR
+       or $r14 NV_PPWR_MMIO_CTRL_MASK_B32_0
+       sethi $r14 NV_PPWR_MMIO_CTRL_TRIGGER
+
+#ifdef NVKM_FALCON_MMIO_TRAP
+       mov $r8 NV_PPWR_INTR_TRIGGER_USER1
+       nv_iowr(NV_PPWR_INTR_TRIGGER, $r8)
+       wr32_host:
+               nv_iord($r8, NV_PPWR_INTR)
+               and $r8 NV_PPWR_INTR_USER1
+               bra nz #wr32_host
+#endif
+
+       nv_iowr(NV_PPWR_MMIO_CTRL, $r14)
+       wr32_wait:
+               nv_iord($r14, NV_PPWR_MMIO_CTRL)
+               and $r14 NV_PPWR_MMIO_CTRL_STATUS
+               bra nz #wr32_wait
+       ret
+
+// busy-wait for a period of time
+//
+// $r15 - current
+// $r14 - ns
+// $r0  - zero
+nsec:
+       nv_iord($r8, NV_PPWR_TIMER_LOW)
+       nsec_loop:
+               nv_iord($r9, NV_PPWR_TIMER_LOW)
+               sub b32 $r9 $r8
+               cmp b32 $r9 $r14
+               bra l #nsec_loop
+       ret
+
+// busy-wait for a period of time
+//
+// $r15 - current
+// $r14 - addr
+// $r13 - mask
+// $r12 - data
+// $r11 - timeout (ns)
+// $r0  - zero
+wait:
+       nv_iord($r8, NV_PPWR_TIMER_LOW)
+       wait_loop:
+               nv_rd32($r10, $r14)
+               and $r10 $r13
+               cmp b32 $r10 $r12
+               bra e #wait_done
+               nv_iord($r9, NV_PPWR_TIMER_LOW)
+               sub b32 $r9 $r8
+               cmp b32 $r9 $r11
+               bra l #wait_loop
+       wait_done:
+       ret
+
+// $r15 - current (kern)
+// $r14 - process
+// $r8  - NV_PPWR_INTR
+intr_watchdog:
+       // read process' timer status, skip if not enabled
+       ld b32 $r9 D[$r14 + #proc_time]
+       cmp b32 $r9 0
+       bra z #intr_watchdog_next_proc
+
+       // subtract last timer's value from process' timer,
+       // if it's <= 0 then the timer has expired
+       ld b32 $r10 D[$r0 + #time_prev]
+       sub b32 $r9 $r10
+       bra g #intr_watchdog_next_time
+               mov $r13 KMSG_ALARM
+               call(send_proc)
+               clear b32 $r9
+               bra #intr_watchdog_next_proc
+
+       // otherwise, update the next timer's value if this
+       // process' timer is the soonest
+       intr_watchdog_next_time:
+               // ... or if there's no next timer yet
+               ld b32 $r10 D[$r0 + #time_next]
+               cmp b32 $r10 0
+               bra z #intr_watchdog_next_time_set
+
+               cmp b32 $r9 $r10
+               bra g #intr_watchdog_next_proc
+               intr_watchdog_next_time_set:
+               st b32 D[$r0 + #time_next] $r9
+
+       // update process' timer status, and advance
+       intr_watchdog_next_proc:
+       st b32 D[$r14 + #proc_time] $r9
+       add b32 $r14 #proc_size
+       cmp b32 $r14 #proc_list_tail
+       bra ne #intr_watchdog
+       ret
+
+intr:
+       push $r0
+       clear b32 $r0
+       push $r8
+       push $r9
+       push $r10
+       push $r11
+       push $r12
+       push $r13
+       push $r14
+       push $r15
+       mov $r15 #proc_kern
+       mov $r8 $flags
+       push $r8
+
+       nv_iord($r8, NV_PPWR_DSCRATCH(0))
+       add b32 $r8 1
+       nv_iowr(NV_PPWR_DSCRATCH(0), $r8)
+
+       nv_iord($r8, NV_PPWR_INTR)
+       and $r9 $r8 NV_PPWR_INTR_WATCHDOG
+       bra z #intr_skip_watchdog
+               st b32 D[$r0 + #time_next] $r0
+               mov $r14 #proc_list_head
+               call(intr_watchdog)
+               ld b32 $r9 D[$r0 + #time_next]
+               cmp b32 $r9 0
+               bra z #intr_skip_watchdog
+                       nv_iowr(NV_PPWR_WATCHDOG_TIME, $r9)
+                       st b32 D[$r0 + #time_prev] $r9
+
+       intr_skip_watchdog:
+       and $r9 $r8 NV_PPWR_INTR_SUBINTR
+       bra z #intr_skip_subintr
+               nv_iord($r9, NV_PPWR_SUBINTR)
+               and $r10 $r9 NV_PPWR_SUBINTR_FIFO
+               bra z #intr_subintr_skip_fifo
+                       nv_iord($r12, NV_PPWR_FIFO_INTR)
+                       push $r12
+                       mov $r14 (PROC_HOST & 0x0000ffff)
+                       sethi $r14 (PROC_HOST & 0xffff0000)
+                       mov $r13 KMSG_FIFO
+                       call(send)
+                       pop $r12
+                       nv_iowr(NV_PPWR_FIFO_INTR, $r12)
+               intr_subintr_skip_fifo:
+               nv_iowr(NV_PPWR_SUBINTR, $r9)
+
+       intr_skip_subintr:
+       and $r9 $r8 NV_PPWR_INTR_PAUSE
+       bra z #intr_skip_pause
+               and $r10 0xffbf
+
+       intr_skip_pause:
+       and $r9 $r8 NV_PPWR_INTR_USER0
+       bra z #intr_skip_user0
+               and $r10 0xffbf
+
+       intr_skip_user0:
+       nv_iowr(NV_PPWR_INTR_ACK, $r8)
+       pop $r8
+       mov $flags $r8
+       pop $r15
+       pop $r14
+       pop $r13
+       pop $r12
+       pop $r11
+       pop $r10
+       pop $r9
+       pop $r8
+       pop $r0
+       bclr $flags $p0
+       iret
+
+// request the current process be sent a message after a timeout expires
+//
+// $r15 - current
+// $r14 - ticks
+// $r0  - zero
+timer:
+       // interrupts off to prevent racing with timer isr
+       bclr $flags ie0
+
+       // if current process already has a timer set, bail
+       ld b32 $r8 D[$r15 + #proc_time]
+       cmp b32 $r8 0
+       bra g #timer_done
+       st b32 D[$r15 + #proc_time] $r14
+
+       // halt watchdog timer temporarily and check for a pending
+       // interrupt.  if there's one already pending, we can just
+       // bail since the timer isr will queue the next soonest
+       // right after it's done
+       nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
+       nv_iord($r8, NV_PPWR_INTR)
+       and $r8 NV_PPWR_INTR_WATCHDOG
+       bra nz #timer_enable
+
+       // update the watchdog if this timer should expire first,
+       // or if there's no timeout already set
+       nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
+       cmp b32 $r14 $r0
+       bra e #timer_reset
+       cmp b32 $r14 $r8
+       bra l #timer_done
+       timer_reset:
+       nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
+       st b32 D[$r0 + #time_prev] $r14
+
+       // re-enable the watchdog timer
+       timer_enable:
+       mov $r8 1
+       nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
+
+       // interrupts back on
+       timer_done:
+       bset $flags ie0
+       ret
+
+// send message to another process
+//
+// $r15 - current
+// $r14 - process
+// $r13 - message
+// $r12 - message data 0
+// $r11 - message data 1
+// $r0  - zero
+send_proc:
+       push $r8
+       push $r9
+       // check for space in queue
+       ld b32 $r8 D[$r14 + #proc_qget]
+       ld b32 $r9 D[$r14 + #proc_qput]
+       xor $r8 #proc_qmaskb
+       cmp b32 $r8 $r9
+       bra e #send_done
+
+       // enqueue message
+       and $r8 $r9 #proc_qmaskp
+       shl b32 $r8 $r8 #proc_qlen
+       add b32 $r8 #proc_queue
+       add b32 $r8 $r14
+
+       ld b32 $r10 D[$r15 + #proc_id]
+       st b32 D[$r8 + #msg_process] $r10
+       st b32 D[$r8 + #msg_message] $r13
+       st b32 D[$r8 + #msg_data0] $r12
+       st b32 D[$r8 + #msg_data1] $r11
+
+       // increment PUT
+       add b32 $r9 1
+       and $r9 #proc_qmaskf
+       st b32 D[$r14 + #proc_qput] $r9
+       bset $flags $p2
+       send_done:
+       pop $r9
+       pop $r8
+       ret
+
+// lookup process structure by its name
+//
+// $r15 - current
+// $r14 - process name
+// $r0  - zero
+//
+// $r14 - process
+// $p1  - success
+find:
+       push $r8
+       mov $r8 #proc_list_head
+       bset $flags $p1
+       find_loop:
+               ld b32 $r10 D[$r8 + #proc_id]
+               cmp b32 $r10 $r14
+               bra e #find_done
+               add b32 $r8 #proc_size
+               cmp b32 $r8 #proc_list_tail
+               bra ne #find_loop
+               bclr $flags $p1
+       find_done:
+       mov b32 $r14 $r8
+       pop $r8
+       ret
+
+// send message to another process
+//
+// $r15 - current
+// $r14 - process id
+// $r13 - message
+// $r12 - message data 0
+// $r11 - message data 1
+// $r0  - zero
+send:
+       call(find)
+       bra $p1 #send_proc
+       ret
+
+// process single message for a given process
+//
+// $r15 - current
+// $r14 - process
+// $r0  - zero
+recv:
+       ld b32 $r8 D[$r14 + #proc_qget]
+       ld b32 $r9 D[$r14 + #proc_qput]
+       bclr $flags $p1
+       cmp b32 $r8 $r9
+       bra e #recv_done
+               // dequeue message
+               and $r9 $r8 #proc_qmaskp
+               add b32 $r8 1
+               and $r8 #proc_qmaskf
+               st b32 D[$r14 + #proc_qget] $r8
+               ld b32 $r10 D[$r14 + #proc_recv]
+
+               push $r15
+               mov $r15 $flags
+               push $r15
+               mov b32 $r15 $r14
+
+               shl b32 $r9 $r9 #proc_qlen
+               add b32 $r14 $r9
+               add b32 $r14 #proc_queue
+               ld b32 $r11 D[$r14 + #msg_data1]
+               ld b32 $r12 D[$r14 + #msg_data0]
+               ld b32 $r13 D[$r14 + #msg_message]
+               ld b32 $r14 D[$r14 + #msg_process]
+
+               // process it
+               call $r10
+               pop $r15
+               mov $flags $r15
+               bset $flags $p1
+               pop $r15
+       recv_done:
+       ret
+
+init:
+       // setup stack
+       nv_iord($r1, NV_PPWR_CAPS)
+       extr $r1 $r1 9:17
+       shl b32 $r1 8
+       mov $sp $r1
+
+#ifdef NVKM_FALCON_MMIO_UAS
+       // somehow allows the magic "access mmio via D[]" stuff that's
+       // used by the nv_rd32/nv_wr32 macros to work
+       mov $r1 0x0010
+       sethi $r1 NV_PPWR_UAS_CONFIG_ENABLE
+       nv_iowrs(NV_PPWR_UAS_CONFIG, $r1)
+#endif
+
+       // route all interrupts except user0/1 and pause to fuc
+       mov $r1 0x00e0
+       sethi $r1 0x00000000
+       nv_iowr(NV_PPWR_INTR_ROUTE, $r1)
+
+       // enable watchdog and subintr intrs
+       mov $r1 NV_PPWR_INTR_EN_CLR_MASK
+       nv_iowr(NV_PPWR_INTR_EN_CLR, $r1)
+       mov $r1 NV_PPWR_INTR_EN_SET_WATCHDOG
+       or $r1 NV_PPWR_INTR_EN_SET_SUBINTR
+       nv_iowr(NV_PPWR_INTR_EN_SET, $r1)
+
+       // enable interrupts globally
+       mov $r1 #intr
+       sethi $r1 0x00000000
+       mov $iv0 $r1
+       bset $flags ie0
+
+       // enable watchdog timer
+       mov $r1 1
+       nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r1)
+
+       // bootstrap processes, idle process will be last, and not return
+       mov $r15 #proc_list_head
+       init_proc:
+               ld b32 $r1 D[$r15 + #proc_init]
+               cmp b32 $r1 0
+               bra z #init_proc
+               call $r1
+               add b32 $r15 #proc_size
+               bra #init_proc
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc
new file mode 100644 (file)
index 0000000..2a74ea9
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define GT215 0xa3
+#define GF100 0xc0
+#define GF119 0xd9
+#define GK208 0x108
+
+#include "os.h"
+
+// IO addresses
+#define NV_PPWR_INTR_TRIGGER                                             0x0000
+#define NV_PPWR_INTR_TRIGGER_USER1                                   0x00000080
+#define NV_PPWR_INTR_TRIGGER_USER0                                   0x00000040
+#define NV_PPWR_INTR_ACK                                                 0x0004
+#define NV_PPWR_INTR_ACK_SUBINTR                                     0x00000800
+#define NV_PPWR_INTR_ACK_WATCHDOG                                    0x00000002
+#define NV_PPWR_INTR                                                     0x0008
+#define NV_PPWR_INTR_SUBINTR                                         0x00000800
+#define NV_PPWR_INTR_USER1                                           0x00000080
+#define NV_PPWR_INTR_USER0                                           0x00000040
+#define NV_PPWR_INTR_PAUSE                                           0x00000020
+#define NV_PPWR_INTR_WATCHDOG                                        0x00000002
+#define NV_PPWR_INTR_EN_SET                                              0x0010
+#define NV_PPWR_INTR_EN_SET_SUBINTR                                  0x00000800
+#define NV_PPWR_INTR_EN_SET_WATCHDOG                                 0x00000002
+#define NV_PPWR_INTR_EN_CLR                                              0x0014
+#define NV_PPWR_INTR_EN_CLR_MASK                    /* fuck i hate envyas */ -1
+#define NV_PPWR_INTR_ROUTE                                               0x001c
+#define NV_PPWR_TIMER_LOW                                                0x002c
+#define NV_PPWR_WATCHDOG_TIME                                            0x0034
+#define NV_PPWR_WATCHDOG_ENABLE                                          0x0038
+#define NV_PPWR_CAPS                                                     0x0108
+#define NV_PPWR_UAS_CONFIG                                               0x0164
+#define NV_PPWR_UAS_CONFIG_ENABLE                                    0x00010000
+#if NVKM_PPWR_CHIPSET >= GK208
+#define NV_PPWR_DSCRATCH(i)                                   (4 * (i) + 0x0450)
+#endif
+#define NV_PPWR_FIFO_PUT(i)                                   (4 * (i) + 0x04a0)
+#define NV_PPWR_FIFO_GET(i)                                   (4 * (i) + 0x04b0)
+#define NV_PPWR_FIFO_INTR                                                0x04c0
+#define NV_PPWR_FIFO_INTR_EN                                             0x04c4
+#define NV_PPWR_RFIFO_PUT                                                0x04c8
+#define NV_PPWR_RFIFO_GET                                                0x04cc
+#define NV_PPWR_H2D                                                      0x04d0
+#define NV_PPWR_D2H                                                      0x04dc
+#if NVKM_PPWR_CHIPSET < GK208
+#define NV_PPWR_DSCRATCH(i)                                   (4 * (i) + 0x05d0)
+#endif
+#define NV_PPWR_SUBINTR                                                  0x0688
+#define NV_PPWR_SUBINTR_FIFO                                         0x00000002
+#define NV_PPWR_MMIO_ADDR                                                0x07a0
+#define NV_PPWR_MMIO_DATA                                                0x07a4
+#define NV_PPWR_MMIO_CTRL                                                0x07ac
+#define NV_PPWR_MMIO_CTRL_TRIGGER                                    0x00010000
+#define NV_PPWR_MMIO_CTRL_STATUS                                     0x00007000
+#define NV_PPWR_MMIO_CTRL_STATUS_IDLE                                0x00000000
+#define NV_PPWR_MMIO_CTRL_MASK                                       0x000000f0
+#define NV_PPWR_MMIO_CTRL_MASK_B32_0                                 0x000000f0
+#define NV_PPWR_MMIO_CTRL_OP                                         0x00000003
+#define NV_PPWR_MMIO_CTRL_OP_RD                                      0x00000001
+#define NV_PPWR_MMIO_CTRL_OP_WR                                      0x00000002
+#define NV_PPWR_OUTPUT                                                   0x07c0
+#define NV_PPWR_OUTPUT_FB_PAUSE                                      0x00000004
+#define NV_PPWR_OUTPUT_SET                                               0x07e0
+#define NV_PPWR_OUTPUT_SET_FB_PAUSE                                  0x00000004
+#define NV_PPWR_OUTPUT_CLR                                               0x07e4
+#define NV_PPWR_OUTPUT_CLR_FB_PAUSE                                  0x00000004
+
+// Inter-process message format
+.equ #msg_process 0x00 /* send() target, recv() sender */
+.equ #msg_message 0x04
+.equ #msg_data0   0x08
+.equ #msg_data1   0x0c
+
+// Kernel message IDs
+#define KMSG_FIFO  0x00000000
+#define KMSG_ALARM 0x00000001
+
+// Process message queue description
+.equ #proc_qlen 4 // log2(size of queue entry in bytes)
+.equ #proc_qnum 2 // log2(max number of entries in queue)
+.equ #proc_qmaskb (1 << #proc_qnum) // max number of entries in queue
+.equ #proc_qmaskp (#proc_qmaskb - 1)
+.equ #proc_qmaskf ((#proc_qmaskb << 1) - 1)
+.equ #proc_qsize  (1 << (#proc_qlen + #proc_qnum))
+
+// Process table entry
+.equ #proc_id    0x00
+.equ #proc_init  0x04
+.equ #proc_recv  0x08
+.equ #proc_time  0x0c
+.equ #proc_qput  0x10
+.equ #proc_qget  0x14
+.equ #proc_queue 0x18
+.equ #proc_size (0x18 + #proc_qsize)
+
+#define process(id,init,recv) /*
+*/     .b32 id /*
+*/     .b32 init /*
+*/     .b32 recv /*
+*/     .b32 0 /*
+*/     .b32 0 /*
+*/     .b32 0 /*
+*/     .skip 64
+
+#ifndef NVKM_FALCON_UNSHIFTED_IO
+#define nv_iord(reg,ior) /*
+*/     mov reg ior /*
+*/     shl b32 reg 6 /*
+*/     iord reg I[reg + 0x000]
+#else
+#define nv_iord(reg,ior) /*
+*/     mov reg ior /*
+*/     iord reg I[reg + 0x000]
+#endif
+
+#ifndef NVKM_FALCON_UNSHIFTED_IO
+#define nv_iowr(ior,reg) /*
+*/     mov $r0 ior /*
+*/     shl b32 $r0 6 /*
+*/     iowr I[$r0 + 0x000] reg /*
+*/     clear b32 $r0
+#else
+#define nv_iowr(ior,reg) /*
+*/     mov $r0 ior /*
+*/     iowr I[$r0 + 0x000] reg /*
+*/     clear b32 $r0
+#endif
+
+#ifndef NVKM_FALCON_UNSHIFTED_IO
+#define nv_iowrs(ior,reg) /*
+*/     mov $r0 ior /*
+*/     shl b32 $r0 6 /*
+*/     iowrs I[$r0 + 0x000] reg /*
+*/     clear b32 $r0
+#else
+#define nv_iowrs(ior,reg) /*
+*/     mov $r0 ior /*
+*/     iowrs I[$r0 + 0x000] reg /*
+*/     clear b32 $r0
+#endif
+
+#define hash #
+#define fn(a) a
+#ifndef NVKM_FALCON_PC24
+#define call(a) call fn(hash)a
+#else
+#define call(a) lcall fn(hash)a
+#endif
+
+#ifndef NVKM_FALCON_MMIO_UAS
+#define nv_rd32(reg,addr) /*
+*/     mov b32 $r14 addr /*
+*/     call(rd32) /*
+*/     mov b32 reg $r13
+#else
+#define nv_rd32(reg,addr) /*
+*/     sethi $r0 0x14000000 /*
+*/     or $r0 addr /*
+*/     ld b32 reg D[$r0] /*
+*/     clear b32 $r0
+#endif
+
+#if !defined(NVKM_FALCON_MMIO_UAS) || defined(NVKM_FALCON_MMIO_TRAP)
+#define nv_wr32(addr,reg) /*
+*/     push addr /*
+*/     push reg /*
+*/     pop $r13 /*
+*/     pop $r14 /*
+*/     call(wr32) /*
+#else
+#define nv_wr32(addr,reg) /*
+*/     sethi $r0 0x14000000 /*
+*/     or $r0 addr /*
+*/     st b32 D[$r0] reg /*
+*/     clear b32 $r0
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc
new file mode 100644 (file)
index 0000000..d43741e
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_PROC
+process(PROC_MEMX, #memx_init, #memx_recv)
+#endif
+
+/******************************************************************************
+ * MEMX data segment
+ *****************************************************************************/
+#ifdef INCLUDE_DATA
+.equ #memx_opcode 0
+.equ #memx_header 2
+.equ #memx_length 4
+.equ #memx_func   8
+
+#define handler(cmd,hdr,len,func) /*
+*/     .b16 MEMX_##cmd /*
+*/     .b16 hdr /*
+*/     .b16 len /*
+*/      .b16 0 /*
+*/     .b32 func
+
+memx_func_head:
+handler(ENTER , 0x0001, 0x0000, #memx_func_enter)
+memx_func_next:
+handler(LEAVE , 0x0000, 0x0000, #memx_func_leave)
+handler(WR32  , 0x0000, 0x0002, #memx_func_wr32)
+handler(WAIT  , 0x0004, 0x0000, #memx_func_wait)
+handler(DELAY , 0x0001, 0x0000, #memx_func_delay)
+memx_func_tail:
+
+.equ #memx_func_size #memx_func_next - #memx_func_head
+.equ #memx_func_num (#memx_func_tail - #memx_func_head) / #memx_func_size
+
+memx_data_head:
+.skip 0x0800
+memx_data_tail:
+#endif
+
+/******************************************************************************
+ * MEMX code segment
+ *****************************************************************************/
+#ifdef INCLUDE_CODE
+// description
+//
+// $r15 - current (memx)
+// $r4  - packet length
+//     +00: bitmask of heads to wait for vblank on
+// $r3  - opcode desciption
+// $r0  - zero
+memx_func_enter:
+       mov $r6 NV_PPWR_OUTPUT_SET_FB_PAUSE
+       nv_iowr(NV_PPWR_OUTPUT_SET, $r6)
+       memx_func_enter_wait:
+               nv_iord($r6, NV_PPWR_OUTPUT)
+               and $r6 NV_PPWR_OUTPUT_FB_PAUSE
+               bra z #memx_func_enter_wait
+       //XXX: TODO
+       ld b32 $r6 D[$r1 + 0x00]
+       add b32 $r1 0x04
+       ret
+
+// description
+//
+// $r15 - current (memx)
+// $r4  - packet length
+// $r3  - opcode desciption
+// $r0  - zero
+memx_func_leave:
+       mov $r6 NV_PPWR_OUTPUT_CLR_FB_PAUSE
+       nv_iowr(NV_PPWR_OUTPUT_CLR, $r6)
+       memx_func_leave_wait:
+               nv_iord($r6, NV_PPWR_OUTPUT)
+               and $r6 NV_PPWR_OUTPUT_FB_PAUSE
+               bra nz #memx_func_leave_wait
+       ret
+
+// description
+//
+// $r15 - current (memx)
+// $r4  - packet length
+//     +00*n: addr
+//     +04*n: data
+// $r3  - opcode desciption
+// $r0  - zero
+memx_func_wr32:
+       ld b32 $r6 D[$r1 + 0x00]
+       ld b32 $r5 D[$r1 + 0x04]
+       add b32 $r1 0x08
+       nv_wr32($r6, $r5)
+       sub b32 $r4 0x02
+       bra nz #memx_func_wr32
+       ret
+
+// description
+//
+// $r15 - current (memx)
+// $r4  - packet length
+//     +00: addr
+//     +04: mask
+//     +08: data
+//     +0c: timeout (ns)
+// $r3  - opcode desciption
+// $r0  - zero
+memx_func_wait:
+       nv_iord($r8, NV_PPWR_TIMER_LOW)
+       ld b32 $r14 D[$r1 + 0x00]
+       ld b32 $r13 D[$r1 + 0x04]
+       ld b32 $r12 D[$r1 + 0x08]
+       ld b32 $r11 D[$r1 + 0x0c]
+       add b32 $r1 0x10
+       call(wait)
+       ret
+
+// description
+//
+// $r15 - current (memx)
+// $r4  - packet length
+//     +00: time (ns)
+// $r3  - opcode desciption
+// $r0  - zero
+memx_func_delay:
+       ld b32 $r14 D[$r1 + 0x00]
+       add b32 $r1 0x04
+       call(nsec)
+       ret
+
+// description
+//
+// $r15 - current (memx)
+// $r14 - sender process name
+// $r13 - message (exec)
+// $r12 - head of script
+// $r11 - tail of script
+// $r0  - zero
+memx_exec:
+       push $r14
+       push $r13
+       mov b32 $r1 $r12
+       mov b32 $r2 $r11
+       memx_exec_next:
+               // fetch the packet header, and locate opcode info
+               ld b32 $r3 D[$r1]
+               add b32 $r1 4
+               shr b32 $r4 $r3 16
+               mulu $r3 #memx_func_size
+
+               // execute the opcode handler
+               ld b32 $r5 D[$r3 + #memx_func_head + #memx_func]
+               call $r5
+
+               // keep going, if we haven't reached the end
+               cmp b32 $r1 $r2
+               bra l #memx_exec_next
+
+       // send completion reply
+       pop $r13
+       pop $r14
+       call(send)
+       ret
+
+// description
+//
+// $r15 - current (memx)
+// $r14 - sender process name
+// $r13 - message
+// $r12 - data0
+// $r11 - data1
+// $r0  - zero
+memx_info:
+       mov $r12 #memx_data_head
+       mov $r11 #memx_data_tail - #memx_data_head
+       call(send)
+       ret
+
+// description
+//
+// $r15 - current (memx)
+// $r14 - sender process name
+// $r13 - message
+// $r12 - data0
+// $r11 - data1
+// $r0  - zero
+memx_recv:
+       cmp b32 $r13 MEMX_MSG_EXEC
+       bra e #memx_exec
+       cmp b32 $r13 MEMX_MSG_INFO
+       bra e #memx_info
+       ret
+
+// description
+//
+// $r15 - current (memx)
+// $r0  - zero
+memx_init:
+       ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc
new file mode 100644 (file)
index 0000000..947be53
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GK208
+
+#define NVKM_FALCON_PC24
+#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #nv108_pwr_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #nv108_pwr_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h
new file mode 100644 (file)
index 0000000..9342e2d
--- /dev/null
@@ -0,0 +1,1165 @@
+uint32_t nv108_pwr_data[] = {
+/* 0x0000: proc_kern */
+       0x52544e49,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0058: proc_list_head */
+       0x54534f48,
+       0x00000379,
+       0x0000032a,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x584d454d,
+       0x0000046f,
+       0x00000461,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x46524550,
+       0x00000473,
+       0x00000471,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x54534554,
+       0x00000494,
+       0x00000475,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x454c4449,
+       0x0000049f,
+       0x0000049d,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0210: proc_list_tail */
+/* 0x0210: time_prev */
+       0x00000000,
+/* 0x0214: time_next */
+       0x00000000,
+/* 0x0218: fifo_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0298: rfifo_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0318: memx_func_head */
+       0x00010000,
+       0x00000000,
+       0x000003a9,
+/* 0x0324: memx_func_next */
+       0x00000001,
+       0x00000000,
+       0x000003c7,
+       0x00000002,
+       0x00000002,
+       0x000003df,
+       0x00040003,
+       0x00000000,
+       0x00000407,
+       0x00010004,
+       0x00000000,
+       0x00000421,
+/* 0x0354: memx_func_tail */
+/* 0x0354: memx_data_head */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0b54: memx_data_tail */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
+
+uint32_t nv108_pwr_code[] = {
+       0x02910ef5,
+/* 0x0004: rd32 */
+       0xf607a040,
+       0x04bd000e,
+       0xe3f0010e,
+       0x07ac4001,
+       0xbd000ef6,
+/* 0x0019: rd32_wait */
+       0x07ac4e04,
+       0xf100eecf,
+       0xf47000e4,
+       0xa44df61b,
+       0x00ddcf07,
+/* 0x002e: wr32 */
+       0xa04000f8,
+       0x000ef607,
+       0xa44004bd,
+       0x000df607,
+       0x020e04bd,
+       0xf0f0e5f0,
+       0xac4001e3,
+       0x000ef607,
+/* 0x004e: wr32_wait */
+       0xac4e04bd,
+       0x00eecf07,
+       0x7000e4f1,
+       0xf8f61bf4,
+/* 0x005d: nsec */
+       0xcf2c0800,
+/* 0x0062: nsec_loop */
+       0x2c090088,
+       0xbb0099cf,
+       0x9ea60298,
+       0xf8f61ef4,
+/* 0x0071: wait */
+       0xcf2c0800,
+/* 0x0076: wait_loop */
+       0xeeb20088,
+       0x0000047e,
+       0xadfddab2,
+       0xf4aca604,
+       0x2c09100b,
+       0xbb0099cf,
+       0x9ba60298,
+/* 0x0093: wait_done */
+       0xf8e61ef4,
+/* 0x0095: intr_watchdog */
+       0x03e99800,
+       0xf40096b0,
+       0x0a98280b,
+       0x029abb84,
+       0x0d0e1cf4,
+       0x01de7e01,
+       0xf494bd00,
+/* 0x00b2: intr_watchdog_next_time */
+       0x0a98140e,
+       0x00a6b085,
+       0xa6080bf4,
+       0x061cf49a,
+/* 0x00c0: intr_watchdog_next_time_set */
+/* 0x00c3: intr_watchdog_next_proc */
+       0xb58509b5,
+       0xe0b603e9,
+       0x10e6b158,
+       0xc81bf402,
+/* 0x00d2: intr */
+       0x00f900f8,
+       0x80f904bd,
+       0xa0f990f9,
+       0xc0f9b0f9,
+       0xe0f9d0f9,
+       0x000ff0f9,
+       0xf90188fe,
+       0x04504880,
+       0xb60088cf,
+       0x50400180,
+       0x0008f604,
+       0x080804bd,
+       0xc40088cf,
+       0x0bf40289,
+       0x8500b51f,
+       0x957e580e,
+       0x09980000,
+       0x0096b085,
+       0x000d0bf4,
+       0x0009f634,
+       0x09b504bd,
+/* 0x0125: intr_skip_watchdog */
+       0x0089e484,
+       0x360bf408,
+       0xcf068849,
+       0x9ac40099,
+       0x220bf402,
+       0xcf04c04c,
+       0xc0f900cc,
+       0xf14f484e,
+       0x0d5453e3,
+       0x023f7e00,
+       0x40c0fc00,
+       0x0cf604c0,
+/* 0x0157: intr_subintr_skip_fifo */
+       0x4004bd00,
+       0x09f60688,
+/* 0x015f: intr_skip_subintr */
+       0xc404bd00,
+       0x0bf42089,
+       0xbfa4f107,
+/* 0x0169: intr_skip_pause */
+       0x4089c4ff,
+       0xf1070bf4,
+/* 0x0173: intr_skip_user0 */
+       0x00ffbfa4,
+       0x0008f604,
+       0x80fc04bd,
+       0xfc0088fe,
+       0xfce0fcf0,
+       0xfcc0fcd0,
+       0xfca0fcb0,
+       0xfc80fc90,
+       0x0032f400,
+/* 0x0196: timer */
+       0x32f401f8,
+       0x03f89810,
+       0xf40086b0,
+       0xfeb53a1c,
+       0xf6380003,
+       0x04bd0008,
+       0x88cf0808,
+       0x0284f000,
+       0x081c1bf4,
+       0x0088cf34,
+       0x0bf4e0a6,
+       0xf4e8a608,
+/* 0x01c6: timer_reset */
+       0x3400161e,
+       0xbd000ef6,
+       0x840eb504,
+/* 0x01d0: timer_enable */
+       0x38000108,
+       0xbd0008f6,
+/* 0x01d9: timer_done */
+       0x1031f404,
+/* 0x01de: send_proc */
+       0x80f900f8,
+       0xe89890f9,
+       0x04e99805,
+       0xa60486f0,
+       0x2a0bf489,
+       0x940398c4,
+       0x80b60488,
+       0x008ebb18,
+       0xb500fa98,
+       0x8db5008a,
+       0x028cb501,
+       0xb6038bb5,
+       0x94f00190,
+       0x04e9b507,
+/* 0x0217: send_done */
+       0xfc0231f4,
+       0xf880fc90,
+/* 0x021d: find */
+       0x0880f900,
+       0x0131f458,
+/* 0x0224: find_loop */
+       0xa6008a98,
+       0x100bf4ae,
+       0xb15880b6,
+       0xf4021086,
+       0x32f4f11b,
+/* 0x0239: find_done */
+       0xfc8eb201,
+/* 0x023f: send */
+       0x7e00f880,
+       0xf400021d,
+       0x00f89b01,
+/* 0x0248: recv */
+       0x9805e898,
+       0x32f404e9,
+       0xf489a601,
+       0x89c43c0b,
+       0x0180b603,
+       0xb50784f0,
+       0xea9805e8,
+       0xfef0f902,
+       0xf0f9018f,
+       0x9994efb2,
+       0x00e9bb04,
+       0x9818e0b6,
+       0xec9803eb,
+       0x01ed9802,
+       0xf900ee98,
+       0xfef0fca5,
+       0x31f400f8,
+/* 0x028f: recv_done */
+       0xf8f0fc01,
+/* 0x0291: init */
+       0x01084100,
+       0xe70011cf,
+       0xb6010911,
+       0x14fe0814,
+       0x00e04100,
+       0x000013f0,
+       0x0001f61c,
+       0xff0104bd,
+       0x01f61400,
+       0x0104bd00,
+       0x0015f102,
+       0xf6100008,
+       0x04bd0001,
+       0xf000d241,
+       0x10fe0013,
+       0x1031f400,
+       0x38000101,
+       0xbd0001f6,
+/* 0x02db: init_proc */
+       0x98580f04,
+       0x16b001f1,
+       0xfa0bf400,
+       0xf0b615f9,
+       0xf20ef458,
+/* 0x02ec: host_send */
+       0xcf04b041,
+       0xa0420011,
+       0x0022cf04,
+       0x0bf412a6,
+       0x071ec42e,
+       0xb704ee94,
+       0x980218e0,
+       0xec9803eb,
+       0x01ed9802,
+       0x7e00ee98,
+       0xb600023f,
+       0x1ec40110,
+       0x04b0400f,
+       0xbd0001f6,
+       0xc70ef404,
+/* 0x0328: host_send_done */
+/* 0x032a: host_recv */
+       0x494100f8,
+       0x5413f14e,
+       0xf4e1a652,
+/* 0x0336: host_recv_wait */
+       0xcc41b90b,
+       0x0011cf04,
+       0xcf04c842,
+       0x16f00022,
+       0xf412a608,
+       0x23c4ef0b,
+       0x0434b607,
+       0x029830b7,
+       0xb5033bb5,
+       0x3db5023c,
+       0x003eb501,
+       0xf00120b6,
+       0xc8400f24,
+       0x0002f604,
+       0x400204bd,
+       0x02f60000,
+       0xf804bd00,
+/* 0x0379: host_init */
+       0x00804100,
+       0xf11014b6,
+       0x40021815,
+       0x01f604d0,
+       0x4104bd00,
+       0x14b60080,
+       0x9815f110,
+       0x04dc4002,
+       0xbd0001f6,
+       0x40010104,
+       0x01f604c4,
+       0xf804bd00,
+/* 0x03a9: memx_func_enter */
+       0x40040600,
+       0x06f607e0,
+/* 0x03b3: memx_func_enter_wait */
+       0x4604bd00,
+       0x66cf07c0,
+       0x0464f000,
+       0x98f70bf4,
+       0x10b60016,
+/* 0x03c7: memx_func_leave */
+       0x0600f804,
+       0x07e44004,
+       0xbd0006f6,
+/* 0x03d1: memx_func_leave_wait */
+       0x07c04604,
+       0xf00066cf,
+       0x1bf40464,
+/* 0x03df: memx_func_wr32 */
+       0x9800f8f7,
+       0x15980016,
+       0x0810b601,
+       0x50f960f9,
+       0xe0fcd0fc,
+       0x00002e7e,
+       0x140003f1,
+       0xa00506fd,
+       0xb604bd05,
+       0x1bf40242,
+/* 0x0407: memx_func_wait */
+       0x0800f8dd,
+       0x0088cf2c,
+       0x98001e98,
+       0x1c98011d,
+       0x031b9802,
+       0x7e1010b6,
+       0xf8000071,
+/* 0x0421: memx_func_delay */
+       0x001e9800,
+       0x7e0410b6,
+       0xf800005d,
+/* 0x042d: memx_exec */
+       0xf9e0f900,
+       0xb2c1b2d0,
+/* 0x0435: memx_exec_next */
+       0x001398b2,
+       0x950410b6,
+       0x30f01034,
+       0xc835980c,
+       0x12a655f9,
+       0xfced1ef4,
+       0x7ee0fcd0,
+       0xf800023f,
+/* 0x0455: memx_info */
+       0x03544c00,
+       0x7e08004b,
+       0xf800023f,
+/* 0x0461: memx_recv */
+       0x01d6b000,
+       0xb0c90bf4,
+       0x0bf400d6,
+/* 0x046f: memx_init */
+       0xf800f8eb,
+/* 0x0471: perf_recv */
+/* 0x0473: perf_init */
+       0xf800f800,
+/* 0x0475: test_recv */
+       0x04584100,
+       0xb60011cf,
+       0x58400110,
+       0x0001f604,
+       0xe7f104bd,
+       0xe3f1d900,
+       0x967e134f,
+       0x00f80001,
+/* 0x0494: test_init */
+       0x7e08004e,
+       0xf8000196,
+/* 0x049d: idle_recv */
+/* 0x049f: idle */
+       0xf400f800,
+       0x54410031,
+       0x0011cf04,
+       0x400110b6,
+       0x01f60454,
+/* 0x04b3: idle_loop */
+       0x0104bd00,
+       0x0232f458,
+/* 0x04b8: idle_proc */
+/* 0x04b8: idle_proc_exec */
+       0x1eb210f9,
+       0x0002487e,
+       0x11f410fc,
+       0x0231f409,
+/* 0x04cb: idle_proc_next */
+       0xb6f00ef4,
+       0x1fa65810,
+       0xf4e81bf4,
+       0x28f4e002,
+       0xc60ef400,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc
new file mode 100644 (file)
index 0000000..6fde0b8
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GT215
+
+//#define NVKM_FALCON_PC24
+//#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #nva3_pwr_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #nva3_pwr_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h
new file mode 100644 (file)
index 0000000..0fa4d7d
--- /dev/null
@@ -0,0 +1,1229 @@
+uint32_t nva3_pwr_data[] = {
+/* 0x0000: proc_kern */
+       0x52544e49,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0058: proc_list_head */
+       0x54534f48,
+       0x00000430,
+       0x000003cd,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x584d454d,
+       0x0000054e,
+       0x00000540,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x46524550,
+       0x00000552,
+       0x00000550,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x54534554,
+       0x0000057b,
+       0x00000554,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x454c4449,
+       0x00000587,
+       0x00000585,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0210: proc_list_tail */
+/* 0x0210: time_prev */
+       0x00000000,
+/* 0x0214: time_next */
+       0x00000000,
+/* 0x0218: fifo_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0298: rfifo_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0318: memx_func_head */
+       0x00010000,
+       0x00000000,
+       0x0000046f,
+/* 0x0324: memx_func_next */
+       0x00000001,
+       0x00000000,
+       0x00000496,
+       0x00000002,
+       0x00000002,
+       0x000004b7,
+       0x00040003,
+       0x00000000,
+       0x000004df,
+       0x00010004,
+       0x00000000,
+       0x000004fc,
+/* 0x0354: memx_func_tail */
+/* 0x0354: memx_data_head */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0b54: memx_data_tail */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
+
+uint32_t nva3_pwr_code[] = {
+       0x030d0ef5,
+/* 0x0004: rd32 */
+       0x07a007f1,
+       0xd00604b6,
+       0x04bd000e,
+       0xf001e7f0,
+       0x07f101e3,
+       0x04b607ac,
+       0x000ed006,
+/* 0x0022: rd32_wait */
+       0xe7f104bd,
+       0xe4b607ac,
+       0x00eecf06,
+       0x7000e4f1,
+       0xf1f21bf4,
+       0xb607a4d7,
+       0xddcf06d4,
+/* 0x003f: wr32 */
+       0xf100f800,
+       0xb607a007,
+       0x0ed00604,
+       0xf104bd00,
+       0xb607a407,
+       0x0dd00604,
+       0xf004bd00,
+       0xe5f002e7,
+       0x01e3f0f0,
+       0x07ac07f1,
+       0xd00604b6,
+       0x04bd000e,
+/* 0x006c: wr32_wait */
+       0x07ace7f1,
+       0xcf06e4b6,
+       0xe4f100ee,
+       0x1bf47000,
+/* 0x007f: nsec */
+       0xf000f8f2,
+       0x84b62c87,
+       0x0088cf06,
+/* 0x0088: nsec_loop */
+       0xb62c97f0,
+       0x99cf0694,
+       0x0298bb00,
+       0xf4069eb8,
+       0x00f8f11e,
+/* 0x009c: wait */
+       0xb62c87f0,
+       0x88cf0684,
+/* 0x00a5: wait_loop */
+       0x02eeb900,
+       0xb90421f4,
+       0xadfd02da,
+       0x06acb804,
+       0xf0150bf4,
+       0x94b62c97,
+       0x0099cf06,
+       0xb80298bb,
+       0x1ef4069b,
+/* 0x00c9: wait_done */
+/* 0x00cb: intr_watchdog */
+       0x9800f8df,
+       0x96b003e9,
+       0x2a0bf400,
+       0xbb840a98,
+       0x1cf4029a,
+       0x01d7f00f,
+       0x025421f5,
+       0x0ef494bd,
+/* 0x00e9: intr_watchdog_next_time */
+       0x850a9815,
+       0xf400a6b0,
+       0x9ab8090b,
+       0x061cf406,
+/* 0x00f8: intr_watchdog_next_time_set */
+/* 0x00fb: intr_watchdog_next_proc */
+       0x80850980,
+       0xe0b603e9,
+       0x10e6b158,
+       0xc61bf402,
+/* 0x010a: intr */
+       0x00f900f8,
+       0x80f904bd,
+       0xa0f990f9,
+       0xc0f9b0f9,
+       0xe0f9d0f9,
+       0xf7f0f0f9,
+       0x0188fe00,
+       0x87f180f9,
+       0x84b605d0,
+       0x0088cf06,
+       0xf10180b6,
+       0xb605d007,
+       0x08d00604,
+       0xf004bd00,
+       0x84b60887,
+       0x0088cf06,
+       0xf40289c4,
+       0x0080230b,
+       0x58e7f085,
+       0x98cb21f4,
+       0x96b08509,
+       0x110bf400,
+       0xb63407f0,
+       0x09d00604,
+       0x8004bd00,
+/* 0x016e: intr_skip_watchdog */
+       0x89e48409,
+       0x0bf40800,
+       0x8897f148,
+       0x0694b606,
+       0xc40099cf,
+       0x0bf4029a,
+       0xc0c7f12c,
+       0x06c4b604,
+       0xf900cccf,
+       0x48e7f1c0,
+       0x53e3f14f,
+       0x00d7f054,
+       0x02b921f5,
+       0x07f1c0fc,
+       0x04b604c0,
+       0x000cd006,
+/* 0x01ae: intr_subintr_skip_fifo */
+       0x07f104bd,
+       0x04b60688,
+       0x0009d006,
+/* 0x01ba: intr_skip_subintr */
+       0x89c404bd,
+       0x070bf420,
+       0xffbfa4f1,
+/* 0x01c4: intr_skip_pause */
+       0xf44089c4,
+       0xa4f1070b,
+/* 0x01ce: intr_skip_user0 */
+       0x07f0ffbf,
+       0x0604b604,
+       0xbd0008d0,
+       0xfe80fc04,
+       0xf0fc0088,
+       0xd0fce0fc,
+       0xb0fcc0fc,
+       0x90fca0fc,
+       0x00fc80fc,
+       0xf80032f4,
+/* 0x01f5: timer */
+       0x1032f401,
+       0xb003f898,
+       0x1cf40086,
+       0x03fe8051,
+       0xb63807f0,
+       0x08d00604,
+       0xf004bd00,
+       0x84b60887,
+       0x0088cf06,
+       0xf40284f0,
+       0x87f0261b,
+       0x0684b634,
+       0xb80088cf,
+       0x0bf406e0,
+       0x06e8b809,
+/* 0x0233: timer_reset */
+       0xf01f1ef4,
+       0x04b63407,
+       0x000ed006,
+       0x0e8004bd,
+/* 0x0241: timer_enable */
+       0x0187f084,
+       0xb63807f0,
+       0x08d00604,
+/* 0x024f: timer_done */
+       0xf404bd00,
+       0x00f81031,
+/* 0x0254: send_proc */
+       0x90f980f9,
+       0x9805e898,
+       0x86f004e9,
+       0x0689b804,
+       0xc42a0bf4,
+       0x88940398,
+       0x1880b604,
+       0x98008ebb,
+       0x8a8000fa,
+       0x018d8000,
+       0x80028c80,
+       0x90b6038b,
+       0x0794f001,
+       0xf404e980,
+/* 0x028e: send_done */
+       0x90fc0231,
+       0x00f880fc,
+/* 0x0294: find */
+       0x87f080f9,
+       0x0131f458,
+/* 0x029c: find_loop */
+       0xb8008a98,
+       0x0bf406ae,
+       0x5880b610,
+       0x021086b1,
+       0xf4f01bf4,
+/* 0x02b2: find_done */
+       0x8eb90132,
+       0xf880fc02,
+/* 0x02b9: send */
+       0x9421f500,
+       0x9701f402,
+/* 0x02c2: recv */
+       0xe89800f8,
+       0x04e99805,
+       0xb80132f4,
+       0x0bf40689,
+       0x0389c43d,
+       0xf00180b6,
+       0xe8800784,
+       0x02ea9805,
+       0x8ffef0f9,
+       0xb9f0f901,
+       0x999402ef,
+       0x00e9bb04,
+       0x9818e0b6,
+       0xec9803eb,
+       0x01ed9802,
+       0xf900ee98,
+       0xfef0fca5,
+       0x31f400f8,
+/* 0x030b: recv_done */
+       0xf8f0fc01,
+/* 0x030d: init */
+       0x0817f100,
+       0x0614b601,
+       0xe70011cf,
+       0xb6010911,
+       0x14fe0814,
+       0xe017f100,
+       0x0013f000,
+       0xb61c07f0,
+       0x01d00604,
+       0xf004bd00,
+       0x07f0ff17,
+       0x0604b614,
+       0xbd0001d0,
+       0x0217f004,
+       0x080015f1,
+       0xb61007f0,
+       0x01d00604,
+       0xf104bd00,
+       0xf0010a17,
+       0x10fe0013,
+       0x1031f400,
+       0xf00117f0,
+       0x04b63807,
+       0x0001d006,
+       0xf7f004bd,
+/* 0x0371: init_proc */
+       0x01f19858,
+       0xf40016b0,
+       0x15f9fa0b,
+       0xf458f0b6,
+/* 0x0382: host_send */
+       0x17f1f20e,
+       0x14b604b0,
+       0x0011cf06,
+       0x04a027f1,
+       0xcf0624b6,
+       0x12b80022,
+       0x320bf406,
+       0x94071ec4,
+       0xe0b704ee,
+       0xeb980218,
+       0x02ec9803,
+       0x9801ed98,
+       0x21f500ee,
+       0x10b602b9,
+       0x0f1ec401,
+       0x04b007f1,
+       0xd00604b6,
+       0x04bd0001,
+/* 0x03cb: host_send_done */
+       0xf8ba0ef4,
+/* 0x03cd: host_recv */
+       0x4917f100,
+       0x5413f14e,
+       0x06e1b852,
+/* 0x03db: host_recv_wait */
+       0xf1aa0bf4,
+       0xb604cc17,
+       0x11cf0614,
+       0xc827f100,
+       0x0624b604,
+       0xf00022cf,
+       0x12b80816,
+       0xe60bf406,
+       0xb60723c4,
+       0x30b70434,
+       0x3b800298,
+       0x023c8003,
+       0x80013d80,
+       0x20b6003e,
+       0x0f24f001,
+       0x04c807f1,
+       0xd00604b6,
+       0x04bd0002,
+       0xf04027f0,
+       0x04b60007,
+       0x0002d006,
+       0x00f804bd,
+/* 0x0430: host_init */
+       0x008017f1,
+       0xf11014b6,
+       0xf1021815,
+       0xb604d007,
+       0x01d00604,
+       0xf104bd00,
+       0xb6008017,
+       0x15f11014,
+       0x07f10298,
+       0x04b604dc,
+       0x0001d006,
+       0x17f004bd,
+       0xc407f101,
+       0x0604b604,
+       0xbd0001d0,
+/* 0x046f: memx_func_enter */
+       0xf000f804,
+       0x07f10467,
+       0x04b607e0,
+       0x0006d006,
+/* 0x047e: memx_func_enter_wait */
+       0x67f104bd,
+       0x64b607c0,
+       0x0066cf06,
+       0xf40464f0,
+       0x1698f30b,
+       0x0410b600,
+/* 0x0496: memx_func_leave */
+       0x67f000f8,
+       0xe407f104,
+       0x0604b607,
+       0xbd0006d0,
+/* 0x04a5: memx_func_leave_wait */
+       0xc067f104,
+       0x0664b607,
+       0xf00066cf,
+       0x1bf40464,
+/* 0x04b7: memx_func_wr32 */
+       0x9800f8f3,
+       0x15980016,
+       0x0810b601,
+       0x50f960f9,
+       0xe0fcd0fc,
+       0xf13f21f4,
+       0xfd140003,
+       0x05800506,
+       0xb604bd00,
+       0x1bf40242,
+/* 0x04df: memx_func_wait */
+       0xf000f8dd,
+       0x84b62c87,
+       0x0088cf06,
+       0x98001e98,
+       0x1c98011d,
+       0x031b9802,
+       0xf41010b6,
+       0x00f89c21,
+/* 0x04fc: memx_func_delay */
+       0xb6001e98,
+       0x21f40410,
+/* 0x0507: memx_exec */
+       0xf900f87f,
+       0xb9d0f9e0,
+       0xb2b902c1,
+/* 0x0511: memx_exec_next */
+       0x00139802,
+       0x950410b6,
+       0x30f01034,
+       0xc835980c,
+       0x12b855f9,
+       0xec1ef406,
+       0xe0fcd0fc,
+       0x02b921f5,
+/* 0x0532: memx_info */
+       0xc7f100f8,
+       0xb7f10354,
+       0x21f50800,
+       0x00f802b9,
+/* 0x0540: memx_recv */
+       0xf401d6b0,
+       0xd6b0c40b,
+       0xe90bf400,
+/* 0x054e: memx_init */
+       0x00f800f8,
+/* 0x0550: perf_recv */
+/* 0x0552: perf_init */
+       0x00f800f8,
+/* 0x0554: test_recv */
+       0x05d817f1,
+       0xcf0614b6,
+       0x10b60011,
+       0xd807f101,
+       0x0604b605,
+       0xbd0001d0,
+       0x00e7f104,
+       0x4fe3f1d9,
+       0xf521f513,
+/* 0x057b: test_init */
+       0xf100f801,
+       0xf50800e7,
+       0xf801f521,
+/* 0x0585: idle_recv */
+/* 0x0587: idle */
+       0xf400f800,
+       0x17f10031,
+       0x14b605d4,
+       0x0011cf06,
+       0xf10110b6,
+       0xb605d407,
+       0x01d00604,
+/* 0x05a3: idle_loop */
+       0xf004bd00,
+       0x32f45817,
+/* 0x05a9: idle_proc */
+/* 0x05a9: idle_proc_exec */
+       0xb910f902,
+       0x21f5021e,
+       0x10fc02c2,
+       0xf40911f4,
+       0x0ef40231,
+/* 0x05bd: idle_proc_next */
+       0x5810b6ef,
+       0xf4061fb8,
+       0x02f4e61b,
+       0x0028f4dd,
+       0x00bb0ef4,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc
new file mode 100644 (file)
index 0000000..eaa64da
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GF100
+
+//#define NVKM_FALCON_PC24
+//#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #nvc0_pwr_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #nvc0_pwr_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h
new file mode 100644 (file)
index 0000000..82c8e8b
--- /dev/null
@@ -0,0 +1,1229 @@
+uint32_t nvc0_pwr_data[] = {
+/* 0x0000: proc_kern */
+       0x52544e49,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0058: proc_list_head */
+       0x54534f48,
+       0x00000430,
+       0x000003cd,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x584d454d,
+       0x0000054e,
+       0x00000540,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x46524550,
+       0x00000552,
+       0x00000550,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x54534554,
+       0x0000057b,
+       0x00000554,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x454c4449,
+       0x00000587,
+       0x00000585,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0210: proc_list_tail */
+/* 0x0210: time_prev */
+       0x00000000,
+/* 0x0214: time_next */
+       0x00000000,
+/* 0x0218: fifo_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0298: rfifo_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0318: memx_func_head */
+       0x00010000,
+       0x00000000,
+       0x0000046f,
+/* 0x0324: memx_func_next */
+       0x00000001,
+       0x00000000,
+       0x00000496,
+       0x00000002,
+       0x00000002,
+       0x000004b7,
+       0x00040003,
+       0x00000000,
+       0x000004df,
+       0x00010004,
+       0x00000000,
+       0x000004fc,
+/* 0x0354: memx_func_tail */
+/* 0x0354: memx_data_head */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0b54: memx_data_tail */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
+
+uint32_t nvc0_pwr_code[] = {
+       0x030d0ef5,
+/* 0x0004: rd32 */
+       0x07a007f1,
+       0xd00604b6,
+       0x04bd000e,
+       0xf001e7f0,
+       0x07f101e3,
+       0x04b607ac,
+       0x000ed006,
+/* 0x0022: rd32_wait */
+       0xe7f104bd,
+       0xe4b607ac,
+       0x00eecf06,
+       0x7000e4f1,
+       0xf1f21bf4,
+       0xb607a4d7,
+       0xddcf06d4,
+/* 0x003f: wr32 */
+       0xf100f800,
+       0xb607a007,
+       0x0ed00604,
+       0xf104bd00,
+       0xb607a407,
+       0x0dd00604,
+       0xf004bd00,
+       0xe5f002e7,
+       0x01e3f0f0,
+       0x07ac07f1,
+       0xd00604b6,
+       0x04bd000e,
+/* 0x006c: wr32_wait */
+       0x07ace7f1,
+       0xcf06e4b6,
+       0xe4f100ee,
+       0x1bf47000,
+/* 0x007f: nsec */
+       0xf000f8f2,
+       0x84b62c87,
+       0x0088cf06,
+/* 0x0088: nsec_loop */
+       0xb62c97f0,
+       0x99cf0694,
+       0x0298bb00,
+       0xf4069eb8,
+       0x00f8f11e,
+/* 0x009c: wait */
+       0xb62c87f0,
+       0x88cf0684,
+/* 0x00a5: wait_loop */
+       0x02eeb900,
+       0xb90421f4,
+       0xadfd02da,
+       0x06acb804,
+       0xf0150bf4,
+       0x94b62c97,
+       0x0099cf06,
+       0xb80298bb,
+       0x1ef4069b,
+/* 0x00c9: wait_done */
+/* 0x00cb: intr_watchdog */
+       0x9800f8df,
+       0x96b003e9,
+       0x2a0bf400,
+       0xbb840a98,
+       0x1cf4029a,
+       0x01d7f00f,
+       0x025421f5,
+       0x0ef494bd,
+/* 0x00e9: intr_watchdog_next_time */
+       0x850a9815,
+       0xf400a6b0,
+       0x9ab8090b,
+       0x061cf406,
+/* 0x00f8: intr_watchdog_next_time_set */
+/* 0x00fb: intr_watchdog_next_proc */
+       0x80850980,
+       0xe0b603e9,
+       0x10e6b158,
+       0xc61bf402,
+/* 0x010a: intr */
+       0x00f900f8,
+       0x80f904bd,
+       0xa0f990f9,
+       0xc0f9b0f9,
+       0xe0f9d0f9,
+       0xf7f0f0f9,
+       0x0188fe00,
+       0x87f180f9,
+       0x84b605d0,
+       0x0088cf06,
+       0xf10180b6,
+       0xb605d007,
+       0x08d00604,
+       0xf004bd00,
+       0x84b60887,
+       0x0088cf06,
+       0xf40289c4,
+       0x0080230b,
+       0x58e7f085,
+       0x98cb21f4,
+       0x96b08509,
+       0x110bf400,
+       0xb63407f0,
+       0x09d00604,
+       0x8004bd00,
+/* 0x016e: intr_skip_watchdog */
+       0x89e48409,
+       0x0bf40800,
+       0x8897f148,
+       0x0694b606,
+       0xc40099cf,
+       0x0bf4029a,
+       0xc0c7f12c,
+       0x06c4b604,
+       0xf900cccf,
+       0x48e7f1c0,
+       0x53e3f14f,
+       0x00d7f054,
+       0x02b921f5,
+       0x07f1c0fc,
+       0x04b604c0,
+       0x000cd006,
+/* 0x01ae: intr_subintr_skip_fifo */
+       0x07f104bd,
+       0x04b60688,
+       0x0009d006,
+/* 0x01ba: intr_skip_subintr */
+       0x89c404bd,
+       0x070bf420,
+       0xffbfa4f1,
+/* 0x01c4: intr_skip_pause */
+       0xf44089c4,
+       0xa4f1070b,
+/* 0x01ce: intr_skip_user0 */
+       0x07f0ffbf,
+       0x0604b604,
+       0xbd0008d0,
+       0xfe80fc04,
+       0xf0fc0088,
+       0xd0fce0fc,
+       0xb0fcc0fc,
+       0x90fca0fc,
+       0x00fc80fc,
+       0xf80032f4,
+/* 0x01f5: timer */
+       0x1032f401,
+       0xb003f898,
+       0x1cf40086,
+       0x03fe8051,
+       0xb63807f0,
+       0x08d00604,
+       0xf004bd00,
+       0x84b60887,
+       0x0088cf06,
+       0xf40284f0,
+       0x87f0261b,
+       0x0684b634,
+       0xb80088cf,
+       0x0bf406e0,
+       0x06e8b809,
+/* 0x0233: timer_reset */
+       0xf01f1ef4,
+       0x04b63407,
+       0x000ed006,
+       0x0e8004bd,
+/* 0x0241: timer_enable */
+       0x0187f084,
+       0xb63807f0,
+       0x08d00604,
+/* 0x024f: timer_done */
+       0xf404bd00,
+       0x00f81031,
+/* 0x0254: send_proc */
+       0x90f980f9,
+       0x9805e898,
+       0x86f004e9,
+       0x0689b804,
+       0xc42a0bf4,
+       0x88940398,
+       0x1880b604,
+       0x98008ebb,
+       0x8a8000fa,
+       0x018d8000,
+       0x80028c80,
+       0x90b6038b,
+       0x0794f001,
+       0xf404e980,
+/* 0x028e: send_done */
+       0x90fc0231,
+       0x00f880fc,
+/* 0x0294: find */
+       0x87f080f9,
+       0x0131f458,
+/* 0x029c: find_loop */
+       0xb8008a98,
+       0x0bf406ae,
+       0x5880b610,
+       0x021086b1,
+       0xf4f01bf4,
+/* 0x02b2: find_done */
+       0x8eb90132,
+       0xf880fc02,
+/* 0x02b9: send */
+       0x9421f500,
+       0x9701f402,
+/* 0x02c2: recv */
+       0xe89800f8,
+       0x04e99805,
+       0xb80132f4,
+       0x0bf40689,
+       0x0389c43d,
+       0xf00180b6,
+       0xe8800784,
+       0x02ea9805,
+       0x8ffef0f9,
+       0xb9f0f901,
+       0x999402ef,
+       0x00e9bb04,
+       0x9818e0b6,
+       0xec9803eb,
+       0x01ed9802,
+       0xf900ee98,
+       0xfef0fca5,
+       0x31f400f8,
+/* 0x030b: recv_done */
+       0xf8f0fc01,
+/* 0x030d: init */
+       0x0817f100,
+       0x0614b601,
+       0xe70011cf,
+       0xb6010911,
+       0x14fe0814,
+       0xe017f100,
+       0x0013f000,
+       0xb61c07f0,
+       0x01d00604,
+       0xf004bd00,
+       0x07f0ff17,
+       0x0604b614,
+       0xbd0001d0,
+       0x0217f004,
+       0x080015f1,
+       0xb61007f0,
+       0x01d00604,
+       0xf104bd00,
+       0xf0010a17,
+       0x10fe0013,
+       0x1031f400,
+       0xf00117f0,
+       0x04b63807,
+       0x0001d006,
+       0xf7f004bd,
+/* 0x0371: init_proc */
+       0x01f19858,
+       0xf40016b0,
+       0x15f9fa0b,
+       0xf458f0b6,
+/* 0x0382: host_send */
+       0x17f1f20e,
+       0x14b604b0,
+       0x0011cf06,
+       0x04a027f1,
+       0xcf0624b6,
+       0x12b80022,
+       0x320bf406,
+       0x94071ec4,
+       0xe0b704ee,
+       0xeb980218,
+       0x02ec9803,
+       0x9801ed98,
+       0x21f500ee,
+       0x10b602b9,
+       0x0f1ec401,
+       0x04b007f1,
+       0xd00604b6,
+       0x04bd0001,
+/* 0x03cb: host_send_done */
+       0xf8ba0ef4,
+/* 0x03cd: host_recv */
+       0x4917f100,
+       0x5413f14e,
+       0x06e1b852,
+/* 0x03db: host_recv_wait */
+       0xf1aa0bf4,
+       0xb604cc17,
+       0x11cf0614,
+       0xc827f100,
+       0x0624b604,
+       0xf00022cf,
+       0x12b80816,
+       0xe60bf406,
+       0xb60723c4,
+       0x30b70434,
+       0x3b800298,
+       0x023c8003,
+       0x80013d80,
+       0x20b6003e,
+       0x0f24f001,
+       0x04c807f1,
+       0xd00604b6,
+       0x04bd0002,
+       0xf04027f0,
+       0x04b60007,
+       0x0002d006,
+       0x00f804bd,
+/* 0x0430: host_init */
+       0x008017f1,
+       0xf11014b6,
+       0xf1021815,
+       0xb604d007,
+       0x01d00604,
+       0xf104bd00,
+       0xb6008017,
+       0x15f11014,
+       0x07f10298,
+       0x04b604dc,
+       0x0001d006,
+       0x17f004bd,
+       0xc407f101,
+       0x0604b604,
+       0xbd0001d0,
+/* 0x046f: memx_func_enter */
+       0xf000f804,
+       0x07f10467,
+       0x04b607e0,
+       0x0006d006,
+/* 0x047e: memx_func_enter_wait */
+       0x67f104bd,
+       0x64b607c0,
+       0x0066cf06,
+       0xf40464f0,
+       0x1698f30b,
+       0x0410b600,
+/* 0x0496: memx_func_leave */
+       0x67f000f8,
+       0xe407f104,
+       0x0604b607,
+       0xbd0006d0,
+/* 0x04a5: memx_func_leave_wait */
+       0xc067f104,
+       0x0664b607,
+       0xf00066cf,
+       0x1bf40464,
+/* 0x04b7: memx_func_wr32 */
+       0x9800f8f3,
+       0x15980016,
+       0x0810b601,
+       0x50f960f9,
+       0xe0fcd0fc,
+       0xf13f21f4,
+       0xfd140003,
+       0x05800506,
+       0xb604bd00,
+       0x1bf40242,
+/* 0x04df: memx_func_wait */
+       0xf000f8dd,
+       0x84b62c87,
+       0x0088cf06,
+       0x98001e98,
+       0x1c98011d,
+       0x031b9802,
+       0xf41010b6,
+       0x00f89c21,
+/* 0x04fc: memx_func_delay */
+       0xb6001e98,
+       0x21f40410,
+/* 0x0507: memx_exec */
+       0xf900f87f,
+       0xb9d0f9e0,
+       0xb2b902c1,
+/* 0x0511: memx_exec_next */
+       0x00139802,
+       0x950410b6,
+       0x30f01034,
+       0xc835980c,
+       0x12b855f9,
+       0xec1ef406,
+       0xe0fcd0fc,
+       0x02b921f5,
+/* 0x0532: memx_info */
+       0xc7f100f8,
+       0xb7f10354,
+       0x21f50800,
+       0x00f802b9,
+/* 0x0540: memx_recv */
+       0xf401d6b0,
+       0xd6b0c40b,
+       0xe90bf400,
+/* 0x054e: memx_init */
+       0x00f800f8,
+/* 0x0550: perf_recv */
+/* 0x0552: perf_init */
+       0x00f800f8,
+/* 0x0554: test_recv */
+       0x05d817f1,
+       0xcf0614b6,
+       0x10b60011,
+       0xd807f101,
+       0x0604b605,
+       0xbd0001d0,
+       0x00e7f104,
+       0x4fe3f1d9,
+       0xf521f513,
+/* 0x057b: test_init */
+       0xf100f801,
+       0xf50800e7,
+       0xf801f521,
+/* 0x0585: idle_recv */
+/* 0x0587: idle */
+       0xf400f800,
+       0x17f10031,
+       0x14b605d4,
+       0x0011cf06,
+       0xf10110b6,
+       0xb605d407,
+       0x01d00604,
+/* 0x05a3: idle_loop */
+       0xf004bd00,
+       0x32f45817,
+/* 0x05a9: idle_proc */
+/* 0x05a9: idle_proc_exec */
+       0xb910f902,
+       0x21f5021e,
+       0x10fc02c2,
+       0xf40911f4,
+       0x0ef40231,
+/* 0x05bd: idle_proc_next */
+       0x5810b6ef,
+       0xf4061fb8,
+       0x02f4e61b,
+       0x0028f4dd,
+       0x00bb0ef4,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc
new file mode 100644 (file)
index 0000000..32d65ea
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GF119
+
+//#define NVKM_FALCON_PC24
+#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #nvd0_pwr_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #nvd0_pwr_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h
new file mode 100644 (file)
index 0000000..ce65e2a
--- /dev/null
@@ -0,0 +1,1229 @@
+uint32_t nvd0_pwr_data[] = {
+/* 0x0000: proc_kern */
+       0x52544e49,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0058: proc_list_head */
+       0x54534f48,
+       0x000003be,
+       0x00000367,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x584d454d,
+       0x000004c4,
+       0x000004b6,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x46524550,
+       0x000004c8,
+       0x000004c6,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x54534554,
+       0x000004eb,
+       0x000004ca,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x454c4449,
+       0x000004f7,
+       0x000004f5,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0210: proc_list_tail */
+/* 0x0210: time_prev */
+       0x00000000,
+/* 0x0214: time_next */
+       0x00000000,
+/* 0x0218: fifo_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0298: rfifo_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0318: memx_func_head */
+       0x00010000,
+       0x00000000,
+       0x000003f4,
+/* 0x0324: memx_func_next */
+       0x00000001,
+       0x00000000,
+       0x00000415,
+       0x00000002,
+       0x00000002,
+       0x00000430,
+       0x00040003,
+       0x00000000,
+       0x00000458,
+       0x00010004,
+       0x00000000,
+       0x00000472,
+/* 0x0354: memx_func_tail */
+/* 0x0354: memx_data_head */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0b54: memx_data_tail */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
+
+uint32_t nvd0_pwr_code[] = {
+       0x02bf0ef5,
+/* 0x0004: rd32 */
+       0x07a007f1,
+       0xbd000ed0,
+       0x01e7f004,
+       0xf101e3f0,
+       0xd007ac07,
+       0x04bd000e,
+/* 0x001c: rd32_wait */
+       0x07ace7f1,
+       0xf100eecf,
+       0xf47000e4,
+       0xd7f1f51b,
+       0xddcf07a4,
+/* 0x0033: wr32 */
+       0xf100f800,
+       0xd007a007,
+       0x04bd000e,
+       0x07a407f1,
+       0xbd000dd0,
+       0x02e7f004,
+       0xf0f0e5f0,
+       0x07f101e3,
+       0x0ed007ac,
+/* 0x0057: wr32_wait */
+       0xf104bd00,
+       0xcf07ace7,
+       0xe4f100ee,
+       0x1bf47000,
+/* 0x0067: nsec */
+       0xf000f8f5,
+       0x88cf2c87,
+/* 0x006d: nsec_loop */
+       0x2c97f000,
+       0xbb0099cf,
+       0x9eb80298,
+       0xf41ef406,
+/* 0x007e: wait */
+       0x87f000f8,
+       0x0088cf2c,
+/* 0x0084: wait_loop */
+       0xf402eeb9,
+       0xdab90421,
+       0x04adfd02,
+       0xf406acb8,
+       0x97f0120b,
+       0x0099cf2c,
+       0xb80298bb,
+       0x1ef4069b,
+/* 0x00a5: wait_done */
+/* 0x00a7: intr_watchdog */
+       0x9800f8e2,
+       0x96b003e9,
+       0x2a0bf400,
+       0xbb840a98,
+       0x1cf4029a,
+       0x01d7f00f,
+       0x020621f5,
+       0x0ef494bd,
+/* 0x00c5: intr_watchdog_next_time */
+       0x850a9815,
+       0xf400a6b0,
+       0x9ab8090b,
+       0x061cf406,
+/* 0x00d4: intr_watchdog_next_time_set */
+/* 0x00d7: intr_watchdog_next_proc */
+       0x80850980,
+       0xe0b603e9,
+       0x10e6b158,
+       0xc61bf402,
+/* 0x00e6: intr */
+       0x00f900f8,
+       0x80f904bd,
+       0xa0f990f9,
+       0xc0f9b0f9,
+       0xe0f9d0f9,
+       0xf7f0f0f9,
+       0x0188fe00,
+       0x87f180f9,
+       0x88cf05d0,
+       0x0180b600,
+       0x05d007f1,
+       0xbd0008d0,
+       0x0887f004,
+       0xc40088cf,
+       0x0bf40289,
+       0x85008020,
+       0xf458e7f0,
+       0x0998a721,
+       0x0096b085,
+       0xf00e0bf4,
+       0x09d03407,
+       0x8004bd00,
+/* 0x013e: intr_skip_watchdog */
+       0x89e48409,
+       0x0bf40800,
+       0x8897f13c,
+       0x0099cf06,
+       0xf4029ac4,
+       0xc7f1260b,
+       0xcccf04c0,
+       0xf1c0f900,
+       0xf14f48e7,
+       0xf05453e3,
+       0x21f500d7,
+       0xc0fc026b,
+       0x04c007f1,
+       0xbd000cd0,
+/* 0x0175: intr_subintr_skip_fifo */
+       0x8807f104,
+       0x0009d006,
+/* 0x017e: intr_skip_subintr */
+       0x89c404bd,
+       0x070bf420,
+       0xffbfa4f1,
+/* 0x0188: intr_skip_pause */
+       0xf44089c4,
+       0xa4f1070b,
+/* 0x0192: intr_skip_user0 */
+       0x07f0ffbf,
+       0x0008d004,
+       0x80fc04bd,
+       0xfc0088fe,
+       0xfce0fcf0,
+       0xfcc0fcd0,
+       0xfca0fcb0,
+       0xfc80fc90,
+       0x0032f400,
+/* 0x01b6: timer */
+       0x32f401f8,
+       0x03f89810,
+       0xf40086b0,
+       0xfe80421c,
+       0x3807f003,
+       0xbd0008d0,
+       0x0887f004,
+       0xf00088cf,
+       0x1bf40284,
+       0x3487f020,
+       0xb80088cf,
+       0x0bf406e0,
+       0x06e8b809,
+/* 0x01eb: timer_reset */
+       0xf0191ef4,
+       0x0ed03407,
+       0x8004bd00,
+/* 0x01f6: timer_enable */
+       0x87f0840e,
+       0x3807f001,
+       0xbd0008d0,
+/* 0x0201: timer_done */
+       0x1031f404,
+/* 0x0206: send_proc */
+       0x80f900f8,
+       0xe89890f9,
+       0x04e99805,
+       0xb80486f0,
+       0x0bf40689,
+       0x0398c42a,
+       0xb6048894,
+       0x8ebb1880,
+       0x00fa9800,
+       0x80008a80,
+       0x8c80018d,
+       0x038b8002,
+       0xf00190b6,
+       0xe9800794,
+       0x0231f404,
+/* 0x0240: send_done */
+       0x80fc90fc,
+/* 0x0246: find */
+       0x80f900f8,
+       0xf45887f0,
+/* 0x024e: find_loop */
+       0x8a980131,
+       0x06aeb800,
+       0xb6100bf4,
+       0x86b15880,
+       0x1bf40210,
+       0x0132f4f0,
+/* 0x0264: find_done */
+       0xfc028eb9,
+/* 0x026b: send */
+       0xf500f880,
+       0xf4024621,
+       0x00f89701,
+/* 0x0274: recv */
+       0x9805e898,
+       0x32f404e9,
+       0x0689b801,
+       0xc43d0bf4,
+       0x80b60389,
+       0x0784f001,
+       0x9805e880,
+       0xf0f902ea,
+       0xf9018ffe,
+       0x02efb9f0,
+       0xbb049994,
+       0xe0b600e9,
+       0x03eb9818,
+       0x9802ec98,
+       0xee9801ed,
+       0xfca5f900,
+       0x00f8fef0,
+       0xfc0131f4,
+/* 0x02bd: recv_done */
+/* 0x02bf: init */
+       0xf100f8f0,
+       0xcf010817,
+       0x11e70011,
+       0x14b60109,
+       0x0014fe08,
+       0x00e017f1,
+       0xf00013f0,
+       0x01d01c07,
+       0xf004bd00,
+       0x07f0ff17,
+       0x0001d014,
+       0x17f004bd,
+       0x0015f102,
+       0x1007f008,
+       0xbd0001d0,
+       0xe617f104,
+       0x0013f000,
+       0xf40010fe,
+       0x17f01031,
+       0x3807f001,
+       0xbd0001d0,
+       0x58f7f004,
+/* 0x0314: init_proc */
+       0xb001f198,
+       0x0bf40016,
+       0xb615f9fa,
+       0x0ef458f0,
+/* 0x0325: host_send */
+       0xb017f1f2,
+       0x0011cf04,
+       0x04a027f1,
+       0xb80022cf,
+       0x0bf40612,
+       0x071ec42f,
+       0xb704ee94,
+       0x980218e0,
+       0xec9803eb,
+       0x01ed9802,
+       0xf500ee98,
+       0xb6026b21,
+       0x1ec40110,
+       0xb007f10f,
+       0x0001d004,
+       0x0ef404bd,
+/* 0x0365: host_send_done */
+/* 0x0367: host_recv */
+       0xf100f8c3,
+       0xf14e4917,
+       0xb8525413,
+       0x0bf406e1,
+/* 0x0375: host_recv_wait */
+       0xcc17f1b3,
+       0x0011cf04,
+       0x04c827f1,
+       0xf00022cf,
+       0x12b80816,
+       0xec0bf406,
+       0xb60723c4,
+       0x30b70434,
+       0x3b800298,
+       0x023c8003,
+       0x80013d80,
+       0x20b6003e,
+       0x0f24f001,
+       0x04c807f1,
+       0xbd0002d0,
+       0x4027f004,
+       0xd00007f0,
+       0x04bd0002,
+/* 0x03be: host_init */
+       0x17f100f8,
+       0x14b60080,
+       0x1815f110,
+       0xd007f102,
+       0x0001d004,
+       0x17f104bd,
+       0x14b60080,
+       0x9815f110,
+       0xdc07f102,
+       0x0001d004,
+       0x17f004bd,
+       0xc407f101,
+       0x0001d004,
+       0x00f804bd,
+/* 0x03f4: memx_func_enter */
+       0xf10467f0,
+       0xd007e007,
+       0x04bd0006,
+/* 0x0400: memx_func_enter_wait */
+       0x07c067f1,
+       0xf00066cf,
+       0x0bf40464,
+       0x001698f6,
+       0xf80410b6,
+/* 0x0415: memx_func_leave */
+       0x0467f000,
+       0x07e407f1,
+       0xbd0006d0,
+/* 0x0421: memx_func_leave_wait */
+       0xc067f104,
+       0x0066cf07,
+       0xf40464f0,
+       0x00f8f61b,
+/* 0x0430: memx_func_wr32 */
+       0x98001698,
+       0x10b60115,
+       0xf960f908,
+       0xfcd0fc50,
+       0x3321f4e0,
+       0x140003f1,
+       0x800506fd,
+       0x04bd0005,
+       0xf40242b6,
+       0x00f8dd1b,
+/* 0x0458: memx_func_wait */
+       0xcf2c87f0,
+       0x1e980088,
+       0x011d9800,
+       0x98021c98,
+       0x10b6031b,
+       0x7e21f410,
+/* 0x0472: memx_func_delay */
+       0x1e9800f8,
+       0x0410b600,
+       0xf86721f4,
+/* 0x047d: memx_exec */
+       0xf9e0f900,
+       0x02c1b9d0,
+/* 0x0487: memx_exec_next */
+       0x9802b2b9,
+       0x10b60013,
+       0x10349504,
+       0x980c30f0,
+       0x55f9c835,
+       0xf40612b8,
+       0xd0fcec1e,
+       0x21f5e0fc,
+       0x00f8026b,
+/* 0x04a8: memx_info */
+       0x0354c7f1,
+       0x0800b7f1,
+       0x026b21f5,
+/* 0x04b6: memx_recv */
+       0xd6b000f8,
+       0xc40bf401,
+       0xf400d6b0,
+       0x00f8e90b,
+/* 0x04c4: memx_init */
+/* 0x04c6: perf_recv */
+       0x00f800f8,
+/* 0x04c8: perf_init */
+/* 0x04ca: test_recv */
+       0x17f100f8,
+       0x11cf05d8,
+       0x0110b600,
+       0x05d807f1,
+       0xbd0001d0,
+       0x00e7f104,
+       0x4fe3f1d9,
+       0xb621f513,
+/* 0x04eb: test_init */
+       0xf100f801,
+       0xf50800e7,
+       0xf801b621,
+/* 0x04f5: idle_recv */
+/* 0x04f7: idle */
+       0xf400f800,
+       0x17f10031,
+       0x11cf05d4,
+       0x0110b600,
+       0x05d407f1,
+       0xbd0001d0,
+/* 0x050d: idle_loop */
+       0x5817f004,
+/* 0x0513: idle_proc */
+/* 0x0513: idle_proc_exec */
+       0xf90232f4,
+       0x021eb910,
+       0x027421f5,
+       0x11f410fc,
+       0x0231f409,
+/* 0x0527: idle_proc_next */
+       0xb6ef0ef4,
+       0x1fb85810,
+       0xe61bf406,
+       0xf4dd02f4,
+       0x0ef40028,
+       0x000000c1,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h
new file mode 100644 (file)
index 0000000..5fb0ccc
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __NVKM_PWR_OS_H__
+#define __NVKM_PWR_OS_H__
+
+/* Process names */
+#define PROC_KERN 0x52544e49
+#define PROC_IDLE 0x454c4449
+#define PROC_HOST 0x54534f48
+#define PROC_MEMX 0x584d454d
+#define PROC_PERF 0x46524550
+#define PROC_TEST 0x54534554
+
+/* KERN: message identifiers */
+#define KMSG_FIFO   0x00000000
+#define KMSG_ALARM  0x00000001
+
+/* MEMX: message identifiers */
+#define MEMX_MSG_INFO 0
+#define MEMX_MSG_EXEC 1
+
+/* MEMX: script opcode definitions */
+#define MEMX_ENTER  0
+#define MEMX_LEAVE  1
+#define MEMX_WR32   2
+#define MEMX_WAIT   3
+#define MEMX_DELAY  4
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc
new file mode 100644 (file)
index 0000000..38eadf7
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_PROC
+process(PROC_PERF, #perf_init, #perf_recv)
+#endif
+
+/******************************************************************************
+ * PERF data segment
+ *****************************************************************************/
+#ifdef INCLUDE_DATA
+#endif
+
+/******************************************************************************
+ * PERF code segment
+ *****************************************************************************/
+#ifdef INCLUDE_CODE
+
+// description
+//
+// $r15 - current (perf)
+// $r14 - sender process name
+// $r13 - message
+// $r12 - data0
+// $r11 - data1
+// $r0  - zero
+perf_recv:
+       ret
+
+// description
+//
+// $r15 - current (perf)
+// $r0  - zero
+perf_init:
+       ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc
new file mode 100644 (file)
index 0000000..0c3a71b
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_PROC
+process(PROC_TEST, #test_init, #test_recv)
+#endif
+
+/******************************************************************************
+ * TEST data segment
+ *****************************************************************************/
+#ifdef INCLUDE_DATA
+#endif
+
+/******************************************************************************
+ * TEST code segment
+ *****************************************************************************/
+#ifdef INCLUDE_CODE
+// description
+//
+// $r15 - current (test)
+// $r14 - sender process name
+// $r13 - message
+// $r12 - data0
+// $r11 - data1
+// $r0  - zero
+test_recv:
+       nv_iord($r1, NV_PPWR_DSCRATCH(2))
+       add b32 $r1 1
+       nv_iowr(NV_PPWR_DSCRATCH(2), $r1)
+       mov $r14 -0x2700 /* 0xd900, envyas grrr! */
+       sethi $r14 0x134f0000
+       call(timer)
+       ret
+
+// description
+//
+// $r15 - current (test)
+// $r0  - zero
+test_init:
+       mov $r14 0x800
+       call(timer)
+       ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c
new file mode 100644 (file)
index 0000000..03de310
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef __NVKM_PWR_MEMX_H__
+#define __NVKM_PWR_MEMX_H__
+
+#include <subdev/pwr.h>
+#include <subdev/pwr/fuc/os.h>
+
+struct nouveau_memx {
+       struct nouveau_pwr *ppwr;
+       u32 base;
+       u32 size;
+       struct {
+               u32 mthd;
+               u32 size;
+               u32 data[64];
+       } c;
+};
+
+static void
+memx_out(struct nouveau_memx *memx)
+{
+       struct nouveau_pwr *ppwr = memx->ppwr;
+       int i;
+
+       if (memx->c.size) {
+               nv_wr32(ppwr, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd);
+               for (i = 0; i < memx->c.size; i++)
+                       nv_wr32(ppwr, 0x10a1c4, memx->c.data[i]);
+               memx->c.size = 0;
+       }
+}
+
+static void
+memx_cmd(struct nouveau_memx *memx, u32 mthd, u32 size, u32 data[])
+{
+       if ((memx->c.size + size >= ARRAY_SIZE(memx->c.data)) ||
+           (memx->c.size && memx->c.mthd != mthd))
+               memx_out(memx);
+       memcpy(&memx->c.data[memx->c.size], data, size * sizeof(data[0]));
+       memx->c.size += size;
+       memx->c.mthd  = mthd;
+}
+
+int
+nouveau_memx_init(struct nouveau_pwr *ppwr, struct nouveau_memx **pmemx)
+{
+       struct nouveau_memx *memx;
+       u32 reply[2];
+       int ret;
+
+       ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO, 0, 0);
+       if (ret)
+               return ret;
+
+       memx = *pmemx = kzalloc(sizeof(*memx), GFP_KERNEL);
+       if (!memx)
+               return -ENOMEM;
+       memx->ppwr = ppwr;
+       memx->base = reply[0];
+       memx->size = reply[1];
+
+       /* acquire data segment access */
+       do {
+               nv_wr32(ppwr, 0x10a580, 0x00000003);
+       } while (nv_rd32(ppwr, 0x10a580) != 0x00000003);
+       nv_wr32(ppwr, 0x10a1c0, 0x01000000 | memx->base);
+       nv_wr32(ppwr, 0x10a1c4, 0x00010000 | MEMX_ENTER);
+       nv_wr32(ppwr, 0x10a1c4, 0x00000000);
+       return 0;
+}
+
+int
+nouveau_memx_fini(struct nouveau_memx **pmemx, bool exec)
+{
+       struct nouveau_memx *memx = *pmemx;
+       struct nouveau_pwr *ppwr = memx->ppwr;
+       u32 finish, reply[2];
+
+       /* flush the cache... */
+       memx_out(memx);
+
+       /* release data segment access */
+       nv_wr32(ppwr, 0x10a1c4, 0x00000000 | MEMX_LEAVE);
+       finish = nv_rd32(ppwr, 0x10a1c0) & 0x00ffffff;
+       nv_wr32(ppwr, 0x10a580, 0x00000000);
+
+       /* call MEMX process to execute the script, and wait for reply */
+       if (exec) {
+               ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_EXEC,
+                                memx->base, finish);
+       }
+
+       kfree(memx);
+       return 0;
+}
+
+void
+nouveau_memx_wr32(struct nouveau_memx *memx, u32 addr, u32 data)
+{
+       nv_debug(memx->ppwr, "R[%06x] = 0x%08x\n", addr, data);
+       memx_cmd(memx, MEMX_WR32, 2, (u32[]){ addr, data });
+}
+
+void
+nouveau_memx_wait(struct nouveau_memx *memx,
+                 u32 addr, u32 mask, u32 data, u32 nsec)
+{
+       nv_debug(memx->ppwr, "R[%06x] & 0x%08x == 0x%08x, %d us\n",
+                               addr, mask, data, nsec);
+       memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, ~mask, data, nsec });
+       memx_out(memx); /* fuc can't handle multiple */
+}
+
+void
+nouveau_memx_nsec(struct nouveau_memx *memx, u32 nsec)
+{
+       nv_debug(memx->ppwr, "    DELAY = %d ns\n", nsec);
+       memx_cmd(memx, MEMX_DELAY, 1, (u32[]){ nsec });
+       memx_out(memx); /* fuc can't handle multiple */
+}
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c
new file mode 100644 (file)
index 0000000..52c8541
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/pwr.h>
+
+#include "fuc/nv108.fuc.h"
+
+struct nv108_pwr_priv {
+       struct nouveau_pwr base;
+};
+
+static int
+nv108_pwr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct nv108_pwr_priv *priv;
+       int ret;
+
+       ret = nouveau_pwr_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       priv->base.code.data = nv108_pwr_code;
+       priv->base.code.size = sizeof(nv108_pwr_code);
+       priv->base.data.data = nv108_pwr_data;
+       priv->base.data.size = sizeof(nv108_pwr_data);
+       return 0;
+}
+
+struct nouveau_oclass
+nv108_pwr_oclass = {
+       .handle = NV_SUBDEV(PWR, 0x00),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv108_pwr_ctor,
+               .dtor = _nouveau_pwr_dtor,
+               .init = _nouveau_pwr_init,
+               .fini = _nouveau_pwr_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c
new file mode 100644 (file)
index 0000000..c132b7c
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/pwr.h>
+
+#include "fuc/nva3.fuc.h"
+
+struct nva3_pwr_priv {
+       struct nouveau_pwr base;
+};
+
+static int
+nva3_pwr_init(struct nouveau_object *object)
+{
+       struct nva3_pwr_priv *priv = (void *)object;
+       nv_mask(priv, 0x022210, 0x00000001, 0x00000000);
+       nv_mask(priv, 0x022210, 0x00000001, 0x00000001);
+       return nouveau_pwr_init(&priv->base);
+}
+
+static int
+nva3_pwr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+             struct nouveau_oclass *oclass, void *data, u32 size,
+             struct nouveau_object **pobject)
+{
+       struct nva3_pwr_priv *priv;
+       int ret;
+
+       ret = nouveau_pwr_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       priv->base.code.data = nva3_pwr_code;
+       priv->base.code.size = sizeof(nva3_pwr_code);
+       priv->base.data.data = nva3_pwr_data;
+       priv->base.data.size = sizeof(nva3_pwr_data);
+       return 0;
+}
+
+struct nouveau_oclass
+nva3_pwr_oclass = {
+       .handle = NV_SUBDEV(PWR, 0xa3),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nva3_pwr_ctor,
+               .dtor = _nouveau_pwr_dtor,
+               .init = nva3_pwr_init,
+               .fini = _nouveau_pwr_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c
new file mode 100644 (file)
index 0000000..495f685
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/pwr.h>
+
+#include "fuc/nvc0.fuc.h"
+
+struct nvc0_pwr_priv {
+       struct nouveau_pwr base;
+};
+
+static int
+nvc0_pwr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+             struct nouveau_oclass *oclass, void *data, u32 size,
+             struct nouveau_object **pobject)
+{
+       struct nvc0_pwr_priv *priv;
+       int ret;
+
+       ret = nouveau_pwr_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       priv->base.code.data = nvc0_pwr_code;
+       priv->base.code.size = sizeof(nvc0_pwr_code);
+       priv->base.data.data = nvc0_pwr_data;
+       priv->base.data.size = sizeof(nvc0_pwr_data);
+       return 0;
+}
+
+struct nouveau_oclass
+nvc0_pwr_oclass = {
+       .handle = NV_SUBDEV(PWR, 0xc0),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvc0_pwr_ctor,
+               .dtor = _nouveau_pwr_dtor,
+               .init = _nouveau_pwr_init,
+               .fini = _nouveau_pwr_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c
new file mode 100644 (file)
index 0000000..043aa14
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/pwr.h>
+
+#include "fuc/nvd0.fuc.h"
+
+struct nvd0_pwr_priv {
+       struct nouveau_pwr base;
+};
+
+static int
+nvd0_pwr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+             struct nouveau_oclass *oclass, void *data, u32 size,
+             struct nouveau_object **pobject)
+{
+       struct nvd0_pwr_priv *priv;
+       int ret;
+
+       ret = nouveau_pwr_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       priv->base.code.data = nvd0_pwr_code;
+       priv->base.code.size = sizeof(nvd0_pwr_code);
+       priv->base.data.data = nvd0_pwr_data;
+       priv->base.data.size = sizeof(nvd0_pwr_data);
+       return 0;
+}
+
+struct nouveau_oclass
+nvd0_pwr_oclass = {
+       .handle = NV_SUBDEV(PWR, 0xd0),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvd0_pwr_ctor,
+               .dtor = _nouveau_pwr_dtor,
+               .init = _nouveau_pwr_init,
+               .fini = _nouveau_pwr_fini,
+       },
+};
index f1de7a9..21b2b30 100644 (file)
@@ -92,10 +92,11 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
        struct nouveau_timer *ptimer = nouveau_timer(therm);
        struct nouveau_therm_priv *priv = (void *)therm;
        unsigned long flags;
-       int duty;
+       bool immd = true;
+       bool poll = true;
+       int duty = -1;
 
        spin_lock_irqsave(&priv->lock, flags);
-       nv_debug(therm, "FAN speed check\n");
        if (mode < 0)
                mode = priv->mode;
        priv->mode = mode;
@@ -106,28 +107,48 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
                duty = nouveau_therm_fan_get(therm);
                if (duty < 0)
                        duty = 100;
+               poll = false;
                break;
        case NOUVEAU_THERM_CTRL_AUTO:
-               if (priv->fan->bios.nr_fan_trip)
+               if (priv->fan->bios.nr_fan_trip) {
                        duty = nouveau_therm_update_trip(therm);
-               else
+               } else
+               if (priv->fan->bios.linear_min_temp ||
+                   priv->fan->bios.linear_max_temp) {
                        duty = nouveau_therm_update_linear(therm);
+               } else {
+                       duty = priv->cstate;
+                       poll = false;
+               }
+               immd = false;
                break;
        case NOUVEAU_THERM_CTRL_NONE:
        default:
                ptimer->alarm_cancel(ptimer, &priv->alarm);
-               goto done;
+               poll = false;
        }
 
-       nv_debug(therm, "FAN target request: %d%%\n", duty);
-       nouveau_therm_fan_set(therm, (mode != NOUVEAU_THERM_CTRL_AUTO), duty);
-
-done:
-       if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO))
+       if (list_empty(&priv->alarm.head) && poll)
                ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm);
-       else if (!list_empty(&priv->alarm.head))
-               nv_debug(therm, "therm fan alarm list is not empty\n");
        spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (duty >= 0) {
+               nv_debug(therm, "FAN target request: %d%%\n", duty);
+               nouveau_therm_fan_set(therm, immd, duty);
+       }
+}
+
+int
+nouveau_therm_cstate(struct nouveau_therm *ptherm, int fan, int dir)
+{
+       struct nouveau_therm_priv *priv = (void *)ptherm;
+       if (!dir || (dir < 0 && fan < priv->cstate) ||
+                   (dir > 0 && fan > priv->cstate)) {
+               nv_debug(ptherm, "default fan speed -> %d%%\n", fan);
+               priv->cstate = fan;
+               nouveau_therm_update(ptherm, -1);
+       }
+       return 0;
 }
 
 static void
@@ -149,14 +170,15 @@ nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode)
                "automatic"
        };
 
-       /* The default PDAEMON ucode interferes with fan management */
+       /* The default PPWR ucode on fermi interferes with fan management */
        if ((mode >= ARRAY_SIZE(name)) ||
-           (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0))
+           (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0 &&
+            !nouveau_subdev(device, NVDEV_SUBDEV_PWR)))
                return -EINVAL;
 
        /* do not allow automatic fan management if the thermal sensor is
         * not available */
-       if (priv->mode == 2 && therm->temp_get(therm) < 0)
+       if (priv->mode == NOUVEAU_THERM_CTRL_AUTO && therm->temp_get(therm) < 0)
                return -EINVAL;
 
        if (priv->mode == mode)
@@ -335,7 +357,7 @@ nouveau_therm_preinit(struct nouveau_therm *therm)
        nouveau_therm_ic_ctor(therm);
        nouveau_therm_fan_ctor(therm);
 
-       nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_NONE);
+       nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_AUTO);
        nouveau_therm_sensor_preinit(therm);
        return 0;
 }
index 39f47b9..95f6129 100644 (file)
@@ -185,8 +185,11 @@ nouveau_therm_fan_set_defaults(struct nouveau_therm *therm)
        priv->fan->bios.max_duty = 100;
        priv->fan->bios.bump_period = 500;
        priv->fan->bios.slow_down_period = 2000;
+/*XXX: talk to mupuf */
+#if 0
        priv->fan->bios.linear_min_temp = 40;
        priv->fan->bios.linear_max_temp = 85;
+#endif
 }
 
 static void
index e601773..f69dab1 100644 (file)
@@ -97,6 +97,13 @@ nouveau_fantog_create(struct nouveau_therm *therm, struct dcb_gpio_func *func)
 {
        struct nouveau_therm_priv *tpriv = (void *)therm;
        struct nouveau_fantog_priv *priv;
+       int ret;
+
+       if (therm->pwm_ctrl) {
+               ret = therm->pwm_ctrl(therm, func->line, false);
+               if (ret)
+                       return ret;
+       }
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        tpriv->fan = &priv->base;
index 8b3adec..13b8500 100644 (file)
@@ -55,28 +55,28 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c,
        return true;
 }
 
-static struct i2c_board_info
+static struct nouveau_i2c_board_info
 nv_board_infos[] = {
-       { I2C_BOARD_INFO("w83l785ts", 0x2d) },
-       { I2C_BOARD_INFO("w83781d", 0x2d) },
-       { I2C_BOARD_INFO("adt7473", 0x2e) },
-       { I2C_BOARD_INFO("adt7473", 0x2d) },
-       { I2C_BOARD_INFO("adt7473", 0x2c) },
-       { I2C_BOARD_INFO("f75375", 0x2e) },
-       { I2C_BOARD_INFO("lm99", 0x4c) },
-       { I2C_BOARD_INFO("lm90", 0x4c) },
-       { I2C_BOARD_INFO("lm90", 0x4d) },
-       { I2C_BOARD_INFO("adm1021", 0x18) },
-       { I2C_BOARD_INFO("adm1021", 0x19) },
-       { I2C_BOARD_INFO("adm1021", 0x1a) },
-       { I2C_BOARD_INFO("adm1021", 0x29) },
-       { I2C_BOARD_INFO("adm1021", 0x2a) },
-       { I2C_BOARD_INFO("adm1021", 0x2b) },
-       { I2C_BOARD_INFO("adm1021", 0x4c) },
-       { I2C_BOARD_INFO("adm1021", 0x4d) },
-       { I2C_BOARD_INFO("adm1021", 0x4e) },
-       { I2C_BOARD_INFO("lm63", 0x18) },
-       { I2C_BOARD_INFO("lm63", 0x4e) },
+       { { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 },
+       { { I2C_BOARD_INFO("w83781d", 0x2d) }, 0  },
+       { { I2C_BOARD_INFO("adt7473", 0x2e) }, 20  },
+       { { I2C_BOARD_INFO("adt7473", 0x2d) }, 20  },
+       { { I2C_BOARD_INFO("adt7473", 0x2c) }, 20  },
+       { { I2C_BOARD_INFO("f75375", 0x2e) }, 0  },
+       { { I2C_BOARD_INFO("lm99", 0x4c) }, 0  },
+       { { I2C_BOARD_INFO("lm90", 0x4c) }, 0  },
+       { { I2C_BOARD_INFO("lm90", 0x4d) }, 0  },
+       { { I2C_BOARD_INFO("adm1021", 0x18) }, 0  },
+       { { I2C_BOARD_INFO("adm1021", 0x19) }, 0  },
+       { { I2C_BOARD_INFO("adm1021", 0x1a) }, 0  },
+       { { I2C_BOARD_INFO("adm1021", 0x29) }, 0  },
+       { { I2C_BOARD_INFO("adm1021", 0x2a) }, 0  },
+       { { I2C_BOARD_INFO("adm1021", 0x2b) }, 0  },
+       { { I2C_BOARD_INFO("adm1021", 0x4c) }, 0  },
+       { { I2C_BOARD_INFO("adm1021", 0x4d) }, 0  },
+       { { I2C_BOARD_INFO("adm1021", 0x4e) }, 0  },
+       { { I2C_BOARD_INFO("lm63", 0x18) }, 0  },
+       { { I2C_BOARD_INFO("lm63", 0x4e) }, 0  },
        { }
 };
 
@@ -89,9 +89,9 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm)
        struct nvbios_extdev_func extdev_entry;
 
        if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
-               struct i2c_board_info board[] = {
-                       { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) },
-                       { }
+               struct nouveau_i2c_board_info board[] = {
+                 { { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0},
+                 { }
                };
 
                i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
@@ -101,9 +101,9 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm)
        }
 
        if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
-               struct i2c_board_info board[] = {
-                       { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) },
-                       { }
+               struct nouveau_i2c_board_info board[] = {
+                 { { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 },
+                 { }
                };
 
                i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
index 42ba633..1d15c52 100644 (file)
@@ -126,7 +126,7 @@ nv84_therm_intr(struct nouveau_subdev *subdev)
 
        spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
 
-       intr = nv_rd32(therm, 0x20100);
+       intr = nv_rd32(therm, 0x20100) & 0x3ff;
 
        /* THRS_4: downclock */
        if (intr & 0x002) {
@@ -209,6 +209,19 @@ nv84_therm_ctor(struct nouveau_object *parent,
        return nouveau_therm_preinit(&priv->base.base);
 }
 
+int
+nv84_therm_fini(struct nouveau_object *object, bool suspend)
+{
+       /* Disable PTherm IRQs */
+       nv_wr32(object, 0x20000, 0x00000000);
+
+       /* ACK all PTherm IRQs */
+       nv_wr32(object, 0x20100, 0xffffffff);
+       nv_wr32(object, 0x1100, 0x10000); /* PBUS */
+
+       return _nouveau_therm_fini(object, suspend);
+}
+
 struct nouveau_oclass
 nv84_therm_oclass = {
        .handle = NV_SUBDEV(THERM, 0x84),
@@ -216,6 +229,6 @@ nv84_therm_oclass = {
                .ctor = nv84_therm_ctor,
                .dtor = _nouveau_therm_dtor,
                .init = _nouveau_therm_init,
-               .fini = _nouveau_therm_fini,
+               .fini = nv84_therm_fini,
        },
 };
index d11a7c4..3b2c458 100644 (file)
@@ -94,6 +94,6 @@ nva3_therm_oclass = {
                .ctor = nva3_therm_ctor,
                .dtor = _nouveau_therm_dtor,
                .init = nva3_therm_init,
-               .fini = _nouveau_therm_fini,
+               .fini = nv84_therm_fini,
        },
 };
index 54c28bd..4dd4f81 100644 (file)
@@ -148,6 +148,6 @@ nvd0_therm_oclass = {
                .ctor = nvd0_therm_ctor,
                .dtor = _nouveau_therm_dtor,
                .init = nvd0_therm_init,
-               .fini = _nouveau_therm_fini,
+               .fini = nv84_therm_fini,
        },
 };
index dd38529..96f8f95 100644 (file)
@@ -76,6 +76,7 @@ struct nouveau_therm_priv {
        spinlock_t lock;
        struct nouveau_therm_trip_point *last_trip;
        int mode;
+       int cstate;
        int suspend;
 
        /* bios */
@@ -144,6 +145,7 @@ int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *);
 int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32);
 int nv50_fan_pwm_clock(struct nouveau_therm *);
 int nv84_temp_get(struct nouveau_therm *therm);
+int nv84_therm_fini(struct nouveau_object *object, bool suspend);
 
 int nva3_therm_fan_sense(struct nouveau_therm *);
 
index b80a330..cfde9eb 100644 (file)
@@ -180,8 +180,6 @@ alarm_timer_callback(struct nouveau_alarm *alarm)
 
        spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
 
-       nv_debug(therm, "polling the internal temperature\n");
-
        nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost,
                                             NOUVEAU_THERM_THRS_FANBOOST);
 
index 57711ec..c0bdd10 100644 (file)
@@ -119,16 +119,8 @@ nv04_timer_alarm_cancel(struct nouveau_timer *ptimer,
 {
        struct nv04_timer_priv *priv = (void *)ptimer;
        unsigned long flags;
-
-       /* avoid deleting an entry while the alarm intr is running */
        spin_lock_irqsave(&priv->lock, flags);
-
-       /* delete the alarm from the list */
-       list_del(&alarm->head);
-
-       /* reset the head so as list_empty returns 1 */
-       INIT_LIST_HEAD(&alarm->head);
-
+       list_del_init(&alarm->head);
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/base.c b/drivers/gpu/drm/nouveau/core/subdev/volt/base.c
new file mode 100644 (file)
index 0000000..32794a9
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/volt.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/vmap.h>
+#include <subdev/bios/volt.h>
+
+static int
+nouveau_volt_get(struct nouveau_volt *volt)
+{
+       if (volt->vid_get) {
+               int ret = volt->vid_get(volt), i;
+               if (ret >= 0) {
+                       for (i = 0; i < volt->vid_nr; i++) {
+                               if (volt->vid[i].vid == ret)
+                                       return volt->vid[i].uv;
+                       }
+                       ret = -EINVAL;
+               }
+               return ret;
+       }
+       return -ENODEV;
+}
+
+static int
+nouveau_volt_set(struct nouveau_volt *volt, u32 uv)
+{
+       if (volt->vid_set) {
+               int i, ret = -EINVAL;
+               for (i = 0; i < volt->vid_nr; i++) {
+                       if (volt->vid[i].uv == uv) {
+                               ret = volt->vid_set(volt, volt->vid[i].vid);
+                               nv_debug(volt, "set %duv: %d\n", uv, ret);
+                               break;
+                       }
+               }
+               return ret;
+       }
+       return -ENODEV;
+}
+
+static int
+nouveau_volt_map(struct nouveau_volt *volt, u8 id)
+{
+       struct nouveau_bios *bios = nouveau_bios(volt);
+       struct nvbios_vmap_entry info;
+       u8  ver, len;
+       u16 vmap;
+
+       vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
+       if (vmap) {
+               if (info.link != 0xff) {
+                       int ret = nouveau_volt_map(volt, info.link);
+                       if (ret < 0)
+                               return ret;
+                       info.min += ret;
+               }
+               return info.min;
+       }
+
+       return id ? id * 10000 : -ENODEV;
+}
+
+static int
+nouveau_volt_set_id(struct nouveau_volt *volt, u8 id, int condition)
+{
+       int ret = nouveau_volt_map(volt, id);
+       if (ret >= 0) {
+               int prev = nouveau_volt_get(volt);
+               if (!condition || prev < 0 ||
+                   (condition < 0 && ret < prev) ||
+                   (condition > 0 && ret > prev)) {
+                       ret = nouveau_volt_set(volt, ret);
+               } else {
+                       ret = 0;
+               }
+       }
+       return ret;
+}
+
+int
+_nouveau_volt_init(struct nouveau_object *object)
+{
+       struct nouveau_volt *volt = (void *)object;
+       int ret;
+
+       ret = nouveau_subdev_init(&volt->base);
+       if (ret)
+               return ret;
+
+       ret = volt->get(volt);
+       if (ret < 0) {
+               if (ret != -ENODEV)
+                       nv_debug(volt, "current voltage unknown\n");
+               return 0;
+       }
+
+       nv_info(volt, "GPU voltage: %duv\n", ret);
+       return 0;
+}
+
+void
+_nouveau_volt_dtor(struct nouveau_object *object)
+{
+       struct nouveau_volt *volt = (void *)object;
+       nouveau_subdev_destroy(&volt->base);
+}
+
+int
+nouveau_volt_create_(struct nouveau_object *parent,
+                    struct nouveau_object *engine,
+                    struct nouveau_oclass *oclass, int length, void **pobject)
+{
+       struct nouveau_bios *bios = nouveau_bios(parent);
+       struct nouveau_volt *volt;
+       struct nvbios_volt_entry ivid;
+       struct nvbios_volt info;
+       u8  ver, hdr, cnt, len;
+       u16 data;
+       int ret, i;
+
+       ret = nouveau_subdev_create_(parent, engine, oclass, 0, "VOLT",
+                                    "voltage", length, pobject);
+       volt = *pobject;
+       if (ret)
+               return ret;
+
+       volt->get = nouveau_volt_get;
+       volt->set = nouveau_volt_set;
+       volt->set_id = nouveau_volt_set_id;
+
+       data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
+       if (data && info.vidmask && info.base && info.step) {
+               for (i = 0; i < info.vidmask + 1; i++) {
+                       if (info.base >= info.min &&
+                           info.base <= info.max) {
+                               volt->vid[volt->vid_nr].uv = info.base;
+                               volt->vid[volt->vid_nr].vid = i;
+                               volt->vid_nr++;
+                       }
+                       info.base += info.step;
+               }
+               volt->vid_mask = info.vidmask;
+       } else
+       if (data && info.vidmask) {
+               for (i = 0; i < cnt; i++) {
+                       data = nvbios_volt_entry_parse(bios, i, &ver, &hdr,
+                                                     &ivid);
+                       if (data) {
+                               volt->vid[volt->vid_nr].uv = ivid.voltage;
+                               volt->vid[volt->vid_nr].vid = ivid.vid;
+                               volt->vid_nr++;
+                       }
+               }
+               volt->vid_mask = info.vidmask;
+       }
+
+       if (volt->vid_nr) {
+               for (i = 0; i < volt->vid_nr; i++) {
+                       nv_debug(volt, "VID %02x: %duv\n",
+                                volt->vid[i].vid, volt->vid[i].uv);
+               }
+
+               /*XXX: this is an assumption.. there probably exists boards
+                * out there with i2c-connected voltage controllers too..
+                */
+               ret = nouveau_voltgpio_init(volt);
+               if (ret == 0) {
+                       volt->vid_get = nouveau_voltgpio_get;
+                       volt->vid_set = nouveau_voltgpio_set;
+               }
+       }
+
+       return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c
new file mode 100644 (file)
index 0000000..755fa91
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/volt.h>
+#include <subdev/gpio.h>
+#include <subdev/bios/gpio.h>
+
+static const u8 tags[] = {
+       DCB_GPIO_VID0, DCB_GPIO_VID1, DCB_GPIO_VID2, DCB_GPIO_VID3,
+       DCB_GPIO_VID4, DCB_GPIO_VID5, DCB_GPIO_VID6, DCB_GPIO_VID7,
+};
+
+int
+nouveau_voltgpio_get(struct nouveau_volt *volt)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(volt);
+       u8 vid = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(tags); i++) {
+               if (volt->vid_mask & (1 << i)) {
+                       int ret = gpio->get(gpio, 0, tags[i], 0xff);
+                       if (ret < 0)
+                               return ret;
+                       vid |= ret << i;
+               }
+       }
+
+       return vid;
+}
+
+int
+nouveau_voltgpio_set(struct nouveau_volt *volt, u8 vid)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(volt);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(tags); i++, vid >>= 1) {
+               if (volt->vid_mask & (1 << i)) {
+                       int ret = gpio->set(gpio, 0, tags[i], 0xff, vid & 1);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+int
+nouveau_voltgpio_init(struct nouveau_volt *volt)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(volt);
+       struct dcb_gpio_func func;
+       int i;
+
+       /* check we have gpio function info for each vid bit.  on some
+        * boards (ie. nvs295) the vid mask has more bits than there
+        * are valid gpio functions... from traces, nvidia appear to
+        * just touch the existing ones, so let's mask off the invalid
+        * bits and continue with life
+        */
+       for (i = 0; i < ARRAY_SIZE(tags); i++) {
+               if (volt->vid_mask & (1 << i)) {
+                       int ret = gpio->find(gpio, 0, tags[i], 0xff, &func);
+                       if (ret) {
+                               if (ret != -ENOENT)
+                                       return ret;
+                               nv_debug(volt, "VID bit %d has no GPIO\n", i);
+                               volt->vid_mask &= ~(1 << i);
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c
new file mode 100644 (file)
index 0000000..87d5358
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/volt.h>
+
+struct nv40_volt_priv {
+       struct nouveau_volt base;
+};
+
+static int
+nv40_volt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct nv40_volt_priv *priv;
+       int ret;
+
+       ret = nouveau_volt_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+struct nouveau_oclass
+nv40_volt_oclass = {
+       .handle = NV_SUBDEV(VOLT, 0x40),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv40_volt_ctor,
+               .dtor = _nouveau_volt_dtor,
+               .init = _nouveau_volt_init,
+               .fini = _nouveau_volt_fini,
+       },
+};
index ea3f5b8..424a489 100644 (file)
@@ -5,6 +5,7 @@ nouveau-y += dispnv04/dac.o
 nouveau-y += dispnv04/dfp.o
 nouveau-y += dispnv04/disp.o
 nouveau-y += dispnv04/hw.o
+nouveau-y += dispnv04/overlay.o
 nouveau-y += dispnv04/tvmodesnv17.o
 nouveau-y += dispnv04/tvnv04.o
 nouveau-y += dispnv04/tvnv17.o
index 59d1c04..936a71c 100644 (file)
@@ -493,7 +493,7 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode)
        if (dev->pdev->device == 0x0174 || dev->pdev->device == 0x0179 ||
            dev->pdev->device == 0x0189 || dev->pdev->device == 0x0329) {
                if (mode == DRM_MODE_DPMS_ON) {
-                       nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 0, 1 << 31);
+                       nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 1 << 31);
                        nv_mask(device, NV_PCRTC_GPIO_EXT, 3, 1);
                } else {
                        nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 0);
@@ -625,13 +625,15 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
        struct nouveau_i2c_port *port = i2c->find(i2c, 2);
-       struct i2c_board_info info[] = {
+       struct nouveau_i2c_board_info info[] = {
                {
-                       .type = "sil164",
-                       .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38),
-                       .platform_data = &(struct sil164_encoder_params) {
-                               SIL164_INPUT_EDGE_RISING
-                       }
+                   {
+                       .type = "sil164",
+                       .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38),
+                       .platform_data = &(struct sil164_encoder_params) {
+                           SIL164_INPUT_EDGE_RISING
+                        }
+                   }, 0
                },
                { }
        };
@@ -646,7 +648,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
                return;
 
        drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
-                            &port->adapter, &info[type]);
+                            &port->adapter, &info[type].dev);
 }
 
 static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
index 4908d3f..b13ff0f 100644 (file)
@@ -140,6 +140,8 @@ nv04_display_create(struct drm_device *dev)
                func->save(encoder);
        }
 
+       nouveau_overlay_init(dev);
+
        return 0;
 }
 
index 2cf65e0..56a28db 100644 (file)
@@ -123,6 +123,9 @@ int nv04_tv_create(struct drm_connector *, struct dcb_output *);
 /* nv17_tv.c */
 int nv17_tv_create(struct drm_connector *, struct dcb_output *);
 
+/* overlay.c */
+void nouveau_overlay_init(struct drm_device *dev);
+
 static inline bool
 nv_two_heads(struct drm_device *dev)
 {
index f8dee83..aca76af 100644 (file)
@@ -27,6 +27,7 @@
 #include "hw.h"
 
 #include <subdev/bios/pll.h>
+#include <subdev/fb.h>
 #include <subdev/clock.h>
 #include <subdev/timer.h>
 
@@ -664,6 +665,7 @@ nv_load_state_ext(struct drm_device *dev, int head,
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_device *device = nv_device(drm->device);
        struct nouveau_timer *ptimer = nouveau_timer(device);
+       struct nouveau_fb *pfb = nouveau_fb(device);
        struct nv04_crtc_reg *regp = &state->crtc_reg[head];
        uint32_t reg900;
        int i;
@@ -680,10 +682,10 @@ nv_load_state_ext(struct drm_device *dev, int head,
                nv_wr32(device, NV_PVIDEO_INTR_EN, 0);
                nv_wr32(device, NV_PVIDEO_OFFSET_BUFF(0), 0);
                nv_wr32(device, NV_PVIDEO_OFFSET_BUFF(1), 0);
-               nv_wr32(device, NV_PVIDEO_LIMIT(0), 0); //drm->fb_available_size - 1);
-               nv_wr32(device, NV_PVIDEO_LIMIT(1), 0); //drm->fb_available_size - 1);
-               nv_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(0), 0); //drm->fb_available_size - 1);
-               nv_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(1), 0); //drm->fb_available_size - 1);
+               nv_wr32(device, NV_PVIDEO_LIMIT(0), pfb->ram->size - 1);
+               nv_wr32(device, NV_PVIDEO_LIMIT(1), pfb->ram->size - 1);
+               nv_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(0), pfb->ram->size - 1);
+               nv_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(1), pfb->ram->size - 1);
                nv_wr32(device, NV_PBUS_POWERCTRL_2, 0);
 
                NVWriteCRTC(dev, head, NV_PCRTC_CURSOR_CONFIG, regp->cursor_cfg);
@@ -740,7 +742,7 @@ nv_load_state_ext(struct drm_device *dev, int head,
        }
        /* NV11 and NV20 stop at 0x52. */
        if (nv_gf4_disp_arch(dev)) {
-               if (nv_device(drm->device)->card_type == NV_10) {
+               if (nv_device(drm->device)->card_type < NV_20) {
                        /* Not waiting for vertical retrace before modifying
                           CRE_53/CRE_54 causes lockups. */
                        nouveau_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8);
diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
new file mode 100644 (file)
index 0000000..3618ac6
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2013 Ilia Mirkin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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.
+ *
+ * Implementation based on the pre-KMS implementation in xf86-video-nouveau,
+ * written by Arthur Huillet.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fourcc.h>
+
+#include "nouveau_drm.h"
+
+#include "nouveau_bo.h"
+#include "nouveau_connector.h"
+#include "nouveau_display.h"
+#include "nvreg.h"
+
+
+struct nouveau_plane {
+       struct drm_plane base;
+       bool flip;
+       struct nouveau_bo *cur;
+
+       struct {
+               struct drm_property *colorkey;
+               struct drm_property *contrast;
+               struct drm_property *brightness;
+               struct drm_property *hue;
+               struct drm_property *saturation;
+               struct drm_property *iturbt_709;
+       } props;
+
+       int colorkey;
+       int contrast;
+       int brightness;
+       int hue;
+       int saturation;
+       int iturbt_709;
+};
+
+static uint32_t formats[] = {
+       DRM_FORMAT_NV12,
+       DRM_FORMAT_UYVY,
+};
+
+/* Sine can be approximated with
+ * http://en.wikipedia.org/wiki/Bhaskara_I's_sine_approximation_formula
+ * sin(x degrees) ~= 4 x (180 - x) / (40500 - x (180 - x) )
+ * Note that this only works for the range [0, 180].
+ * Also note that sin(x) == -sin(x - 180)
+ */
+static inline int
+sin_mul(int degrees, int factor)
+{
+       if (degrees > 180) {
+               degrees -= 180;
+               factor *= -1;
+       }
+       return factor * 4 * degrees * (180 - degrees) /
+               (40500 - degrees * (180 - degrees));
+}
+
+/* cos(x) = sin(x + 90) */
+static inline int
+cos_mul(int degrees, int factor)
+{
+       return sin_mul((degrees + 90) % 360, factor);
+}
+
+static int
+nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+                 struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+                 unsigned int crtc_w, unsigned int crtc_h,
+                 uint32_t src_x, uint32_t src_y,
+                 uint32_t src_w, uint32_t src_h)
+{
+       struct nouveau_device *dev = nouveau_dev(plane->dev);
+       struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+       struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
+       struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+       struct nouveau_bo *cur = nv_plane->cur;
+       bool flip = nv_plane->flip;
+       int format = ALIGN(src_w * 4, 0x100);
+       int soff = NV_PCRTC0_SIZE * nv_crtc->index;
+       int soff2 = NV_PCRTC0_SIZE * !nv_crtc->index;
+       int ret;
+
+       if (format > 0xffff)
+               return -EINVAL;
+
+       ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM);
+       if (ret)
+               return ret;
+
+       nv_plane->cur = nv_fb->nvbo;
+
+       /* Source parameters given in 16.16 fixed point, ignore fractional. */
+       src_x = src_x >> 16;
+       src_y = src_y >> 16;
+       src_w = src_w >> 16;
+       src_h = src_h >> 16;
+
+       nv_mask(dev, NV_PCRTC_ENGINE_CTRL + soff, NV_CRTC_FSEL_OVERLAY, NV_CRTC_FSEL_OVERLAY);
+       nv_mask(dev, NV_PCRTC_ENGINE_CTRL + soff2, NV_CRTC_FSEL_OVERLAY, 0);
+
+       nv_wr32(dev, NV_PVIDEO_BASE(flip), 0);
+       nv_wr32(dev, NV_PVIDEO_OFFSET_BUFF(flip), nv_fb->nvbo->bo.offset);
+       nv_wr32(dev, NV_PVIDEO_SIZE_IN(flip), src_h << 16 | src_w);
+       nv_wr32(dev, NV_PVIDEO_POINT_IN(flip), src_y << 16 | src_x);
+       nv_wr32(dev, NV_PVIDEO_DS_DX(flip), (src_w << 20) / crtc_w);
+       nv_wr32(dev, NV_PVIDEO_DT_DY(flip), (src_h << 20) / crtc_h);
+       nv_wr32(dev, NV_PVIDEO_POINT_OUT(flip), crtc_y << 16 | crtc_x);
+       nv_wr32(dev, NV_PVIDEO_SIZE_OUT(flip), crtc_h << 16 | crtc_w);
+
+       if (fb->pixel_format == DRM_FORMAT_NV12) {
+               format |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8;
+               format |= NV_PVIDEO_FORMAT_PLANAR;
+       }
+       if (nv_plane->iturbt_709)
+               format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
+       if (nv_plane->colorkey & (1 << 24))
+               format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;
+
+       if (fb->pixel_format == DRM_FORMAT_NV12) {
+               nv_wr32(dev, NV_PVIDEO_UVPLANE_BASE(flip), 0);
+               nv_wr32(dev, NV_PVIDEO_UVPLANE_OFFSET_BUFF(flip),
+                       nv_fb->nvbo->bo.offset + fb->offsets[1]);
+       }
+       nv_wr32(dev, NV_PVIDEO_FORMAT(flip), format);
+       nv_wr32(dev, NV_PVIDEO_STOP, 0);
+       /* TODO: wait for vblank? */
+       nv_wr32(dev, NV_PVIDEO_BUFFER, flip ? 0x10 : 0x1);
+       nv_plane->flip = !flip;
+
+       if (cur)
+               nouveau_bo_unpin(cur);
+
+       return 0;
+}
+
+static int
+nv10_disable_plane(struct drm_plane *plane)
+{
+       struct nouveau_device *dev = nouveau_dev(plane->dev);
+       struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+
+       nv_wr32(dev, NV_PVIDEO_STOP, 1);
+       if (nv_plane->cur) {
+               nouveau_bo_unpin(nv_plane->cur);
+               nv_plane->cur = NULL;
+       }
+
+       return 0;
+}
+
+static void
+nv10_destroy_plane(struct drm_plane *plane)
+{
+       nv10_disable_plane(plane);
+       drm_plane_cleanup(plane);
+       kfree(plane);
+}
+
+static void
+nv10_set_params(struct nouveau_plane *plane)
+{
+       struct nouveau_device *dev = nouveau_dev(plane->base.dev);
+       u32 luma = (plane->brightness - 512) << 16 | plane->contrast;
+       u32 chroma = ((sin_mul(plane->hue, plane->saturation) & 0xffff) << 16) |
+               (cos_mul(plane->hue, plane->saturation) & 0xffff);
+       u32 format = 0;
+
+       nv_wr32(dev, NV_PVIDEO_LUMINANCE(0), luma);
+       nv_wr32(dev, NV_PVIDEO_LUMINANCE(1), luma);
+       nv_wr32(dev, NV_PVIDEO_CHROMINANCE(0), chroma);
+       nv_wr32(dev, NV_PVIDEO_CHROMINANCE(1), chroma);
+       nv_wr32(dev, NV_PVIDEO_COLOR_KEY, plane->colorkey & 0xffffff);
+
+       if (plane->cur) {
+               if (plane->iturbt_709)
+                       format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
+               if (plane->colorkey & (1 << 24))
+                       format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;
+               nv_mask(dev, NV_PVIDEO_FORMAT(plane->flip),
+                       NV_PVIDEO_FORMAT_MATRIX_ITURBT709 |
+                       NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY,
+                       format);
+       }
+}
+
+static int
+nv10_set_property(struct drm_plane *plane,
+                 struct drm_property *property,
+                 uint64_t value)
+{
+       struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+
+       if (property == nv_plane->props.colorkey)
+               nv_plane->colorkey = value;
+       else if (property == nv_plane->props.contrast)
+               nv_plane->contrast = value;
+       else if (property == nv_plane->props.brightness)
+               nv_plane->brightness = value;
+       else if (property == nv_plane->props.hue)
+               nv_plane->hue = value;
+       else if (property == nv_plane->props.saturation)
+               nv_plane->saturation = value;
+       else if (property == nv_plane->props.iturbt_709)
+               nv_plane->iturbt_709 = value;
+       else
+               return -EINVAL;
+
+       nv10_set_params(nv_plane);
+       return 0;
+}
+
+static const struct drm_plane_funcs nv10_plane_funcs = {
+       .update_plane = nv10_update_plane,
+       .disable_plane = nv10_disable_plane,
+       .set_property = nv10_set_property,
+       .destroy = nv10_destroy_plane,
+};
+
+static void
+nv10_overlay_init(struct drm_device *device)
+{
+       struct nouveau_device *dev = nouveau_dev(device);
+       struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL);
+       int ret;
+
+       if (!plane)
+               return;
+
+       ret = drm_plane_init(device, &plane->base, 3 /* both crtc's */,
+                            &nv10_plane_funcs,
+                            formats, ARRAY_SIZE(formats), false);
+       if (ret)
+               goto err;
+
+       /* Set up the plane properties */
+       plane->props.colorkey = drm_property_create_range(
+                       device, 0, "colorkey", 0, 0x01ffffff);
+       plane->props.contrast = drm_property_create_range(
+                       device, 0, "contrast", 0, 8192 - 1);
+       plane->props.brightness = drm_property_create_range(
+                       device, 0, "brightness", 0, 1024);
+       plane->props.hue = drm_property_create_range(
+                       device, 0, "hue", 0, 359);
+       plane->props.saturation = drm_property_create_range(
+                       device, 0, "saturation", 0, 8192 - 1);
+       plane->props.iturbt_709 = drm_property_create_range(
+                       device, 0, "iturbt_709", 0, 1);
+       if (!plane->props.colorkey ||
+           !plane->props.contrast ||
+           !plane->props.brightness ||
+           !plane->props.hue ||
+           !plane->props.saturation ||
+           !plane->props.iturbt_709)
+               goto cleanup;
+
+       plane->colorkey = 0;
+       drm_object_attach_property(&plane->base.base,
+                                  plane->props.colorkey, plane->colorkey);
+
+       plane->contrast = 0x1000;
+       drm_object_attach_property(&plane->base.base,
+                                  plane->props.contrast, plane->contrast);
+
+       plane->brightness = 512;
+       drm_object_attach_property(&plane->base.base,
+                                  plane->props.brightness, plane->brightness);
+
+       plane->hue = 0;
+       drm_object_attach_property(&plane->base.base,
+                                  plane->props.hue, plane->hue);
+
+       plane->saturation = 0x1000;
+       drm_object_attach_property(&plane->base.base,
+                                  plane->props.saturation, plane->saturation);
+
+       plane->iturbt_709 = 0;
+       drm_object_attach_property(&plane->base.base,
+                                  plane->props.iturbt_709, plane->iturbt_709);
+
+       nv10_set_params(plane);
+       nv_wr32(dev, NV_PVIDEO_STOP, 1);
+       return;
+cleanup:
+       drm_plane_cleanup(&plane->base);
+err:
+       kfree(plane);
+       nv_error(dev, "Failed to create plane\n");
+}
+
+void
+nouveau_overlay_init(struct drm_device *device)
+{
+       struct nouveau_device *dev = nouveau_dev(device);
+       if (dev->chipset >= 0x10 && dev->chipset <= 0x40)
+               nv10_overlay_init(device);
+}
index bf13db4..cc4b208 100644 (file)
 
 #include <subdev/i2c.h>
 
-static struct i2c_board_info nv04_tv_encoder_info[] = {
+static struct nouveau_i2c_board_info nv04_tv_encoder_info[] = {
        {
-               I2C_BOARD_INFO("ch7006", 0x75),
-               .platform_data = &(struct ch7006_encoder_params) {
-                       CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER,
-                       0, 0, 0,
-                       CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED,
-                       CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC
-               }
+               {
+                       I2C_BOARD_INFO("ch7006", 0x75),
+                       .platform_data = &(struct ch7006_encoder_params) {
+                               CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER,
+                               0, 0, 0,
+                               CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED,
+                               CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC
+                       }
+               },
+               0
        },
        { }
 };
@@ -229,7 +232,8 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
 
        /* Run the slave-specific initialization */
        ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
-                                  &port->adapter, &nv04_tv_encoder_info[type]);
+                                  &port->adapter,
+                                  &nv04_tv_encoder_info[type].dev);
        if (ret < 0)
                goto fail_cleanup;
 
index 72055a3..3621e7f 100644 (file)
@@ -87,6 +87,7 @@ nouveau_abi16_swclass(struct nouveau_drm *drm)
        case NV_04:
                return 0x006e;
        case NV_10:
+       case NV_11:
        case NV_20:
        case NV_30:
        case NV_40:
index dd7d2e1..f9a2df2 100644 (file)
@@ -317,6 +317,16 @@ static bool nouveau_dsm_detect(void)
                        has_optimus = 1;
        }
 
+       while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) {
+               vga_count++;
+
+               retval = nouveau_dsm_pci_probe(pdev);
+               if (retval & NOUVEAU_DSM_HAS_MUX)
+                       has_dsm |= 1;
+               if (retval & NOUVEAU_DSM_HAS_OPT)
+                       has_optimus = 1;
+       }
+
        /* find the optimus DSM or the old v1 DSM */
        if (has_optimus == 1) {
                acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
index 6e7a55f..2953c4e 100644 (file)
@@ -11,10 +11,28 @@ MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)");
 static int nouveau_agpmode = -1;
 module_param_named(agpmode, nouveau_agpmode, int, 0400);
 
+struct nouveau_agpmode_quirk {
+       u16 hostbridge_vendor;
+       u16 hostbridge_device;
+       u16 chip_vendor;
+       u16 chip_device;
+       int mode;
+};
+
+static struct nouveau_agpmode_quirk nouveau_agpmode_quirk_list[] = {
+       /* VIA Apollo PRO133x / GeForce FX 5600 Ultra, max agpmode 2, fdo #20341 */
+       { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 },
+
+       {},
+};
+
 static unsigned long
-get_agp_mode(struct nouveau_drm *drm, unsigned long mode)
+get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info)
 {
        struct nouveau_device *device = nv_device(drm->device);
+       struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list;
+       int agpmode = nouveau_agpmode;
+       unsigned long mode = info->mode;
 
        /*
         * FW seems to be broken on nv18, it makes the card lock up
@@ -23,12 +41,28 @@ get_agp_mode(struct nouveau_drm *drm, unsigned long mode)
        if (device->chipset == 0x18)
                mode &= ~PCI_AGP_COMMAND_FW;
 
+       /*
+        * Go through the quirks list and adjust the agpmode accordingly.
+        */
+       while (agpmode == -1 && quirk->hostbridge_vendor) {
+               if (info->id_vendor == quirk->hostbridge_vendor &&
+                   info->id_device == quirk->hostbridge_device &&
+                   device->pdev->vendor == quirk->chip_vendor &&
+                   device->pdev->device == quirk->chip_device) {
+                       agpmode = quirk->mode;
+                       nv_info(device, "Forcing agp mode to %dX. Use agpmode to override.\n",
+                               agpmode);
+                       break;
+               }
+               ++quirk;
+       }
+
        /*
         * AGP mode set in the command line.
         */
-       if (nouveau_agpmode > 0) {
+       if (agpmode > 0) {
                bool agpv3 = mode & 0x8;
-               int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode;
+               int rate = agpv3 ? agpmode / 4 : agpmode;
 
                mode = (mode & ~0x7) | (rate & 0x7);
        }
@@ -90,7 +124,7 @@ nouveau_agp_reset(struct nouveau_drm *drm)
                if (ret)
                        return;
 
-               mode.mode  = get_agp_mode(drm, info.mode);
+               mode.mode  = get_agp_mode(drm, &info);
                mode.mode &= ~PCI_AGP_COMMAND_FW;
 
                ret = drm_agp_enable(dev, mode);
@@ -139,7 +173,7 @@ nouveau_agp_init(struct nouveau_drm *drm)
        }
 
        /* see agp.h for the AGPSTAT_* modes available */
-       mode.mode = get_agp_mode(drm, info.mode);
+       mode.mode = get_agp_mode(drm, &info);
 
        ret = drm_agp_enable(dev, mode);
        if (ret) {
index 4172854..949ab0c 100644 (file)
@@ -269,7 +269,8 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
        struct nouveau_fb *pfb = nouveau_fb(drm->device);
        u32 vram_pages = pfb->ram->size >> PAGE_SHIFT;
 
-       if (nv_device(drm->device)->card_type == NV_10 &&
+       if ((nv_device(drm->device)->card_type == NV_10 ||
+            nv_device(drm->device)->card_type == NV_11) &&
            nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) &&
            nvbo->bo.mem.num_pages < vram_pages / 4) {
                /*
@@ -982,7 +983,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
                     bool no_wait_gpu, struct ttm_mem_reg *new_mem)
 {
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
-       struct nouveau_channel *chan = chan = drm->ttm.chan;
+       struct nouveau_channel *chan = drm->ttm.chan;
        struct nouveau_bo *nvbo = nouveau_bo(bo);
        struct ttm_mem_reg *old_mem = &bo->mem;
        int ret;
index 2136d00..1674882 100644 (file)
@@ -100,6 +100,7 @@ static void
 nouveau_connector_destroy(struct drm_connector *connector)
 {
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
+       nouveau_event_ref(NULL, &nv_connector->hpd_func);
        kfree(nv_connector->edid);
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
@@ -214,9 +215,10 @@ nouveau_connector_set_encoder(struct drm_connector *connector,
        } else {
                connector->doublescan_allowed = true;
                if (nv_device(drm->device)->card_type == NV_20 ||
-                  (nv_device(drm->device)->card_type == NV_10 &&
-                   (dev->pdev->device & 0x0ff0) != 0x0100 &&
-                   (dev->pdev->device & 0x0ff0) != 0x0150))
+                   ((nv_device(drm->device)->card_type == NV_10 ||
+                     nv_device(drm->device)->card_type == NV_11) &&
+                    (dev->pdev->device & 0x0ff0) != 0x0100 &&
+                    (dev->pdev->device & 0x0ff0) != 0x0150))
                        /* HW is broken */
                        connector->interlace_allowed = false;
                else
@@ -932,10 +934,9 @@ nouveau_connector_hotplug_work(struct work_struct *work)
 }
 
 static int
-nouveau_connector_hotplug(struct nouveau_eventh *event, int index)
+nouveau_connector_hotplug(void *data, int index)
 {
-       struct nouveau_connector *nv_connector =
-               container_of(event, struct nouveau_connector, hpd_func);
+       struct nouveau_connector *nv_connector = data;
        schedule_work(&nv_connector->hpd_work);
        return NVKM_EVENT_KEEP;
 }
@@ -1007,10 +1008,16 @@ nouveau_connector_create(struct drm_device *dev, int index)
 
                ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)],
                                 DCB_GPIO_UNUSED, &nv_connector->hpd);
-               nv_connector->hpd_func.func = nouveau_connector_hotplug;
                if (ret)
                        nv_connector->hpd.func = DCB_GPIO_UNUSED;
 
+               if (nv_connector->hpd.func != DCB_GPIO_UNUSED) {
+                       nouveau_event_new(gpio->events, nv_connector->hpd.line,
+                                         nouveau_connector_hotplug,
+                                         nv_connector,
+                                        &nv_connector->hpd_func);
+               }
+
                nv_connector->type = nv_connector->dcb[0];
                if (drm_conntype_from_dcb(nv_connector->type) ==
                                          DRM_MODE_CONNECTOR_Unknown) {
index 6e399aa..264a778 100644 (file)
@@ -69,7 +69,7 @@ struct nouveau_connector {
 
        struct dcb_gpio_func hpd;
        struct work_struct hpd_work;
-       struct nouveau_eventh hpd_func;
+       struct nouveau_eventh *hpd_func;
 
        int dithering_mode;
        int dithering_depth;
@@ -107,7 +107,4 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
 struct drm_connector *
 nouveau_connector_create(struct drm_device *, int index);
 
-int
-nouveau_connector_bpp(struct drm_connector *);
-
 #endif /* __NOUVEAU_CONNECTOR_H__ */
index bdd5cf7..44642d9 100644 (file)
 
 #include "nouveau_fence.h"
 
-#include <subdev/bios/gpio.h>
-#include <subdev/gpio.h>
 #include <engine/disp.h>
 
 #include <core/class.h>
 
+static int
+nouveau_display_vblank_handler(void *data, int head)
+{
+       struct nouveau_drm *drm = data;
+       drm_handle_vblank(drm->dev, head);
+       return NVKM_EVENT_KEEP;
+}
+
+int
+nouveau_display_vblank_enable(struct drm_device *dev, int head)
+{
+       struct nouveau_display *disp = nouveau_display(dev);
+       if (disp) {
+               nouveau_event_get(disp->vblank[head]);
+               return 0;
+       }
+       return -EIO;
+}
+
+void
+nouveau_display_vblank_disable(struct drm_device *dev, int head)
+{
+       struct nouveau_display *disp = nouveau_display(dev);
+       if (disp)
+               nouveau_event_put(disp->vblank[head]);
+}
+
+static void
+nouveau_display_vblank_fini(struct drm_device *dev)
+{
+       struct nouveau_display *disp = nouveau_display(dev);
+       int i;
+
+       if (disp->vblank) {
+               for (i = 0; i < dev->mode_config.num_crtc; i++)
+                       nouveau_event_ref(NULL, &disp->vblank[i]);
+               kfree(disp->vblank);
+               disp->vblank = NULL;
+       }
+
+       drm_vblank_cleanup(dev);
+}
+
+static int
+nouveau_display_vblank_init(struct drm_device *dev)
+{
+       struct nouveau_display *disp = nouveau_display(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_disp *pdisp = nouveau_disp(drm->device);
+       int ret, i;
+
+       disp->vblank = kzalloc(dev->mode_config.num_crtc *
+                              sizeof(*disp->vblank), GFP_KERNEL);
+       if (!disp->vblank)
+               return -ENOMEM;
+
+       for (i = 0; i < dev->mode_config.num_crtc; i++) {
+               ret = nouveau_event_new(pdisp->vblank, i,
+                                       nouveau_display_vblank_handler,
+                                       drm, &disp->vblank[i]);
+               if (ret) {
+                       nouveau_display_vblank_fini(dev);
+                       return ret;
+               }
+       }
+
+       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+       if (ret) {
+               nouveau_display_vblank_fini(dev);
+               return ret;
+       }
+
+       return 0;
+}
+
 static void
 nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
 {
@@ -227,9 +300,7 @@ static struct nouveau_drm_prop_enum_list dither_depth[] = {
 int
 nouveau_display_init(struct drm_device *dev)
 {
-       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_display *disp = nouveau_display(dev);
-       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
        struct drm_connector *connector;
        int ret;
 
@@ -243,10 +314,7 @@ nouveau_display_init(struct drm_device *dev)
        /* enable hotplug interrupts */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct nouveau_connector *conn = nouveau_connector(connector);
-               if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
-                       nouveau_event_get(gpio->events, conn->hpd.line,
-                                        &conn->hpd_func);
-               }
+               if (conn->hpd_func) nouveau_event_get(conn->hpd_func);
        }
 
        return ret;
@@ -255,18 +323,13 @@ nouveau_display_init(struct drm_device *dev)
 void
 nouveau_display_fini(struct drm_device *dev)
 {
-       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_display *disp = nouveau_display(dev);
-       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
        struct drm_connector *connector;
 
        /* disable hotplug interrupts */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct nouveau_connector *conn = nouveau_connector(connector);
-               if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
-                       nouveau_event_put(gpio->events, conn->hpd.line,
-                                        &conn->hpd_func);
-               }
+               if (conn->hpd_func) nouveau_event_put(conn->hpd_func);
        }
 
        drm_kms_helper_poll_disable(dev);
@@ -352,7 +415,7 @@ nouveau_display_create(struct drm_device *dev)
                goto disp_create_err;
 
        if (dev->mode_config.num_crtc) {
-               ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+               ret = nouveau_display_vblank_init(dev);
                if (ret)
                        goto vblank_err;
        }
@@ -374,7 +437,7 @@ nouveau_display_destroy(struct drm_device *dev)
        struct nouveau_display *disp = nouveau_display(dev);
 
        nouveau_backlight_exit(dev);
-       drm_vblank_cleanup(dev);
+       nouveau_display_vblank_fini(dev);
 
        drm_kms_helper_poll_fini(dev);
        drm_mode_config_cleanup(dev);
@@ -394,7 +457,7 @@ nouveau_display_suspend(struct drm_device *dev)
 
        nouveau_display_fini(dev);
 
-       NV_SUSPEND(drm, "unpinning framebuffer(s)...\n");
+       NV_INFO(drm, "unpinning framebuffer(s)...\n");
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_framebuffer *nouveau_fb;
 
index 025c66f..8bc8bab 100644 (file)
@@ -36,6 +36,8 @@ struct nouveau_display {
        int  (*init)(struct drm_device *);
        void (*fini)(struct drm_device *);
 
+       struct nouveau_eventh **vblank;
+
        struct drm_property *dithering_mode;
        struct drm_property *dithering_depth;
        struct drm_property *underscan_property;
@@ -59,6 +61,8 @@ void nouveau_display_fini(struct drm_device *dev);
 int  nouveau_display_suspend(struct drm_device *dev);
 void nouveau_display_repin(struct drm_device *dev);
 void nouveau_display_resume(struct drm_device *dev);
+int  nouveau_display_vblank_enable(struct drm_device *, int);
+void nouveau_display_vblank_disable(struct drm_device *, int);
 
 int  nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                            struct drm_pending_vblank_event *event,
index 428d818..2418b0d 100644 (file)
@@ -46,7 +46,8 @@
 #include "nouveau_gem.h"
 #include "nouveau_agp.h"
 #include "nouveau_vga.h"
-#include "nouveau_pm.h"
+#include "nouveau_sysfs.h"
+#include "nouveau_hwmon.h"
 #include "nouveau_acpi.h"
 #include "nouveau_bios.h"
 #include "nouveau_ioctl.h"
@@ -78,41 +79,6 @@ module_param_named(runpm, nouveau_runtime_pm, int, 0400);
 
 static struct drm_driver driver;
 
-static int
-nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head)
-{
-       struct nouveau_drm *drm =
-               container_of(event, struct nouveau_drm, vblank[head]);
-       drm_handle_vblank(drm->dev, head);
-       return NVKM_EVENT_KEEP;
-}
-
-static int
-nouveau_drm_vblank_enable(struct drm_device *dev, int head)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_disp *pdisp = nouveau_disp(drm->device);
-
-       if (WARN_ON_ONCE(head > ARRAY_SIZE(drm->vblank)))
-               return -EIO;
-       WARN_ON_ONCE(drm->vblank[head].func);
-       drm->vblank[head].func = nouveau_drm_vblank_handler;
-       nouveau_event_get(pdisp->vblank, head, &drm->vblank[head]);
-       return 0;
-}
-
-static void
-nouveau_drm_vblank_disable(struct drm_device *dev, int head)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_disp *pdisp = nouveau_disp(drm->device);
-       if (drm->vblank[head].func)
-               nouveau_event_put(pdisp->vblank, head, &drm->vblank[head]);
-       else
-               WARN_ON_ONCE(1);
-       drm->vblank[head].func = NULL;
-}
-
 static u64
 nouveau_name(struct pci_dev *pdev)
 {
@@ -177,7 +143,8 @@ nouveau_accel_init(struct nouveau_drm *drm)
 
        /* initialise synchronisation routines */
        if      (device->card_type < NV_10) ret = nv04_fence_create(drm);
-       else if (device->chipset   <  0x17) ret = nv10_fence_create(drm);
+       else if (device->card_type < NV_11 ||
+                device->chipset   <  0x17) ret = nv10_fence_create(drm);
        else if (device->card_type < NV_50) ret = nv17_fence_create(drm);
        else if (device->chipset   <  0x84) ret = nv50_fence_create(drm);
        else if (device->card_type < NV_C0) ret = nv84_fence_create(drm);
@@ -418,8 +385,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
                        goto fail_dispinit;
        }
 
-       nouveau_pm_init(dev);
-
+       nouveau_sysfs_init(dev);
+       nouveau_hwmon_init(dev);
        nouveau_accel_init(drm);
        nouveau_fbcon_init(dev);
 
@@ -455,8 +422,8 @@ nouveau_drm_unload(struct drm_device *dev)
        pm_runtime_get_sync(dev->dev);
        nouveau_fbcon_fini(dev);
        nouveau_accel_fini(drm);
-
-       nouveau_pm_fini(dev);
+       nouveau_hwmon_fini(dev);
+       nouveau_sysfs_fini(dev);
 
        if (dev->mode_config.num_crtc)
                nouveau_display_fini(dev);
@@ -496,16 +463,16 @@ nouveau_do_suspend(struct drm_device *dev)
        int ret;
 
        if (dev->mode_config.num_crtc) {
-               NV_SUSPEND(drm, "suspending display...\n");
+               NV_INFO(drm, "suspending display...\n");
                ret = nouveau_display_suspend(dev);
                if (ret)
                        return ret;
        }
 
-       NV_SUSPEND(drm, "evicting buffers...\n");
+       NV_INFO(drm, "evicting buffers...\n");
        ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM);
 
-       NV_SUSPEND(drm, "waiting for kernel channels to go idle...\n");
+       NV_INFO(drm, "waiting for kernel channels to go idle...\n");
        if (drm->cechan) {
                ret = nouveau_channel_idle(drm->cechan);
                if (ret)
@@ -518,7 +485,7 @@ nouveau_do_suspend(struct drm_device *dev)
                        return ret;
        }
 
-       NV_SUSPEND(drm, "suspending client object trees...\n");
+       NV_INFO(drm, "suspending client object trees...\n");
        if (drm->fence && nouveau_fence(drm)->suspend) {
                if (!nouveau_fence(drm)->suspend(drm))
                        return -ENOMEM;
@@ -530,7 +497,7 @@ nouveau_do_suspend(struct drm_device *dev)
                        goto fail_client;
        }
 
-       NV_SUSPEND(drm, "suspending kernel object tree...\n");
+       NV_INFO(drm, "suspending kernel object tree...\n");
        ret = nouveau_client_fini(&drm->client.base, true);
        if (ret)
                goto fail_client;
@@ -544,7 +511,7 @@ fail_client:
        }
 
        if (dev->mode_config.num_crtc) {
-               NV_SUSPEND(drm, "resuming display...\n");
+               NV_INFO(drm, "resuming display...\n");
                nouveau_display_resume(dev);
        }
        return ret;
@@ -563,7 +530,6 @@ int nouveau_pmops_suspend(struct device *dev)
        if (drm_dev->mode_config.num_crtc)
                nouveau_fbcon_set_suspend(drm_dev, 1);
 
-       nv_suspend_set_printk_level(NV_DBG_INFO);
        ret = nouveau_do_suspend(drm_dev);
        if (ret)
                return ret;
@@ -571,8 +537,6 @@ int nouveau_pmops_suspend(struct device *dev)
        pci_save_state(pdev);
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
-       nv_suspend_set_printk_level(NV_DBG_DEBUG);
-
        return 0;
 }
 
@@ -582,15 +546,15 @@ nouveau_do_resume(struct drm_device *dev)
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_cli *cli;
 
-       NV_SUSPEND(drm, "re-enabling device...\n");
+       NV_INFO(drm, "re-enabling device...\n");
 
        nouveau_agp_reset(drm);
 
-       NV_SUSPEND(drm, "resuming kernel object tree...\n");
+       NV_INFO(drm, "resuming kernel object tree...\n");
        nouveau_client_init(&drm->client.base);
        nouveau_agp_init(drm);
 
-       NV_SUSPEND(drm, "resuming client object trees...\n");
+       NV_INFO(drm, "resuming client object trees...\n");
        if (drm->fence && nouveau_fence(drm)->resume)
                nouveau_fence(drm)->resume(drm);
 
@@ -599,10 +563,9 @@ nouveau_do_resume(struct drm_device *dev)
        }
 
        nouveau_run_vbios_init(dev);
-       nouveau_pm_resume(dev);
 
        if (dev->mode_config.num_crtc) {
-               NV_SUSPEND(drm, "resuming display...\n");
+               NV_INFO(drm, "resuming display...\n");
                nouveau_display_repin(dev);
        }
 
@@ -626,19 +589,15 @@ int nouveau_pmops_resume(struct device *dev)
                return ret;
        pci_set_master(pdev);
 
-       nv_suspend_set_printk_level(NV_DBG_INFO);
        ret = nouveau_do_resume(drm_dev);
-       if (ret) {
-               nv_suspend_set_printk_level(NV_DBG_DEBUG);
+       if (ret)
                return ret;
-       }
        if (drm_dev->mode_config.num_crtc)
                nouveau_fbcon_set_suspend(drm_dev, 0);
 
        nouveau_fbcon_zfill_all(drm_dev);
        if (drm_dev->mode_config.num_crtc)
                nouveau_display_resume(drm_dev);
-       nv_suspend_set_printk_level(NV_DBG_DEBUG);
        return 0;
 }
 
@@ -648,12 +607,10 @@ static int nouveau_pmops_freeze(struct device *dev)
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        int ret;
 
-       nv_suspend_set_printk_level(NV_DBG_INFO);
        if (drm_dev->mode_config.num_crtc)
                nouveau_fbcon_set_suspend(drm_dev, 1);
 
        ret = nouveau_do_suspend(drm_dev);
-       nv_suspend_set_printk_level(NV_DBG_DEBUG);
        return ret;
 }
 
@@ -663,18 +620,14 @@ static int nouveau_pmops_thaw(struct device *dev)
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        int ret;
 
-       nv_suspend_set_printk_level(NV_DBG_INFO);
        ret = nouveau_do_resume(drm_dev);
-       if (ret) {
-               nv_suspend_set_printk_level(NV_DBG_DEBUG);
+       if (ret)
                return ret;
-       }
        if (drm_dev->mode_config.num_crtc)
                nouveau_fbcon_set_suspend(drm_dev, 0);
        nouveau_fbcon_zfill_all(drm_dev);
        if (drm_dev->mode_config.num_crtc)
                nouveau_display_resume(drm_dev);
-       nv_suspend_set_printk_level(NV_DBG_DEBUG);
        return 0;
 }
 
@@ -816,8 +769,8 @@ driver = {
 #endif
 
        .get_vblank_counter = drm_vblank_count,
-       .enable_vblank = nouveau_drm_vblank_enable,
-       .disable_vblank = nouveau_drm_vblank_disable,
+       .enable_vblank = nouveau_display_vblank_enable,
+       .disable_vblank = nouveau_display_vblank_disable,
 
        .ioctls = nouveau_ioctls,
        .num_ioctls = ARRAY_SIZE(nouveau_ioctls),
@@ -878,6 +831,7 @@ static int nouveau_pmops_runtime_suspend(struct device *dev)
        if (nouveau_runtime_pm == 0)
                return -EINVAL;
 
+       nv_debug_level(SILENT);
        drm_kms_helper_poll_disable(drm_dev);
        vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
        nouveau_switcheroo_optimus_dsm();
@@ -914,6 +868,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev)
        nv_mask(device, 0x88488, (1 << 25), (1 << 25));
        vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
        drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
+       nv_debug_level(NORMAL);
        return ret;
 }
 
index 994fd6e..71ed2da 100644 (file)
@@ -51,10 +51,11 @@ struct nouveau_drm_tile {
 };
 
 enum nouveau_drm_handle {
-       NVDRM_CLIENT = 0xffffffff,
-       NVDRM_DEVICE = 0xdddddddd,
-       NVDRM_PUSH   = 0xbbbb0000, /* |= client chid */
-       NVDRM_CHAN   = 0xcccc0000, /* |= client chid */
+       NVDRM_CLIENT  = 0xffffffff,
+       NVDRM_DEVICE  = 0xdddddddd,
+       NVDRM_CONTROL = 0xdddddddc,
+       NVDRM_PUSH    = 0xbbbb0000, /* |= client chid */
+       NVDRM_CHAN    = 0xcccc0000, /* |= client chid */
 };
 
 struct nouveau_cli {
@@ -127,10 +128,10 @@ struct nouveau_drm {
        struct nvbios vbios;
        struct nouveau_display *display;
        struct backlight_device *backlight;
-       struct nouveau_eventh vblank[4];
 
        /* power management */
-       struct nouveau_pm *pm;
+       struct nouveau_hwmon *hwmon;
+       struct nouveau_sysfs *sysfs;
 
        /* display power reference */
        bool have_disp_power_ref;
@@ -154,7 +155,6 @@ nouveau_dev(struct drm_device *dev)
 int nouveau_pmops_suspend(struct device *);
 int nouveau_pmops_resume(struct device *);
 
-#define NV_SUSPEND(cli, fmt, args...) nv_suspend((cli), fmt, ##args)
 #define NV_FATAL(cli, fmt, args...) nv_fatal((cli), fmt, ##args)
 #define NV_ERROR(cli, fmt, args...) nv_error((cli), fmt, ##args)
 #define NV_WARN(cli, fmt, args...) nv_warn((cli), fmt, ##args)
index c80b519..7903e0e 100644 (file)
@@ -503,34 +503,45 @@ nouveau_fbcon_fini(struct drm_device *dev)
        drm->fbcon = NULL;
 }
 
-void nouveau_fbcon_save_disable_accel(struct drm_device *dev)
+void
+nouveau_fbcon_save_disable_accel(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-
-       drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
-       drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+       if (drm->fbcon) {
+               drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
+               drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+       }
 }
 
-void nouveau_fbcon_restore_accel(struct drm_device *dev)
+void
+nouveau_fbcon_restore_accel(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
+       if (drm->fbcon) {
+               drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
+       }
 }
 
-void nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
+void
+nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       console_lock();
-       if (state == 0)
-               nouveau_fbcon_save_disable_accel(dev);
-       fb_set_suspend(drm->fbcon->helper.fbdev, state);
-       if (state == 1)
-               nouveau_fbcon_restore_accel(dev);
-       console_unlock();
+       if (drm->fbcon) {
+               console_lock();
+               if (state == 0)
+                       nouveau_fbcon_save_disable_accel(dev);
+               fb_set_suspend(drm->fbcon->helper.fbdev, state);
+               if (state == 1)
+                       nouveau_fbcon_restore_accel(dev);
+               console_unlock();
+       }
 }
 
-void nouveau_fbcon_zfill_all(struct drm_device *dev)
+void
+nouveau_fbcon_zfill_all(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       nouveau_fbcon_zfill(dev, drm->fbcon);
+       if (drm->fbcon) {
+               nouveau_fbcon_zfill(dev, drm->fbcon);
+       }
 }
index be31499..34b8271 100644 (file)
@@ -165,17 +165,11 @@ nouveau_fence_done(struct nouveau_fence *fence)
        return !fence->channel;
 }
 
-struct nouveau_fence_uevent {
-       struct nouveau_eventh handler;
-       struct nouveau_fence_priv *priv;
-};
-
 static int
-nouveau_fence_wait_uevent_handler(struct nouveau_eventh *event, int index)
+nouveau_fence_wait_uevent_handler(void *data, int index)
 {
-       struct nouveau_fence_uevent *uevent =
-               container_of(event, struct nouveau_fence_uevent, handler);
-       wake_up_all(&uevent->priv->waiting);
+       struct nouveau_fence_priv *priv = data;
+       wake_up_all(&priv->waiting);
        return NVKM_EVENT_KEEP;
 }
 
@@ -186,13 +180,16 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
        struct nouveau_channel *chan = fence->channel;
        struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device);
        struct nouveau_fence_priv *priv = chan->drm->fence;
-       struct nouveau_fence_uevent uevent = {
-               .handler.func = nouveau_fence_wait_uevent_handler,
-               .priv = priv,
-       };
+       struct nouveau_eventh *handler;
        int ret = 0;
 
-       nouveau_event_get(pfifo->uevent, 0, &uevent.handler);
+       ret = nouveau_event_new(pfifo->uevent, 0,
+                               nouveau_fence_wait_uevent_handler,
+                               priv, &handler);
+       if (ret)
+               return ret;
+
+       nouveau_event_get(handler);
 
        if (fence->timeout) {
                unsigned long timeout = fence->timeout - jiffies;
@@ -224,7 +221,7 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
                }
        }
 
-       nouveau_event_put(pfifo->uevent, 0, &uevent.handler);
+       nouveau_event_ref(NULL, &handler);
        if (unlikely(ret < 0))
                return ret;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
new file mode 100644 (file)
index 0000000..38a4db5
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#endif
+#include <linux/power_supply.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <drm/drmP.h>
+
+#include "nouveau_drm.h"
+#include "nouveau_hwmon.h"
+
+#include <subdev/gpio.h>
+#include <subdev/timer.h>
+#include <subdev/therm.h>
+
+#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
+static ssize_t
+nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       int temp = therm->temp_get(therm);
+
+       if (temp < 0)
+               return temp;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", temp * 1000);
+}
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
+                                                 NULL, 0);
+
+static ssize_t
+nouveau_hwmon_show_temp1_auto_point1_pwm(struct device *d,
+                                        struct device_attribute *a, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", 100);
+}
+static SENSOR_DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO,
+                         nouveau_hwmon_show_temp1_auto_point1_pwm, NULL, 0);
+
+static ssize_t
+nouveau_hwmon_temp1_auto_point1_temp(struct device *d,
+                                    struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+             therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST) * 1000);
+}
+static ssize_t
+nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d,
+                                        struct device_attribute *a,
+                                        const char *buf, size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return count;
+
+       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST,
+                       value / 1000);
+
+       return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_temp1_auto_point1_temp,
+                         nouveau_hwmon_set_temp1_auto_point1_temp, 0);
+
+static ssize_t
+nouveau_hwmon_temp1_auto_point1_temp_hyst(struct device *d,
+                                         struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+        therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000);
+}
+static ssize_t
+nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d,
+                                             struct device_attribute *a,
+                                             const char *buf, size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return count;
+
+       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST,
+                       value / 1000);
+
+       return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_temp1_auto_point1_temp_hyst,
+                         nouveau_hwmon_set_temp1_auto_point1_temp_hyst, 0);
+
+static ssize_t
+nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+              therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK) * 1000);
+}
+static ssize_t
+nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
+                                               const char *buf, size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return count;
+
+       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK, value / 1000);
+
+       return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp,
+                                                 nouveau_hwmon_set_max_temp,
+                                                 0);
+
+static ssize_t
+nouveau_hwmon_max_temp_hyst(struct device *d, struct device_attribute *a,
+                           char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+         therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000);
+}
+static ssize_t
+nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a,
+                                               const char *buf, size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return count;
+
+       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST,
+                       value / 1000);
+
+       return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_max_temp_hyst,
+                         nouveau_hwmon_set_max_temp_hyst, 0);
+
+static ssize_t
+nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
+                                                       char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+              therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL) * 1000);
+}
+static ssize_t
+nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
+                                                           const char *buf,
+                                                               size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return count;
+
+       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL, value / 1000);
+
+       return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
+                                               nouveau_hwmon_critical_temp,
+                                               nouveau_hwmon_set_critical_temp,
+                                               0);
+
+static ssize_t
+nouveau_hwmon_critical_temp_hyst(struct device *d, struct device_attribute *a,
+                                                       char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+         therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST) * 1000);
+}
+static ssize_t
+nouveau_hwmon_set_critical_temp_hyst(struct device *d,
+                                    struct device_attribute *a,
+                                    const char *buf,
+                                    size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return count;
+
+       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST,
+                       value / 1000);
+
+       return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_critical_temp_hyst,
+                         nouveau_hwmon_set_critical_temp_hyst, 0);
+static ssize_t
+nouveau_hwmon_emergency_temp(struct device *d, struct device_attribute *a,
+                                                       char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+              therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN) * 1000);
+}
+static ssize_t
+nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a,
+                                                           const char *buf,
+                                                               size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return count;
+
+       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN, value / 1000);
+
+       return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO | S_IWUSR,
+                                       nouveau_hwmon_emergency_temp,
+                                       nouveau_hwmon_set_emergency_temp,
+                                       0);
+
+static ssize_t
+nouveau_hwmon_emergency_temp_hyst(struct device *d, struct device_attribute *a,
+                                                       char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+         therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000);
+}
+static ssize_t
+nouveau_hwmon_set_emergency_temp_hyst(struct device *d,
+                                     struct device_attribute *a,
+                                     const char *buf,
+                                     size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return count;
+
+       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST,
+                       value / 1000);
+
+       return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO | S_IWUSR,
+                                       nouveau_hwmon_emergency_temp_hyst,
+                                       nouveau_hwmon_set_emergency_temp_hyst,
+                                       0);
+
+static ssize_t nouveau_hwmon_show_name(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       return sprintf(buf, "nouveau\n");
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0);
+
+static ssize_t nouveau_hwmon_show_update_rate(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       return sprintf(buf, "1000\n");
+}
+static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO,
+                                               nouveau_hwmon_show_update_rate,
+                                               NULL, 0);
+
+static ssize_t
+nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr,
+                             char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm));
+}
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, nouveau_hwmon_show_fan1_input,
+                         NULL, 0);
+
+ static ssize_t
+nouveau_hwmon_get_pwm1_enable(struct device *d,
+                          struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       int ret;
+
+       ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MODE);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t
+nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a,
+                          const char *buf, size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+       int ret;
+
+       if (strict_strtol(buf, 10, &value) == -EINVAL)
+               return -EINVAL;
+
+       ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value);
+       if (ret)
+               return ret;
+       else
+               return count;
+}
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_get_pwm1_enable,
+                         nouveau_hwmon_set_pwm1_enable, 0);
+
+static ssize_t
+nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       int ret;
+
+       ret = therm->fan_get(therm);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t
+nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a,
+                      const char *buf, size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       int ret = -ENODEV;
+       long value;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return -EINVAL;
+
+       ret = therm->fan_set(therm, value);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_get_pwm1,
+                         nouveau_hwmon_set_pwm1, 0);
+
+static ssize_t
+nouveau_hwmon_get_pwm1_min(struct device *d,
+                          struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       int ret;
+
+       ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t
+nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a,
+                          const char *buf, size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+       int ret;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return -EINVAL;
+
+       ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY, value);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_get_pwm1_min,
+                         nouveau_hwmon_set_pwm1_min, 0);
+
+static ssize_t
+nouveau_hwmon_get_pwm1_max(struct device *d,
+                          struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       int ret;
+
+       ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t
+nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a,
+                          const char *buf, size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+       int ret;
+
+       if (kstrtol(buf, 10, &value) == -EINVAL)
+               return -EINVAL;
+
+       ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY, value);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_get_pwm1_max,
+                         nouveau_hwmon_set_pwm1_max, 0);
+
+static struct attribute *hwmon_default_attributes[] = {
+       &sensor_dev_attr_name.dev_attr.attr,
+       &sensor_dev_attr_update_rate.dev_attr.attr,
+       NULL
+};
+static struct attribute *hwmon_temp_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_emergency.dev_attr.attr,
+       &sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr,
+       NULL
+};
+static struct attribute *hwmon_fan_rpm_attributes[] = {
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       NULL
+};
+static struct attribute *hwmon_pwm_fan_attributes[] = {
+       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm1_min.dev_attr.attr,
+       &sensor_dev_attr_pwm1_max.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group hwmon_default_attrgroup = {
+       .attrs = hwmon_default_attributes,
+};
+static const struct attribute_group hwmon_temp_attrgroup = {
+       .attrs = hwmon_temp_attributes,
+};
+static const struct attribute_group hwmon_fan_rpm_attrgroup = {
+       .attrs = hwmon_fan_rpm_attributes,
+};
+static const struct attribute_group hwmon_pwm_fan_attrgroup = {
+       .attrs = hwmon_pwm_fan_attributes,
+};
+#endif
+
+int
+nouveau_hwmon_init(struct drm_device *dev)
+{
+#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       struct nouveau_hwmon *hwmon;
+       struct device *hwmon_dev;
+       int ret = 0;
+
+       hwmon = drm->hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL);
+       if (!hwmon)
+               return -ENOMEM;
+       hwmon->dev = dev;
+
+       if (!therm || !therm->temp_get || !therm->attr_get || !therm->attr_set)
+               return -ENODEV;
+
+       hwmon_dev = hwmon_device_register(&dev->pdev->dev);
+       if (IS_ERR(hwmon_dev)) {
+               ret = PTR_ERR(hwmon_dev);
+               NV_ERROR(drm, "Unable to register hwmon device: %d\n", ret);
+               return ret;
+       }
+       dev_set_drvdata(hwmon_dev, dev);
+
+       /* set the default attributes */
+       ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_default_attrgroup);
+       if (ret) {
+               if (ret)
+                       goto error;
+       }
+
+       /* if the card has a working thermal sensor */
+       if (therm->temp_get(therm) >= 0) {
+               ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup);
+               if (ret) {
+                       if (ret)
+                               goto error;
+               }
+       }
+
+       /* if the card has a pwm fan */
+       /*XXX: incorrect, need better detection for this, some boards have
+        *     the gpio entries for pwm fan control even when there's no
+        *     actual fan connected to it... therm table? */
+       if (therm->fan_get && therm->fan_get(therm) >= 0) {
+               ret = sysfs_create_group(&hwmon_dev->kobj,
+                                        &hwmon_pwm_fan_attrgroup);
+               if (ret)
+                       goto error;
+       }
+
+       /* if the card can read the fan rpm */
+       if (therm->fan_sense(therm) >= 0) {
+               ret = sysfs_create_group(&hwmon_dev->kobj,
+                                        &hwmon_fan_rpm_attrgroup);
+               if (ret)
+                       goto error;
+       }
+
+       hwmon->hwmon = hwmon_dev;
+
+       return 0;
+
+error:
+       NV_ERROR(drm, "Unable to create some hwmon sysfs files: %d\n", ret);
+       hwmon_device_unregister(hwmon_dev);
+       hwmon->hwmon = NULL;
+       return ret;
+#else
+       hwmon->hwmon = NULL;
+       return 0;
+#endif
+}
+
+void
+nouveau_hwmon_fini(struct drm_device *dev)
+{
+#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
+       struct nouveau_hwmon *hwmon = nouveau_hwmon(dev);
+
+       if (hwmon->hwmon) {
+               sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_default_attrgroup);
+               sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_temp_attrgroup);
+               sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_pwm_fan_attrgroup);
+               sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_fan_rpm_attrgroup);
+
+               hwmon_device_unregister(hwmon->hwmon);
+       }
+
+       nouveau_drm(dev)->hwmon = NULL;
+       kfree(hwmon);
+#endif
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.h b/drivers/gpu/drm/nouveau/nouveau_hwmon.h
new file mode 100644 (file)
index 0000000..62ccbb3
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifndef __NOUVEAU_PM_H__
+#define __NOUVEAU_PM_H__
+
+struct nouveau_hwmon {
+       struct drm_device *dev;
+       struct device *hwmon;
+};
+
+static inline struct nouveau_hwmon *
+nouveau_hwmon(struct drm_device *dev)
+{
+       return nouveau_drm(dev)->hwmon;
+}
+
+/* nouveau_hwmon.c */
+int  nouveau_hwmon_init(struct drm_device *dev);
+void nouveau_hwmon_fini(struct drm_device *dev);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_hwsq.h b/drivers/gpu/drm/nouveau/nouveau_hwsq.h
deleted file mode 100644 (file)
index 6976875..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#ifndef __NOUVEAU_HWSQ_H__
-#define __NOUVEAU_HWSQ_H__
-
-struct hwsq_ucode {
-       u8 data[0x200];
-       union {
-               u8  *u08;
-               u16 *u16;
-               u32 *u32;
-       } ptr;
-       u16 len;
-
-       u32 reg;
-       u32 val;
-};
-
-static inline void
-hwsq_init(struct hwsq_ucode *hwsq)
-{
-       hwsq->ptr.u08 = hwsq->data;
-       hwsq->reg = 0xffffffff;
-       hwsq->val = 0xffffffff;
-}
-
-static inline void
-hwsq_fini(struct hwsq_ucode *hwsq)
-{
-       do {
-               *hwsq->ptr.u08++ = 0x7f;
-               hwsq->len = hwsq->ptr.u08 - hwsq->data;
-       } while (hwsq->len & 3);
-       hwsq->ptr.u08 = hwsq->data;
-}
-
-static inline void
-hwsq_usec(struct hwsq_ucode *hwsq, u8 usec)
-{
-       u32 shift = 0;
-       while (usec & ~3) {
-               usec >>= 2;
-               shift++;
-       }
-
-       *hwsq->ptr.u08++ = (shift << 2) | usec;
-}
-
-static inline void
-hwsq_setf(struct hwsq_ucode *hwsq, u8 flag, int val)
-{
-       flag += 0x80;
-       if (val >= 0)
-               flag += 0x20;
-       if (val >= 1)
-               flag += 0x20;
-       *hwsq->ptr.u08++ = flag;
-}
-
-static inline void
-hwsq_op5f(struct hwsq_ucode *hwsq, u8 v0, u8 v1)
-{
-       *hwsq->ptr.u08++ = 0x5f;
-       *hwsq->ptr.u08++ = v0;
-       *hwsq->ptr.u08++ = v1;
-}
-
-static inline void
-hwsq_wr32(struct hwsq_ucode *hwsq, u32 reg, u32 val)
-{
-       if (val != hwsq->val) {
-               if ((val & 0xffff0000) == (hwsq->val & 0xffff0000)) {
-                       *hwsq->ptr.u08++ = 0x42;
-                       *hwsq->ptr.u16++ = (val & 0x0000ffff);
-               } else {
-                       *hwsq->ptr.u08++ = 0xe2;
-                       *hwsq->ptr.u32++ = val;
-               }
-
-               hwsq->val = val;
-       }
-
-       if ((reg & 0xffff0000) == (hwsq->reg & 0xffff0000)) {
-               *hwsq->ptr.u08++ = 0x40;
-               *hwsq->ptr.u16++ = (reg & 0x0000ffff);
-       } else {
-               *hwsq->ptr.u08++ = 0xe0;
-               *hwsq->ptr.u32++ = reg;
-       }
-       hwsq->reg = reg;
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
deleted file mode 100644 (file)
index 4f6a572..0000000
+++ /dev/null
@@ -1,647 +0,0 @@
-/*
- * Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
- * Copyright 2005 Stephane Marchesin
- *
- * The Weather Channel (TM) funded Tungsten Graphics to develop the
- * initial release of the Radeon 8500 driver under the XFree86 license.
- * This notice must be preserved.
- *
- * 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 AND/OR THEIR 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.
- *
- * Authors:
- *    Ben Skeggs <bskeggs@redhat.com>
- *    Roy Spliet <r.spliet@student.tudelft.nl>
- */
-
-#include "nouveau_drm.h"
-#include "nouveau_pm.h"
-
-#include <subdev/fb.h>
-
-static int
-nv40_mem_timing_calc(struct drm_device *dev, u32 freq,
-                    struct nouveau_pm_tbl_entry *e, u8 len,
-                    struct nouveau_pm_memtiming *boot,
-                    struct nouveau_pm_memtiming *t)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-
-       t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC);
-
-       /* XXX: I don't trust the -1's and +1's... they must come
-        *      from somewhere! */
-       t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 |
-                   1 << 16 |
-                   (e->tWTR + 2 + (t->tCWL - 1)) << 8 |
-                   (e->tCL + 2 - (t->tCWL - 1));
-
-       t->reg[2] = 0x20200000 |
-                   ((t->tCWL - 1) << 24 |
-                    e->tRRD << 16 |
-                    e->tRCDWR << 8 |
-                    e->tRCDRD);
-
-       NV_DEBUG(drm, "Entry %d: 220: %08x %08x %08x\n", t->id,
-                t->reg[0], t->reg[1], t->reg[2]);
-       return 0;
-}
-
-static int
-nv50_mem_timing_calc(struct drm_device *dev, u32 freq,
-                    struct nouveau_pm_tbl_entry *e, u8 len,
-                    struct nouveau_pm_memtiming *boot,
-                    struct nouveau_pm_memtiming *t)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_fb *pfb = nouveau_fb(device);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct bit_entry P;
-       uint8_t unk18 = 1, unk20 = 0, unk21 = 0, tmp7_3;
-
-       if (bit_table(dev, 'P', &P))
-               return -EINVAL;
-
-       switch (min(len, (u8) 22)) {
-       case 22:
-               unk21 = e->tUNK_21;
-       case 21:
-               unk20 = e->tUNK_20;
-       case 20:
-               if (e->tCWL > 0)
-                       t->tCWL = e->tCWL;
-       case 19:
-               unk18 = e->tUNK_18;
-               break;
-       }
-
-       t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC);
-
-       t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 |
-                               max(unk18, (u8) 1) << 16 |
-                               (e->tWTR + 2 + (t->tCWL - 1)) << 8;
-
-       t->reg[2] = ((t->tCWL - 1) << 24 |
-                   e->tRRD << 16 |
-                   e->tRCDWR << 8 |
-                   e->tRCDRD);
-
-       t->reg[4] = e->tUNK_13 << 8  | e->tUNK_13;
-
-       t->reg[5] = (e->tRFC << 24 | max(e->tRCDRD, e->tRCDWR) << 16 | e->tRP);
-
-       t->reg[8] = boot->reg[8] & 0xffffff00;
-
-       if (P.version == 1) {
-               t->reg[1] |= (e->tCL + 2 - (t->tCWL - 1));
-
-               t->reg[3] = (0x14 + e->tCL) << 24 |
-                           0x16 << 16 |
-                           (e->tCL - 1) << 8 |
-                           (e->tCL - 1);
-
-               t->reg[4] |= boot->reg[4] & 0xffff0000;
-
-               t->reg[6] = (0x33 - t->tCWL) << 16 |
-                           t->tCWL << 8 |
-                           (0x2e + e->tCL - t->tCWL);
-
-               t->reg[7] = 0x4000202 | (e->tCL - 1) << 16;
-
-               /* XXX: P.version == 1 only has DDR2 and GDDR3? */
-               if (pfb->ram->type == NV_MEM_TYPE_DDR2) {
-                       t->reg[5] |= (e->tCL + 3) << 8;
-                       t->reg[6] |= (t->tCWL - 2) << 8;
-                       t->reg[8] |= (e->tCL - 4);
-               } else {
-                       t->reg[5] |= (e->tCL + 2) << 8;
-                       t->reg[6] |= t->tCWL << 8;
-                       t->reg[8] |= (e->tCL - 2);
-               }
-       } else {
-               t->reg[1] |= (5 + e->tCL - (t->tCWL));
-
-               /* XXX: 0xb? 0x30? */
-               t->reg[3] = (0x30 + e->tCL) << 24 |
-                           (boot->reg[3] & 0x00ff0000)|
-                           (0xb + e->tCL) << 8 |
-                           (e->tCL - 1);
-
-               t->reg[4] |= (unk20 << 24 | unk21 << 16);
-
-               /* XXX: +6? */
-               t->reg[5] |= (t->tCWL + 6) << 8;
-
-               t->reg[6] = (0x5a + e->tCL) << 16 |
-                           (6 - e->tCL + t->tCWL) << 8 |
-                           (0x50 + e->tCL - t->tCWL);
-
-               tmp7_3 = (boot->reg[7] & 0xff000000) >> 24;
-               t->reg[7] = (tmp7_3 << 24) |
-                           ((tmp7_3 - 6 + e->tCL) << 16) |
-                           0x202;
-       }
-
-       NV_DEBUG(drm, "Entry %d: 220: %08x %08x %08x %08x\n", t->id,
-                t->reg[0], t->reg[1], t->reg[2], t->reg[3]);
-       NV_DEBUG(drm, "         230: %08x %08x %08x %08x\n",
-                t->reg[4], t->reg[5], t->reg[6], t->reg[7]);
-       NV_DEBUG(drm, "         240: %08x\n", t->reg[8]);
-       return 0;
-}
-
-static int
-nvc0_mem_timing_calc(struct drm_device *dev, u32 freq,
-                    struct nouveau_pm_tbl_entry *e, u8 len,
-                    struct nouveau_pm_memtiming *boot,
-                    struct nouveau_pm_memtiming *t)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-
-       if (e->tCWL > 0)
-               t->tCWL = e->tCWL;
-
-       t->reg[0] = (e->tRP << 24 | (e->tRAS & 0x7f) << 17 |
-                    e->tRFC << 8 | e->tRC);
-
-       t->reg[1] = (boot->reg[1] & 0xff000000) |
-                   (e->tRCDWR & 0x0f) << 20 |
-                   (e->tRCDRD & 0x0f) << 14 |
-                   (t->tCWL << 7) |
-                   (e->tCL & 0x0f);
-
-       t->reg[2] = (boot->reg[2] & 0xff0000ff) |
-                   e->tWR << 16 | e->tWTR << 8;
-
-       t->reg[3] = (e->tUNK_20 & 0x1f) << 9 |
-                   (e->tUNK_21 & 0xf) << 5 |
-                   (e->tUNK_13 & 0x1f);
-
-       t->reg[4] = (boot->reg[4] & 0xfff00fff) |
-                   (e->tRRD&0x1f) << 15;
-
-       NV_DEBUG(drm, "Entry %d: 290: %08x %08x %08x %08x\n", t->id,
-                t->reg[0], t->reg[1], t->reg[2], t->reg[3]);
-       NV_DEBUG(drm, "         2a0: %08x\n", t->reg[4]);
-       return 0;
-}
-
-/**
- * MR generation methods
- */
-
-static int
-nouveau_mem_ddr2_mr(struct drm_device *dev, u32 freq,
-                   struct nouveau_pm_tbl_entry *e, u8 len,
-                   struct nouveau_pm_memtiming *boot,
-                   struct nouveau_pm_memtiming *t)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-
-       t->drive_strength = 0;
-       if (len < 15) {
-               t->odt = boot->odt;
-       } else {
-               t->odt = e->RAM_FT1 & 0x07;
-       }
-
-       if (e->tCL >= NV_MEM_CL_DDR2_MAX) {
-               NV_WARN(drm, "(%u) Invalid tCL: %u", t->id, e->tCL);
-               return -ERANGE;
-       }
-
-       if (e->tWR >= NV_MEM_WR_DDR2_MAX) {
-               NV_WARN(drm, "(%u) Invalid tWR: %u", t->id, e->tWR);
-               return -ERANGE;
-       }
-
-       if (t->odt > 3) {
-               NV_WARN(drm, "(%u) Invalid odt value, assuming disabled: %x",
-                       t->id, t->odt);
-               t->odt = 0;
-       }
-
-       t->mr[0] = (boot->mr[0] & 0x100f) |
-                  (e->tCL) << 4 |
-                  (e->tWR - 1) << 9;
-       t->mr[1] = (boot->mr[1] & 0x101fbb) |
-                  (t->odt & 0x1) << 2 |
-                  (t->odt & 0x2) << 5;
-
-       NV_DEBUG(drm, "(%u) MR: %08x", t->id, t->mr[0]);
-       return 0;
-}
-
-static const uint8_t nv_mem_wr_lut_ddr3[NV_MEM_WR_DDR3_MAX] = {
-       0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0};
-
-static int
-nouveau_mem_ddr3_mr(struct drm_device *dev, u32 freq,
-                   struct nouveau_pm_tbl_entry *e, u8 len,
-                   struct nouveau_pm_memtiming *boot,
-                   struct nouveau_pm_memtiming *t)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       u8 cl = e->tCL - 4;
-
-       t->drive_strength = 0;
-       if (len < 15) {
-               t->odt = boot->odt;
-       } else {
-               t->odt = e->RAM_FT1 & 0x07;
-       }
-
-       if (e->tCL >= NV_MEM_CL_DDR3_MAX || e->tCL < 4) {
-               NV_WARN(drm, "(%u) Invalid tCL: %u", t->id, e->tCL);
-               return -ERANGE;
-       }
-
-       if (e->tWR >= NV_MEM_WR_DDR3_MAX || e->tWR < 4) {
-               NV_WARN(drm, "(%u) Invalid tWR: %u", t->id, e->tWR);
-               return -ERANGE;
-       }
-
-       if (e->tCWL < 5) {
-               NV_WARN(drm, "(%u) Invalid tCWL: %u", t->id, e->tCWL);
-               return -ERANGE;
-       }
-
-       t->mr[0] = (boot->mr[0] & 0x180b) |
-                  /* CAS */
-                  (cl & 0x7) << 4 |
-                  (cl & 0x8) >> 1 |
-                  (nv_mem_wr_lut_ddr3[e->tWR]) << 9;
-       t->mr[1] = (boot->mr[1] & 0x101dbb) |
-                  (t->odt & 0x1) << 2 |
-                  (t->odt & 0x2) << 5 |
-                  (t->odt & 0x4) << 7;
-       t->mr[2] = (boot->mr[2] & 0x20ffb7) | (e->tCWL - 5) << 3;
-
-       NV_DEBUG(drm, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[2]);
-       return 0;
-}
-
-static const uint8_t nv_mem_cl_lut_gddr3[NV_MEM_CL_GDDR3_MAX] = {
-       0, 0, 0, 0, 4, 5, 6, 7, 0, 1, 2, 3, 8, 9, 10, 11};
-static const uint8_t nv_mem_wr_lut_gddr3[NV_MEM_WR_GDDR3_MAX] = {
-       0, 0, 0, 0, 0, 2, 3, 8, 9, 10, 11, 0, 0, 1, 1, 0, 3};
-
-static int
-nouveau_mem_gddr3_mr(struct drm_device *dev, u32 freq,
-                    struct nouveau_pm_tbl_entry *e, u8 len,
-                    struct nouveau_pm_memtiming *boot,
-                    struct nouveau_pm_memtiming *t)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-
-       if (len < 15) {
-               t->drive_strength = boot->drive_strength;
-               t->odt = boot->odt;
-       } else {
-               t->drive_strength = (e->RAM_FT1 & 0x30) >> 4;
-               t->odt = e->RAM_FT1 & 0x07;
-       }
-
-       if (e->tCL >= NV_MEM_CL_GDDR3_MAX) {
-               NV_WARN(drm, "(%u) Invalid tCL: %u", t->id, e->tCL);
-               return -ERANGE;
-       }
-
-       if (e->tWR >= NV_MEM_WR_GDDR3_MAX) {
-               NV_WARN(drm, "(%u) Invalid tWR: %u", t->id, e->tWR);
-               return -ERANGE;
-       }
-
-       if (t->odt > 3) {
-               NV_WARN(drm, "(%u) Invalid odt value, assuming autocal: %x",
-                       t->id, t->odt);
-               t->odt = 0;
-       }
-
-       t->mr[0] = (boot->mr[0] & 0xe0b) |
-                  /* CAS */
-                  ((nv_mem_cl_lut_gddr3[e->tCL] & 0x7) << 4) |
-                  ((nv_mem_cl_lut_gddr3[e->tCL] & 0x8) >> 2);
-       t->mr[1] = (boot->mr[1] & 0x100f40) | t->drive_strength |
-                  (t->odt << 2) |
-                  (nv_mem_wr_lut_gddr3[e->tWR] & 0xf) << 4;
-       t->mr[2] = boot->mr[2];
-
-       NV_DEBUG(drm, "(%u) MR: %08x %08x %08x", t->id,
-                     t->mr[0], t->mr[1], t->mr[2]);
-       return 0;
-}
-
-static int
-nouveau_mem_gddr5_mr(struct drm_device *dev, u32 freq,
-                    struct nouveau_pm_tbl_entry *e, u8 len,
-                    struct nouveau_pm_memtiming *boot,
-                    struct nouveau_pm_memtiming *t)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-
-       if (len < 15) {
-               t->drive_strength = boot->drive_strength;
-               t->odt = boot->odt;
-       } else {
-               t->drive_strength = (e->RAM_FT1 & 0x30) >> 4;
-               t->odt = e->RAM_FT1 & 0x03;
-       }
-
-       if (e->tCL >= NV_MEM_CL_GDDR5_MAX) {
-               NV_WARN(drm, "(%u) Invalid tCL: %u", t->id, e->tCL);
-               return -ERANGE;
-       }
-
-       if (e->tWR >= NV_MEM_WR_GDDR5_MAX) {
-               NV_WARN(drm, "(%u) Invalid tWR: %u", t->id, e->tWR);
-               return -ERANGE;
-       }
-
-       if (t->odt > 3) {
-               NV_WARN(drm, "(%u) Invalid odt value, assuming autocal: %x",
-                       t->id, t->odt);
-               t->odt = 0;
-       }
-
-       t->mr[0] = (boot->mr[0] & 0x007) |
-                  ((e->tCL - 5) << 3) |
-                  ((e->tWR - 4) << 8);
-       t->mr[1] = (boot->mr[1] & 0x1007f0) |
-                  t->drive_strength |
-                  (t->odt << 2);
-
-       NV_DEBUG(drm, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[1]);
-       return 0;
-}
-
-int
-nouveau_mem_timing_calc(struct drm_device *dev, u32 freq,
-                       struct nouveau_pm_memtiming *t)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_fb *pfb = nouveau_fb(device);
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_pm_memtiming *boot = &pm->boot.timing;
-       struct nouveau_pm_tbl_entry *e;
-       u8 ver, len, *ptr, *ramcfg;
-       int ret;
-
-       ptr = nouveau_perf_timing(dev, freq, &ver, &len);
-       if (!ptr || ptr[0] == 0x00) {
-               *t = *boot;
-               return 0;
-       }
-       e = (struct nouveau_pm_tbl_entry *)ptr;
-
-       t->tCWL = boot->tCWL;
-
-       switch (device->card_type) {
-       case NV_40:
-               ret = nv40_mem_timing_calc(dev, freq, e, len, boot, t);
-               break;
-       case NV_50:
-               ret = nv50_mem_timing_calc(dev, freq, e, len, boot, t);
-               break;
-       case NV_C0:
-       case NV_D0:
-               ret = nvc0_mem_timing_calc(dev, freq, e, len, boot, t);
-               break;
-       default:
-               ret = -ENODEV;
-               break;
-       }
-
-       switch (pfb->ram->type * !ret) {
-       case NV_MEM_TYPE_GDDR3:
-               ret = nouveau_mem_gddr3_mr(dev, freq, e, len, boot, t);
-               break;
-       case NV_MEM_TYPE_GDDR5:
-               ret = nouveau_mem_gddr5_mr(dev, freq, e, len, boot, t);
-               break;
-       case NV_MEM_TYPE_DDR2:
-               ret = nouveau_mem_ddr2_mr(dev, freq, e, len, boot, t);
-               break;
-       case NV_MEM_TYPE_DDR3:
-               ret = nouveau_mem_ddr3_mr(dev, freq, e, len, boot, t);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       ramcfg = nouveau_perf_ramcfg(dev, freq, &ver, &len);
-       if (ramcfg) {
-               int dll_off;
-
-               if (ver == 0x00)
-                       dll_off = !!(ramcfg[3] & 0x04);
-               else
-                       dll_off = !!(ramcfg[2] & 0x40);
-
-               switch (pfb->ram->type) {
-               case NV_MEM_TYPE_GDDR3:
-                       t->mr[1] &= ~0x00000040;
-                       t->mr[1] |=  0x00000040 * dll_off;
-                       break;
-               default:
-                       t->mr[1] &= ~0x00000001;
-                       t->mr[1] |=  0x00000001 * dll_off;
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-void
-nouveau_mem_timing_read(struct drm_device *dev, struct nouveau_pm_memtiming *t)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_fb *pfb = nouveau_fb(device);
-       u32 timing_base, timing_regs, mr_base;
-       int i;
-
-       if (device->card_type >= 0xC0) {
-               timing_base = 0x10f290;
-               mr_base = 0x10f300;
-       } else {
-               timing_base = 0x100220;
-               mr_base = 0x1002c0;
-       }
-
-       t->id = -1;
-
-       switch (device->card_type) {
-       case NV_50:
-               timing_regs = 9;
-               break;
-       case NV_C0:
-       case NV_D0:
-               timing_regs = 5;
-               break;
-       case NV_30:
-       case NV_40:
-               timing_regs = 3;
-               break;
-       default:
-               timing_regs = 0;
-               return;
-       }
-       for(i = 0; i < timing_regs; i++)
-               t->reg[i] = nv_rd32(device, timing_base + (0x04 * i));
-
-       t->tCWL = 0;
-       if (device->card_type < NV_C0) {
-               t->tCWL = ((nv_rd32(device, 0x100228) & 0x0f000000) >> 24) + 1;
-       } else if (device->card_type <= NV_D0) {
-               t->tCWL = ((nv_rd32(device, 0x10f294) & 0x00000f80) >> 7);
-       }
-
-       t->mr[0] = nv_rd32(device, mr_base);
-       t->mr[1] = nv_rd32(device, mr_base + 0x04);
-       t->mr[2] = nv_rd32(device, mr_base + 0x20);
-       t->mr[3] = nv_rd32(device, mr_base + 0x24);
-
-       t->odt = 0;
-       t->drive_strength = 0;
-
-       switch (pfb->ram->type) {
-       case NV_MEM_TYPE_DDR3:
-               t->odt |= (t->mr[1] & 0x200) >> 7;
-       case NV_MEM_TYPE_DDR2:
-               t->odt |= (t->mr[1] & 0x04) >> 2 |
-                         (t->mr[1] & 0x40) >> 5;
-               break;
-       case NV_MEM_TYPE_GDDR3:
-       case NV_MEM_TYPE_GDDR5:
-               t->drive_strength = t->mr[1] & 0x03;
-               t->odt = (t->mr[1] & 0x0c) >> 2;
-               break;
-       default:
-               break;
-       }
-}
-
-int
-nouveau_mem_exec(struct nouveau_mem_exec_func *exec,
-                struct nouveau_pm_level *perflvl)
-{
-       struct nouveau_drm *drm = nouveau_drm(exec->dev);
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nouveau_fb *pfb = nouveau_fb(device);
-       struct nouveau_pm_memtiming *info = &perflvl->timing;
-       u32 tMRD = 1000, tCKSRE = 0, tCKSRX = 0, tXS = 0, tDLLK = 0;
-       u32 mr[3] = { info->mr[0], info->mr[1], info->mr[2] };
-       u32 mr1_dlloff;
-
-       switch (pfb->ram->type) {
-       case NV_MEM_TYPE_DDR2:
-               tDLLK = 2000;
-               mr1_dlloff = 0x00000001;
-               break;
-       case NV_MEM_TYPE_DDR3:
-               tDLLK = 12000;
-               tCKSRE = 2000;
-               tXS = 1000;
-               mr1_dlloff = 0x00000001;
-               break;
-       case NV_MEM_TYPE_GDDR3:
-               tDLLK = 40000;
-               mr1_dlloff = 0x00000040;
-               break;
-       default:
-               NV_ERROR(drm, "cannot reclock unsupported memtype\n");
-               return -ENODEV;
-       }
-
-       /* fetch current MRs */
-       switch (pfb->ram->type) {
-       case NV_MEM_TYPE_GDDR3:
-       case NV_MEM_TYPE_DDR3:
-               mr[2] = exec->mrg(exec, 2);
-       default:
-               mr[1] = exec->mrg(exec, 1);
-               mr[0] = exec->mrg(exec, 0);
-               break;
-       }
-
-       /* DLL 'on' -> DLL 'off' mode, disable before entering self-refresh  */
-       if (!(mr[1] & mr1_dlloff) && (info->mr[1] & mr1_dlloff)) {
-               exec->precharge(exec);
-               exec->mrs (exec, 1, mr[1] | mr1_dlloff);
-               exec->wait(exec, tMRD);
-       }
-
-       /* enter self-refresh mode */
-       exec->precharge(exec);
-       exec->refresh(exec);
-       exec->refresh(exec);
-       exec->refresh_auto(exec, false);
-       exec->refresh_self(exec, true);
-       exec->wait(exec, tCKSRE);
-
-       /* modify input clock frequency */
-       exec->clock_set(exec);
-
-       /* exit self-refresh mode */
-       exec->wait(exec, tCKSRX);
-       exec->precharge(exec);
-       exec->refresh_self(exec, false);
-       exec->refresh_auto(exec, true);
-       exec->wait(exec, tXS);
-       exec->wait(exec, tXS);
-
-       /* update MRs */
-       if (mr[2] != info->mr[2]) {
-               exec->mrs (exec, 2, info->mr[2]);
-               exec->wait(exec, tMRD);
-       }
-
-       if (mr[1] != info->mr[1]) {
-               /* need to keep DLL off until later, at least on GDDR3 */
-               exec->mrs (exec, 1, info->mr[1] | (mr[1] & mr1_dlloff));
-               exec->wait(exec, tMRD);
-       }
-
-       if (mr[0] != info->mr[0]) {
-               exec->mrs (exec, 0, info->mr[0]);
-               exec->wait(exec, tMRD);
-       }
-
-       /* update PFB timing registers */
-       exec->timing_set(exec);
-
-       /* DLL (enable + ) reset */
-       if (!(info->mr[1] & mr1_dlloff)) {
-               if (mr[1] & mr1_dlloff) {
-                       exec->mrs (exec, 1, info->mr[1]);
-                       exec->wait(exec, tMRD);
-               }
-               exec->mrs (exec, 0, info->mr[0] | 0x00000100);
-               exec->wait(exec, tMRD);
-               exec->mrs (exec, 0, info->mr[0] | 0x00000000);
-               exec->wait(exec, tMRD);
-               exec->wait(exec, tDLLK);
-               if (pfb->ram->type == NV_MEM_TYPE_GDDR3)
-                       exec->precharge(exec);
-       }
-
-       return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
deleted file mode 100644 (file)
index 4fe883c..0000000
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <drm/drmP.h>
-
-#include "nouveau_drm.h"
-#include "nouveau_reg.h"
-#include "nouveau_pm.h"
-
-static u8 *
-nouveau_perf_table(struct drm_device *dev, u8 *ver)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nvbios *bios = &drm->vbios;
-       struct bit_entry P;
-
-       if (!bit_table(dev, 'P', &P) && P.version && P.version <= 2) {
-               u8 *perf = ROMPTR(dev, P.data[0]);
-               if (perf) {
-                       *ver = perf[0];
-                       return perf;
-               }
-       }
-
-       if (bios->type == NVBIOS_BMP) {
-               if (bios->data[bios->offset + 6] >= 0x25) {
-                       u8 *perf = ROMPTR(dev, bios->data[bios->offset + 0x94]);
-                       if (perf) {
-                               *ver = perf[1];
-                               return perf;
-                       }
-               }
-       }
-
-       return NULL;
-}
-
-static u8 *
-nouveau_perf_entry(struct drm_device *dev, int idx,
-                  u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-       u8 *perf = nouveau_perf_table(dev, ver);
-       if (perf) {
-               if (*ver >= 0x12 && *ver < 0x20 && idx < perf[2]) {
-                       *hdr = perf[3];
-                       *cnt = 0;
-                       *len = 0;
-                       return perf + perf[0] + idx * perf[3];
-               } else
-               if (*ver >= 0x20 && *ver < 0x40 && idx < perf[2]) {
-                       *hdr = perf[3];
-                       *cnt = perf[4];
-                       *len = perf[5];
-                       return perf + perf[1] + idx * (*hdr + (*cnt * *len));
-               } else
-               if (*ver >= 0x40 && *ver < 0x41 && idx < perf[5]) {
-                       *hdr = perf[2];
-                       *cnt = perf[4];
-                       *len = perf[3];
-                       return perf + perf[1] + idx * (*hdr + (*cnt * *len));
-               }
-       }
-       return NULL;
-}
-
-u8 *
-nouveau_perf_rammap(struct drm_device *dev, u32 freq,
-                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct bit_entry P;
-       u8 *perf, i = 0;
-
-       if (!bit_table(dev, 'P', &P) && P.version == 2) {
-               u8 *rammap = ROMPTR(dev, P.data[4]);
-               if (rammap) {
-                       u8 *ramcfg = rammap + rammap[1];
-
-                       *ver = rammap[0];
-                       *hdr = rammap[2];
-                       *cnt = rammap[4];
-                       *len = rammap[3];
-
-                       freq /= 1000;
-                       for (i = 0; i < rammap[5]; i++) {
-                               if (freq >= ROM16(ramcfg[0]) &&
-                                   freq <= ROM16(ramcfg[2]))
-                                       return ramcfg;
-
-                               ramcfg += *hdr + (*cnt * *len);
-                       }
-               }
-
-               return NULL;
-       }
-
-       if (nv_device(drm->device)->chipset == 0x49 ||
-           nv_device(drm->device)->chipset == 0x4b)
-               freq /= 2;
-
-       while ((perf = nouveau_perf_entry(dev, i++, ver, hdr, cnt, len))) {
-               if (*ver >= 0x20 && *ver < 0x25) {
-                       if (perf[0] != 0xff && freq <= ROM16(perf[11]) * 1000)
-                               break;
-               } else
-               if (*ver >= 0x25 && *ver < 0x40) {
-                       if (perf[0] != 0xff && freq <= ROM16(perf[12]) * 1000)
-                               break;
-               }
-       }
-
-       if (perf) {
-               u8 *ramcfg = perf + *hdr;
-               *ver = 0x00;
-               *hdr = 0;
-               return ramcfg;
-       }
-
-       return NULL;
-}
-
-u8 *
-nouveau_perf_ramcfg(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nvbios *bios = &drm->vbios;
-       u8 strap, hdr, cnt;
-       u8 *rammap;
-
-       strap = (nv_rd32(device, 0x101000) & 0x0000003c) >> 2;
-       if (bios->ram_restrict_tbl_ptr)
-               strap = bios->data[bios->ram_restrict_tbl_ptr + strap];
-
-       rammap = nouveau_perf_rammap(dev, freq, ver, &hdr, &cnt, len);
-       if (rammap && strap < cnt)
-               return rammap + hdr + (strap * *len);
-
-       return NULL;
-}
-
-u8 *
-nouveau_perf_timing(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nvbios *bios = &drm->vbios;
-       struct bit_entry P;
-       u8 *perf, *timing = NULL;
-       u8 i = 0, hdr, cnt;
-
-       if (bios->type == NVBIOS_BMP) {
-               while ((perf = nouveau_perf_entry(dev, i++, ver, &hdr, &cnt,
-                                                 len)) && *ver == 0x15) {
-                       if (freq <= ROM32(perf[5]) * 20) {
-                               *ver = 0x00;
-                               *len = 14;
-                               return perf + 41;
-                       }
-               }
-               return NULL;
-       }
-
-       if (!bit_table(dev, 'P', &P)) {
-               if (P.version == 1)
-                       timing = ROMPTR(dev, P.data[4]);
-               else
-               if (P.version == 2)
-                       timing = ROMPTR(dev, P.data[8]);
-       }
-
-       if (timing && timing[0] == 0x10) {
-               u8 *ramcfg = nouveau_perf_ramcfg(dev, freq, ver, len);
-               if (ramcfg && ramcfg[1] < timing[2]) {
-                       *ver = timing[0];
-                       *len = timing[3];
-                       return timing + timing[1] + (ramcfg[1] * timing[3]);
-               }
-       }
-
-       return NULL;
-}
-
-static void
-legacy_perf_init(struct drm_device *dev)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nvbios *bios = &drm->vbios;
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       char *perf, *entry, *bmp = &bios->data[bios->offset];
-       int headerlen, use_straps;
-
-       if (bmp[5] < 0x5 || bmp[6] < 0x14) {
-               NV_DEBUG(drm, "BMP version too old for perf\n");
-               return;
-       }
-
-       perf = ROMPTR(dev, bmp[0x73]);
-       if (!perf) {
-               NV_DEBUG(drm, "No memclock table pointer found.\n");
-               return;
-       }
-
-       switch (perf[0]) {
-       case 0x12:
-       case 0x14:
-       case 0x18:
-               use_straps = 0;
-               headerlen = 1;
-               break;
-       case 0x01:
-               use_straps = perf[1] & 1;
-               headerlen = (use_straps ? 8 : 2);
-               break;
-       default:
-               NV_WARN(drm, "Unknown memclock table version %x.\n", perf[0]);
-               return;
-       }
-
-       entry = perf + headerlen;
-       if (use_straps)
-               entry += (nv_rd32(device, NV_PEXTDEV_BOOT_0) & 0x3c) >> 1;
-
-       sprintf(pm->perflvl[0].name, "performance_level_0");
-       pm->perflvl[0].memory = ROM16(entry[0]) * 20;
-       pm->nr_perflvl = 1;
-}
-
-static void
-nouveau_perf_voltage(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct bit_entry P;
-       u8 *vmap;
-       int id;
-
-       id = perflvl->volt_min;
-       perflvl->volt_min = 0;
-
-       /* boards using voltage table version <0x40 store the voltage
-        * level directly in the perflvl entry as a multiple of 10mV
-        */
-       if (drm->pm->voltage.version < 0x40) {
-               perflvl->volt_min = id * 10000;
-               perflvl->volt_max = perflvl->volt_min;
-               return;
-       }
-
-       /* on newer ones, the perflvl stores an index into yet another
-        * vbios table containing a min/max voltage value for the perflvl
-        */
-       if (bit_table(dev, 'P', &P) || P.version != 2 || P.length < 34) {
-               NV_DEBUG(drm, "where's our volt map table ptr? %d %d\n",
-                        P.version, P.length);
-               return;
-       }
-
-       vmap = ROMPTR(dev, P.data[32]);
-       if (!vmap) {
-               NV_DEBUG(drm, "volt map table pointer invalid\n");
-               return;
-       }
-
-       if (id < vmap[3]) {
-               vmap += vmap[1] + (vmap[2] * id);
-               perflvl->volt_min = ROM32(vmap[0]);
-               perflvl->volt_max = ROM32(vmap[4]);
-       }
-}
-
-void
-nouveau_perf_init(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nvbios *bios = &drm->vbios;
-       u8 *perf, ver, hdr, cnt, len;
-       int ret, vid, i = -1;
-
-       if (bios->type == NVBIOS_BMP && bios->data[bios->offset + 6] < 0x25) {
-               legacy_perf_init(dev);
-               return;
-       }
-
-       perf = nouveau_perf_table(dev, &ver);
-
-       while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) {
-               struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
-
-               if (perf[0] == 0xff)
-                       continue;
-
-               switch (ver) {
-               case 0x12:
-               case 0x13:
-               case 0x15:
-                       perflvl->fanspeed = perf[55];
-                       if (hdr > 56)
-                               perflvl->volt_min = perf[56];
-                       perflvl->core = ROM32(perf[1]) * 10;
-                       perflvl->memory = ROM32(perf[5]) * 20;
-                       break;
-               case 0x21:
-               case 0x23:
-               case 0x24:
-                       perflvl->fanspeed = perf[4];
-                       perflvl->volt_min = perf[5];
-                       perflvl->shader = ROM16(perf[6]) * 1000;
-                       perflvl->core = perflvl->shader;
-                       perflvl->core += (signed char)perf[8] * 1000;
-                       if (nv_device(drm->device)->chipset == 0x49 ||
-                           nv_device(drm->device)->chipset == 0x4b)
-                               perflvl->memory = ROM16(perf[11]) * 1000;
-                       else
-                               perflvl->memory = ROM16(perf[11]) * 2000;
-                       break;
-               case 0x25:
-                       perflvl->fanspeed = perf[4];
-                       perflvl->volt_min = perf[5];
-                       perflvl->core = ROM16(perf[6]) * 1000;
-                       perflvl->shader = ROM16(perf[10]) * 1000;
-                       perflvl->memory = ROM16(perf[12]) * 1000;
-                       break;
-               case 0x30:
-                       perflvl->memscript = ROM16(perf[2]);
-               case 0x35:
-                       perflvl->fanspeed = perf[6];
-                       perflvl->volt_min = perf[7];
-                       perflvl->core = ROM16(perf[8]) * 1000;
-                       perflvl->shader = ROM16(perf[10]) * 1000;
-                       perflvl->memory = ROM16(perf[12]) * 1000;
-                       perflvl->vdec = ROM16(perf[16]) * 1000;
-                       perflvl->dom6 = ROM16(perf[20]) * 1000;
-                       break;
-               case 0x40:
-#define subent(n) ((ROM16(perf[hdr + (n) * len]) & 0xfff) * 1000)
-                       perflvl->fanspeed = 0; /*XXX*/
-                       perflvl->volt_min = perf[2];
-                       if (nv_device(drm->device)->card_type == NV_50) {
-                               perflvl->core   = subent(0);
-                               perflvl->shader = subent(1);
-                               perflvl->memory = subent(2);
-                               perflvl->vdec   = subent(3);
-                               perflvl->unka0  = subent(4);
-                       } else {
-                               perflvl->hub06  = subent(0);
-                               perflvl->hub01  = subent(1);
-                               perflvl->copy   = subent(2);
-                               perflvl->shader = subent(3);
-                               perflvl->rop    = subent(4);
-                               perflvl->memory = subent(5);
-                               perflvl->vdec   = subent(6);
-                               perflvl->daemon = subent(10);
-                               perflvl->hub07  = subent(11);
-                               perflvl->core   = perflvl->shader / 2;
-                       }
-                       break;
-               }
-
-               /* make sure vid is valid */
-               nouveau_perf_voltage(dev, perflvl);
-               if (pm->voltage.supported && perflvl->volt_min) {
-                       vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min);
-                       if (vid < 0) {
-                               NV_DEBUG(drm, "perflvl %d, bad vid\n", i);
-                               continue;
-                       }
-               }
-
-               /* get the corresponding memory timings */
-               ret = nouveau_mem_timing_calc(dev, perflvl->memory,
-                                                 &perflvl->timing);
-               if (ret) {
-                       NV_DEBUG(drm, "perflvl %d, bad timing: %d\n", i, ret);
-                       continue;
-               }
-
-               snprintf(perflvl->name, sizeof(perflvl->name),
-                        "performance_level_%d", i);
-               perflvl->id = i;
-
-               snprintf(perflvl->profile.name, sizeof(perflvl->profile.name),
-                        "%d", perflvl->id);
-               perflvl->profile.func = &nouveau_pm_static_profile_func;
-               list_add_tail(&perflvl->profile.head, &pm->profiles);
-
-
-               pm->nr_perflvl++;
-       }
-}
-
-void
-nouveau_perf_fini(struct drm_device *dev)
-{
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
deleted file mode 100644 (file)
index 936b442..0000000
+++ /dev/null
@@ -1,1174 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#ifdef CONFIG_ACPI
-#include <linux/acpi.h>
-#endif
-#include <linux/power_supply.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-
-#include <drm/drmP.h>
-
-#include "nouveau_drm.h"
-#include "nouveau_pm.h"
-
-#include <subdev/gpio.h>
-#include <subdev/timer.h>
-#include <subdev/therm.h>
-
-MODULE_PARM_DESC(perflvl, "Performance level (default: boot)");
-static char *nouveau_perflvl;
-module_param_named(perflvl, nouveau_perflvl, charp, 0400);
-
-MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)");
-static int nouveau_perflvl_wr;
-module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
-
-static int
-nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl,
-                      struct nouveau_pm_level *a, struct nouveau_pm_level *b)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       int ret;
-
-       /*XXX: not on all boards, we should control based on temperature
-        *     on recent boards..  or maybe on some other factor we don't
-        *     know about?
-        */
-       if (therm && therm->fan_set &&
-               a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) {
-               ret = therm->fan_set(therm, perflvl->fanspeed);
-               if (ret && ret != -ENODEV) {
-                       NV_ERROR(drm, "fanspeed set failed: %d\n", ret);
-               }
-       }
-
-       if (pm->voltage.supported && pm->voltage_set) {
-               if (perflvl->volt_min && b->volt_min > a->volt_min) {
-                       ret = pm->voltage_set(dev, perflvl->volt_min);
-                       if (ret) {
-                               NV_ERROR(drm, "voltage set failed: %d\n", ret);
-                               return ret;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int
-nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       void *state;
-       int ret;
-
-       if (perflvl == pm->cur)
-               return 0;
-
-       ret = nouveau_pm_perflvl_aux(dev, perflvl, pm->cur, perflvl);
-       if (ret)
-               return ret;
-
-       state = pm->clocks_pre(dev, perflvl);
-       if (IS_ERR(state)) {
-               ret = PTR_ERR(state);
-               goto error;
-       }
-       ret = pm->clocks_set(dev, state);
-       if (ret)
-               goto error;
-
-       ret = nouveau_pm_perflvl_aux(dev, perflvl, perflvl, pm->cur);
-       if (ret)
-               return ret;
-
-       pm->cur = perflvl;
-       return 0;
-
-error:
-       /* restore the fan speed and voltage before leaving */
-       nouveau_pm_perflvl_aux(dev, perflvl, perflvl, pm->cur);
-       return ret;
-}
-
-void
-nouveau_pm_trigger(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_timer *ptimer = nouveau_timer(drm->device);
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_pm_profile *profile = NULL;
-       struct nouveau_pm_level *perflvl = NULL;
-       int ret;
-
-       /* select power profile based on current power source */
-       if (power_supply_is_system_supplied())
-               profile = pm->profile_ac;
-       else
-               profile = pm->profile_dc;
-
-       if (profile != pm->profile) {
-               pm->profile->func->fini(pm->profile);
-               pm->profile = profile;
-               pm->profile->func->init(pm->profile);
-       }
-
-       /* select performance level based on profile */
-       perflvl = profile->func->select(profile);
-
-       /* change perflvl, if necessary */
-       if (perflvl != pm->cur) {
-               u64 time0 = ptimer->read(ptimer);
-
-               NV_INFO(drm, "setting performance level: %d", perflvl->id);
-               ret = nouveau_pm_perflvl_set(dev, perflvl);
-               if (ret)
-                       NV_INFO(drm, "> reclocking failed: %d\n\n", ret);
-
-               NV_INFO(drm, "> reclocking took %lluns\n\n",
-                            ptimer->read(ptimer) - time0);
-       }
-}
-
-static struct nouveau_pm_profile *
-profile_find(struct drm_device *dev, const char *string)
-{
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_pm_profile *profile;
-
-       list_for_each_entry(profile, &pm->profiles, head) {
-               if (!strncmp(profile->name, string, sizeof(profile->name)))
-                       return profile;
-       }
-
-       return NULL;
-}
-
-static int
-nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
-{
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_pm_profile *ac = NULL, *dc = NULL;
-       char string[16], *cur = string, *ptr;
-
-       /* safety precaution, for now */
-       if (nouveau_perflvl_wr != 7777)
-               return -EPERM;
-
-       strncpy(string, profile, sizeof(string));
-       string[sizeof(string) - 1] = 0;
-       if ((ptr = strchr(string, '\n')))
-               *ptr = '\0';
-
-       ptr = strsep(&cur, ",");
-       if (ptr)
-               ac = profile_find(dev, ptr);
-
-       ptr = strsep(&cur, ",");
-       if (ptr)
-               dc = profile_find(dev, ptr);
-       else
-               dc = ac;
-
-       if (ac == NULL || dc == NULL)
-               return -EINVAL;
-
-       pm->profile_ac = ac;
-       pm->profile_dc = dc;
-       nouveau_pm_trigger(dev);
-       return 0;
-}
-
-static void
-nouveau_pm_static_dummy(struct nouveau_pm_profile *profile)
-{
-}
-
-static struct nouveau_pm_level *
-nouveau_pm_static_select(struct nouveau_pm_profile *profile)
-{
-       return container_of(profile, struct nouveau_pm_level, profile);
-}
-
-const struct nouveau_pm_profile_func nouveau_pm_static_profile_func = {
-       .destroy = nouveau_pm_static_dummy,
-       .init = nouveau_pm_static_dummy,
-       .fini = nouveau_pm_static_dummy,
-       .select = nouveau_pm_static_select,
-};
-
-static int
-nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       int ret;
-
-       memset(perflvl, 0, sizeof(*perflvl));
-
-       if (pm->clocks_get) {
-               ret = pm->clocks_get(dev, perflvl);
-               if (ret)
-                       return ret;
-       }
-
-       if (pm->voltage.supported && pm->voltage_get) {
-               ret = pm->voltage_get(dev);
-               if (ret > 0) {
-                       perflvl->volt_min = ret;
-                       perflvl->volt_max = ret;
-               }
-       }
-
-       if (therm && therm->fan_get) {
-               ret = therm->fan_get(therm);
-               if (ret >= 0)
-                       perflvl->fanspeed = ret;
-       }
-
-       nouveau_mem_timing_read(dev, &perflvl->timing);
-       return 0;
-}
-
-static void
-nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
-{
-       char c[16], s[16], v[32], f[16], m[16];
-
-       c[0] = '\0';
-       if (perflvl->core)
-               snprintf(c, sizeof(c), " core %dMHz", perflvl->core / 1000);
-
-       s[0] = '\0';
-       if (perflvl->shader)
-               snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000);
-
-       m[0] = '\0';
-       if (perflvl->memory)
-               snprintf(m, sizeof(m), " memory %dMHz", perflvl->memory / 1000);
-
-       v[0] = '\0';
-       if (perflvl->volt_min && perflvl->volt_min != perflvl->volt_max) {
-               snprintf(v, sizeof(v), " voltage %dmV-%dmV",
-                        perflvl->volt_min / 1000, perflvl->volt_max / 1000);
-       } else
-       if (perflvl->volt_min) {
-               snprintf(v, sizeof(v), " voltage %dmV",
-                        perflvl->volt_min / 1000);
-       }
-
-       f[0] = '\0';
-       if (perflvl->fanspeed)
-               snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
-
-       snprintf(ptr, len, "%s%s%s%s%s\n", c, s, m, v, f);
-}
-
-static ssize_t
-nouveau_pm_get_perflvl_info(struct device *d,
-                           struct device_attribute *a, char *buf)
-{
-       struct nouveau_pm_level *perflvl =
-               container_of(a, struct nouveau_pm_level, dev_attr);
-       char *ptr = buf;
-       int len = PAGE_SIZE;
-
-       snprintf(ptr, len, "%d:", perflvl->id);
-       ptr += strlen(buf);
-       len -= strlen(buf);
-
-       nouveau_pm_perflvl_info(perflvl, ptr, len);
-       return strlen(buf);
-}
-
-static ssize_t
-nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
-{
-       struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_pm_level cur;
-       int len = PAGE_SIZE, ret;
-       char *ptr = buf;
-
-       snprintf(ptr, len, "profile: %s, %s\nc:",
-                pm->profile_ac->name, pm->profile_dc->name);
-       ptr += strlen(buf);
-       len -= strlen(buf);
-
-       ret = nouveau_pm_perflvl_get(dev, &cur);
-       if (ret == 0)
-               nouveau_pm_perflvl_info(&cur, ptr, len);
-       return strlen(buf);
-}
-
-static ssize_t
-nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a,
-                      const char *buf, size_t count)
-{
-       struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
-       int ret;
-
-       ret = nouveau_pm_profile_set(dev, buf);
-       if (ret)
-               return ret;
-       return strlen(buf);
-}
-
-static DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR,
-                  nouveau_pm_get_perflvl, nouveau_pm_set_perflvl);
-
-static int
-nouveau_sysfs_init(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct device *d = &dev->pdev->dev;
-       int ret, i;
-
-       ret = device_create_file(d, &dev_attr_performance_level);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < pm->nr_perflvl; i++) {
-               struct nouveau_pm_level *perflvl = &pm->perflvl[i];
-
-               perflvl->dev_attr.attr.name = perflvl->name;
-               perflvl->dev_attr.attr.mode = S_IRUGO;
-               perflvl->dev_attr.show = nouveau_pm_get_perflvl_info;
-               perflvl->dev_attr.store = NULL;
-               sysfs_attr_init(&perflvl->dev_attr.attr);
-
-               ret = device_create_file(d, &perflvl->dev_attr);
-               if (ret) {
-                       NV_ERROR(drm, "failed pervlvl %d sysfs: %d\n",
-                                perflvl->id, i);
-                       perflvl->dev_attr.attr.name = NULL;
-                       nouveau_pm_fini(dev);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-static void
-nouveau_sysfs_fini(struct drm_device *dev)
-{
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct device *d = &dev->pdev->dev;
-       int i;
-
-       device_remove_file(d, &dev_attr_performance_level);
-       for (i = 0; i < pm->nr_perflvl; i++) {
-               struct nouveau_pm_level *pl = &pm->perflvl[i];
-
-               if (!pl->dev_attr.attr.name)
-                       break;
-
-               device_remove_file(d, &pl->dev_attr);
-       }
-}
-
-#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
-static ssize_t
-nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       int temp = therm->temp_get(therm);
-
-       if (temp < 0)
-               return temp;
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", temp * 1000);
-}
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
-                                                 NULL, 0);
-
-static ssize_t
-nouveau_hwmon_show_temp1_auto_point1_pwm(struct device *d,
-                                        struct device_attribute *a, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%d\n", 100);
-}
-static SENSOR_DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO,
-                         nouveau_hwmon_show_temp1_auto_point1_pwm, NULL, 0);
-
-static ssize_t
-nouveau_hwmon_temp1_auto_point1_temp(struct device *d,
-                                    struct device_attribute *a, char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-             therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST) * 1000);
-}
-static ssize_t
-nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d,
-                                        struct device_attribute *a,
-                                        const char *buf, size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return count;
-
-       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST,
-                       value / 1000);
-
-       return count;
-}
-static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_temp1_auto_point1_temp,
-                         nouveau_hwmon_set_temp1_auto_point1_temp, 0);
-
-static ssize_t
-nouveau_hwmon_temp1_auto_point1_temp_hyst(struct device *d,
-                                         struct device_attribute *a, char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-        therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000);
-}
-static ssize_t
-nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d,
-                                             struct device_attribute *a,
-                                             const char *buf, size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return count;
-
-       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST,
-                       value / 1000);
-
-       return count;
-}
-static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_temp1_auto_point1_temp_hyst,
-                         nouveau_hwmon_set_temp1_auto_point1_temp_hyst, 0);
-
-static ssize_t
-nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-              therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK) * 1000);
-}
-static ssize_t
-nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
-                                               const char *buf, size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return count;
-
-       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK, value / 1000);
-
-       return count;
-}
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp,
-                                                 nouveau_hwmon_set_max_temp,
-                                                 0);
-
-static ssize_t
-nouveau_hwmon_max_temp_hyst(struct device *d, struct device_attribute *a,
-                           char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-         therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000);
-}
-static ssize_t
-nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a,
-                                               const char *buf, size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return count;
-
-       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST,
-                       value / 1000);
-
-       return count;
-}
-static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_max_temp_hyst,
-                         nouveau_hwmon_set_max_temp_hyst, 0);
-
-static ssize_t
-nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
-                                                       char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-              therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL) * 1000);
-}
-static ssize_t
-nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
-                                                           const char *buf,
-                                                               size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return count;
-
-       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL, value / 1000);
-
-       return count;
-}
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
-                                               nouveau_hwmon_critical_temp,
-                                               nouveau_hwmon_set_critical_temp,
-                                               0);
-
-static ssize_t
-nouveau_hwmon_critical_temp_hyst(struct device *d, struct device_attribute *a,
-                                                       char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-         therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST) * 1000);
-}
-static ssize_t
-nouveau_hwmon_set_critical_temp_hyst(struct device *d,
-                                    struct device_attribute *a,
-                                    const char *buf,
-                                    size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return count;
-
-       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST,
-                       value / 1000);
-
-       return count;
-}
-static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_critical_temp_hyst,
-                         nouveau_hwmon_set_critical_temp_hyst, 0);
-static ssize_t
-nouveau_hwmon_emergency_temp(struct device *d, struct device_attribute *a,
-                                                       char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-              therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN) * 1000);
-}
-static ssize_t
-nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a,
-                                                           const char *buf,
-                                                               size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return count;
-
-       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN, value / 1000);
-
-       return count;
-}
-static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO | S_IWUSR,
-                                       nouveau_hwmon_emergency_temp,
-                                       nouveau_hwmon_set_emergency_temp,
-                                       0);
-
-static ssize_t
-nouveau_hwmon_emergency_temp_hyst(struct device *d, struct device_attribute *a,
-                                                       char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-         therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000);
-}
-static ssize_t
-nouveau_hwmon_set_emergency_temp_hyst(struct device *d,
-                                     struct device_attribute *a,
-                                     const char *buf,
-                                     size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return count;
-
-       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST,
-                       value / 1000);
-
-       return count;
-}
-static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO | S_IWUSR,
-                                       nouveau_hwmon_emergency_temp_hyst,
-                                       nouveau_hwmon_set_emergency_temp_hyst,
-                                       0);
-
-static ssize_t nouveau_hwmon_show_name(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf)
-{
-       return sprintf(buf, "nouveau\n");
-}
-static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0);
-
-static ssize_t nouveau_hwmon_show_update_rate(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf)
-{
-       return sprintf(buf, "1000\n");
-}
-static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO,
-                                               nouveau_hwmon_show_update_rate,
-                                               NULL, 0);
-
-static ssize_t
-nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr,
-                             char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm));
-}
-static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, nouveau_hwmon_show_fan1_input,
-                         NULL, 0);
-
- static ssize_t
-nouveau_hwmon_get_pwm1_enable(struct device *d,
-                          struct device_attribute *a, char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       int ret;
-
-       ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MODE);
-       if (ret < 0)
-               return ret;
-
-       return sprintf(buf, "%i\n", ret);
-}
-
-static ssize_t
-nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a,
-                          const char *buf, size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-       int ret;
-
-       if (strict_strtol(buf, 10, &value) == -EINVAL)
-               return -EINVAL;
-
-       ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value);
-       if (ret)
-               return ret;
-       else
-               return count;
-}
-static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_get_pwm1_enable,
-                         nouveau_hwmon_set_pwm1_enable, 0);
-
-static ssize_t
-nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       int ret;
-
-       ret = therm->fan_get(therm);
-       if (ret < 0)
-               return ret;
-
-       return sprintf(buf, "%i\n", ret);
-}
-
-static ssize_t
-nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a,
-                      const char *buf, size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       int ret = -ENODEV;
-       long value;
-
-       if (nouveau_perflvl_wr != 7777)
-               return -EPERM;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return -EINVAL;
-
-       ret = therm->fan_set(therm, value);
-       if (ret)
-               return ret;
-
-       return count;
-}
-
-static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_get_pwm1,
-                         nouveau_hwmon_set_pwm1, 0);
-
-static ssize_t
-nouveau_hwmon_get_pwm1_min(struct device *d,
-                          struct device_attribute *a, char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       int ret;
-
-       ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY);
-       if (ret < 0)
-               return ret;
-
-       return sprintf(buf, "%i\n", ret);
-}
-
-static ssize_t
-nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a,
-                          const char *buf, size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-       int ret;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return -EINVAL;
-
-       ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY, value);
-       if (ret < 0)
-               return ret;
-
-       return count;
-}
-
-static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_get_pwm1_min,
-                         nouveau_hwmon_set_pwm1_min, 0);
-
-static ssize_t
-nouveau_hwmon_get_pwm1_max(struct device *d,
-                          struct device_attribute *a, char *buf)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       int ret;
-
-       ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY);
-       if (ret < 0)
-               return ret;
-
-       return sprintf(buf, "%i\n", ret);
-}
-
-static ssize_t
-nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a,
-                          const char *buf, size_t count)
-{
-       struct drm_device *dev = dev_get_drvdata(d);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       long value;
-       int ret;
-
-       if (kstrtol(buf, 10, &value) == -EINVAL)
-               return -EINVAL;
-
-       ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY, value);
-       if (ret < 0)
-               return ret;
-
-       return count;
-}
-
-static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_get_pwm1_max,
-                         nouveau_hwmon_set_pwm1_max, 0);
-
-static struct attribute *hwmon_default_attributes[] = {
-       &sensor_dev_attr_name.dev_attr.attr,
-       &sensor_dev_attr_update_rate.dev_attr.attr,
-       NULL
-};
-static struct attribute *hwmon_temp_attributes[] = {
-       &sensor_dev_attr_temp1_input.dev_attr.attr,
-       &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr,
-       &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
-       &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
-       &sensor_dev_attr_temp1_max.dev_attr.attr,
-       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
-       &sensor_dev_attr_temp1_crit.dev_attr.attr,
-       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
-       &sensor_dev_attr_temp1_emergency.dev_attr.attr,
-       &sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr,
-       NULL
-};
-static struct attribute *hwmon_fan_rpm_attributes[] = {
-       &sensor_dev_attr_fan1_input.dev_attr.attr,
-       NULL
-};
-static struct attribute *hwmon_pwm_fan_attributes[] = {
-       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
-       &sensor_dev_attr_pwm1.dev_attr.attr,
-       &sensor_dev_attr_pwm1_min.dev_attr.attr,
-       &sensor_dev_attr_pwm1_max.dev_attr.attr,
-       NULL
-};
-
-static const struct attribute_group hwmon_default_attrgroup = {
-       .attrs = hwmon_default_attributes,
-};
-static const struct attribute_group hwmon_temp_attrgroup = {
-       .attrs = hwmon_temp_attributes,
-};
-static const struct attribute_group hwmon_fan_rpm_attrgroup = {
-       .attrs = hwmon_fan_rpm_attributes,
-};
-static const struct attribute_group hwmon_pwm_fan_attrgroup = {
-       .attrs = hwmon_pwm_fan_attributes,
-};
-#endif
-
-static int
-nouveau_hwmon_init(struct drm_device *dev)
-{
-       struct nouveau_pm *pm = nouveau_pm(dev);
-
-#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
-       struct device *hwmon_dev;
-       int ret = 0;
-
-       if (!therm || !therm->temp_get || !therm->attr_get || !therm->attr_set)
-               return -ENODEV;
-
-       hwmon_dev = hwmon_device_register(&dev->pdev->dev);
-       if (IS_ERR(hwmon_dev)) {
-               ret = PTR_ERR(hwmon_dev);
-               NV_ERROR(drm, "Unable to register hwmon device: %d\n", ret);
-               return ret;
-       }
-       dev_set_drvdata(hwmon_dev, dev);
-
-       /* set the default attributes */
-       ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_default_attrgroup);
-       if (ret) {
-               if (ret)
-                       goto error;
-       }
-
-       /* if the card has a working thermal sensor */
-       if (therm->temp_get(therm) >= 0) {
-               ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup);
-               if (ret) {
-                       if (ret)
-                               goto error;
-               }
-       }
-
-       /* if the card has a pwm fan */
-       /*XXX: incorrect, need better detection for this, some boards have
-        *     the gpio entries for pwm fan control even when there's no
-        *     actual fan connected to it... therm table? */
-       if (therm->fan_get && therm->fan_get(therm) >= 0) {
-               ret = sysfs_create_group(&hwmon_dev->kobj,
-                                        &hwmon_pwm_fan_attrgroup);
-               if (ret)
-                       goto error;
-       }
-
-       /* if the card can read the fan rpm */
-       if (therm->fan_sense(therm) >= 0) {
-               ret = sysfs_create_group(&hwmon_dev->kobj,
-                                        &hwmon_fan_rpm_attrgroup);
-               if (ret)
-                       goto error;
-       }
-
-       pm->hwmon = hwmon_dev;
-
-       return 0;
-
-error:
-       NV_ERROR(drm, "Unable to create some hwmon sysfs files: %d\n", ret);
-       hwmon_device_unregister(hwmon_dev);
-       pm->hwmon = NULL;
-       return ret;
-#else
-       pm->hwmon = NULL;
-       return 0;
-#endif
-}
-
-static void
-nouveau_hwmon_fini(struct drm_device *dev)
-{
-#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
-       struct nouveau_pm *pm = nouveau_pm(dev);
-
-       if (pm->hwmon) {
-               sysfs_remove_group(&pm->hwmon->kobj, &hwmon_default_attrgroup);
-               sysfs_remove_group(&pm->hwmon->kobj, &hwmon_temp_attrgroup);
-               sysfs_remove_group(&pm->hwmon->kobj, &hwmon_pwm_fan_attrgroup);
-               sysfs_remove_group(&pm->hwmon->kobj, &hwmon_fan_rpm_attrgroup);
-
-               hwmon_device_unregister(pm->hwmon);
-       }
-#endif
-}
-
-#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
-static int
-nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data)
-{
-       struct nouveau_pm *pm = container_of(nb, struct nouveau_pm, acpi_nb);
-       struct nouveau_drm *drm = nouveau_drm(pm->dev);
-       struct acpi_bus_event *entry = (struct acpi_bus_event *)data;
-
-       if (strcmp(entry->device_class, "ac_adapter") == 0) {
-               bool ac = power_supply_is_system_supplied();
-
-               NV_DEBUG(drm, "power supply changed: %s\n", ac ? "AC" : "DC");
-               nouveau_pm_trigger(pm->dev);
-       }
-
-       return NOTIFY_OK;
-}
-#endif
-
-int
-nouveau_pm_init(struct drm_device *dev)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_pm *pm;
-       char info[256];
-       int ret, i;
-
-       pm = drm->pm = kzalloc(sizeof(*pm), GFP_KERNEL);
-       if (!pm)
-               return -ENOMEM;
-
-       pm->dev = dev;
-
-       if (device->card_type < NV_40) {
-               pm->clocks_get = nv04_pm_clocks_get;
-               pm->clocks_pre = nv04_pm_clocks_pre;
-               pm->clocks_set = nv04_pm_clocks_set;
-               if (nouveau_gpio(drm->device)) {
-                       pm->voltage_get = nouveau_voltage_gpio_get;
-                       pm->voltage_set = nouveau_voltage_gpio_set;
-               }
-       } else
-       if (device->card_type < NV_50) {
-               pm->clocks_get = nv40_pm_clocks_get;
-               pm->clocks_pre = nv40_pm_clocks_pre;
-               pm->clocks_set = nv40_pm_clocks_set;
-               pm->voltage_get = nouveau_voltage_gpio_get;
-               pm->voltage_set = nouveau_voltage_gpio_set;
-       } else
-       if (device->card_type < NV_C0) {
-               if (device->chipset <  0xa3 ||
-                   device->chipset == 0xaa ||
-                   device->chipset == 0xac) {
-                       pm->clocks_get = nv50_pm_clocks_get;
-                       pm->clocks_pre = nv50_pm_clocks_pre;
-                       pm->clocks_set = nv50_pm_clocks_set;
-               } else {
-                       pm->clocks_get = nva3_pm_clocks_get;
-                       pm->clocks_pre = nva3_pm_clocks_pre;
-                       pm->clocks_set = nva3_pm_clocks_set;
-               }
-               pm->voltage_get = nouveau_voltage_gpio_get;
-               pm->voltage_set = nouveau_voltage_gpio_set;
-       } else
-       if (device->card_type < NV_E0) {
-               pm->clocks_get = nvc0_pm_clocks_get;
-               pm->clocks_pre = nvc0_pm_clocks_pre;
-               pm->clocks_set = nvc0_pm_clocks_set;
-               pm->voltage_get = nouveau_voltage_gpio_get;
-               pm->voltage_set = nouveau_voltage_gpio_set;
-       }
-
-
-       /* parse aux tables from vbios */
-       nouveau_volt_init(dev);
-
-       INIT_LIST_HEAD(&pm->profiles);
-
-       /* determine current ("boot") performance level */
-       ret = nouveau_pm_perflvl_get(dev, &pm->boot);
-       if (ret) {
-               NV_ERROR(drm, "failed to determine boot perflvl\n");
-               return ret;
-       }
-
-       strncpy(pm->boot.name, "boot", 4);
-       strncpy(pm->boot.profile.name, "boot", 4);
-       pm->boot.profile.func = &nouveau_pm_static_profile_func;
-
-       list_add(&pm->boot.profile.head, &pm->profiles);
-
-       pm->profile_ac = &pm->boot.profile;
-       pm->profile_dc = &pm->boot.profile;
-       pm->profile = &pm->boot.profile;
-       pm->cur = &pm->boot;
-
-       /* add performance levels from vbios */
-       nouveau_perf_init(dev);
-
-       /* display available performance levels */
-       NV_INFO(drm, "%d available performance level(s)\n", pm->nr_perflvl);
-       for (i = 0; i < pm->nr_perflvl; i++) {
-               nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info));
-               NV_INFO(drm, "%d:%s", pm->perflvl[i].id, info);
-       }
-
-       nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
-       NV_INFO(drm, "c:%s", info);
-
-       /* switch performance levels now if requested */
-       if (nouveau_perflvl != NULL)
-               nouveau_pm_profile_set(dev, nouveau_perflvl);
-
-       nouveau_sysfs_init(dev);
-       nouveau_hwmon_init(dev);
-#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
-       pm->acpi_nb.notifier_call = nouveau_pm_acpi_event;
-       register_acpi_notifier(&pm->acpi_nb);
-#endif
-
-       return 0;
-}
-
-void
-nouveau_pm_fini(struct drm_device *dev)
-{
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_pm_profile *profile, *tmp;
-
-       list_for_each_entry_safe(profile, tmp, &pm->profiles, head) {
-               list_del(&profile->head);
-               profile->func->destroy(profile);
-       }
-
-       if (pm->cur != &pm->boot)
-               nouveau_pm_perflvl_set(dev, &pm->boot);
-
-       nouveau_perf_fini(dev);
-       nouveau_volt_fini(dev);
-
-#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
-       unregister_acpi_notifier(&pm->acpi_nb);
-#endif
-       nouveau_hwmon_fini(dev);
-       nouveau_sysfs_fini(dev);
-
-       nouveau_drm(dev)->pm = NULL;
-       kfree(pm);
-}
-
-void
-nouveau_pm_resume(struct drm_device *dev)
-{
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_pm_level *perflvl;
-
-       if (!pm->cur || pm->cur == &pm->boot)
-               return;
-
-       perflvl = pm->cur;
-       pm->cur = &pm->boot;
-       nouveau_pm_perflvl_set(dev, perflvl);
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
deleted file mode 100644 (file)
index 73b789c..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#ifndef __NOUVEAU_PM_H__
-#define __NOUVEAU_PM_H__
-
-#include <subdev/bios/pll.h>
-#include <subdev/clock.h>
-
-struct nouveau_pm_voltage_level {
-       u32 voltage; /* microvolts */
-       u8  vid;
-};
-
-struct nouveau_pm_voltage {
-       bool supported;
-       u8 version;
-       u8 vid_mask;
-
-       struct nouveau_pm_voltage_level *level;
-       int nr_level;
-};
-
-/* Exclusive upper limits */
-#define NV_MEM_CL_DDR2_MAX 8
-#define NV_MEM_WR_DDR2_MAX 9
-#define NV_MEM_CL_DDR3_MAX 17
-#define NV_MEM_WR_DDR3_MAX 17
-#define NV_MEM_CL_GDDR3_MAX 16
-#define NV_MEM_WR_GDDR3_MAX 18
-#define NV_MEM_CL_GDDR5_MAX 21
-#define NV_MEM_WR_GDDR5_MAX 20
-
-struct nouveau_pm_memtiming {
-       int id;
-
-       u32 reg[9];
-       u32 mr[4];
-
-       u8 tCWL;
-
-       u8 odt;
-       u8 drive_strength;
-};
-
-struct nouveau_pm_tbl_header {
-       u8 version;
-       u8 header_len;
-       u8 entry_cnt;
-       u8 entry_len;
-};
-
-struct nouveau_pm_tbl_entry {
-       u8 tWR;
-       u8 tWTR;
-       u8 tCL;
-       u8 tRC;
-       u8 empty_4;
-       u8 tRFC;        /* Byte 5 */
-       u8 empty_6;
-       u8 tRAS;        /* Byte 7 */
-       u8 empty_8;
-       u8 tRP;         /* Byte 9 */
-       u8 tRCDRD;
-       u8 tRCDWR;
-       u8 tRRD;
-       u8 tUNK_13;
-       u8 RAM_FT1;             /* 14, a bitmask of random RAM features */
-       u8 empty_15;
-       u8 tUNK_16;
-       u8 empty_17;
-       u8 tUNK_18;
-       u8 tCWL;
-       u8 tUNK_20, tUNK_21;
-};
-
-struct nouveau_pm_profile;
-struct nouveau_pm_profile_func {
-       void (*destroy)(struct nouveau_pm_profile *);
-       void (*init)(struct nouveau_pm_profile *);
-       void (*fini)(struct nouveau_pm_profile *);
-       struct nouveau_pm_level *(*select)(struct nouveau_pm_profile *);
-};
-
-struct nouveau_pm_profile {
-       const struct nouveau_pm_profile_func *func;
-       struct list_head head;
-       char name[8];
-};
-
-#define NOUVEAU_PM_MAX_LEVEL 8
-struct nouveau_pm_level {
-       struct nouveau_pm_profile profile;
-       struct device_attribute dev_attr;
-       char name[32];
-       int id;
-
-       struct nouveau_pm_memtiming timing;
-       u32 memory;
-       u16 memscript;
-
-       u32 core;
-       u32 shader;
-       u32 rop;
-       u32 copy;
-       u32 daemon;
-       u32 vdec;
-       u32 dom6;
-       u32 unka0;      /* nva3:nvc0 */
-       u32 hub01;      /* nvc0- */
-       u32 hub06;      /* nvc0- */
-       u32 hub07;      /* nvc0- */
-
-       u32 volt_min; /* microvolts */
-       u32 volt_max;
-       u8  fanspeed;
-};
-
-struct nouveau_pm_temp_sensor_constants {
-       u16 offset_constant;
-       s16 offset_mult;
-       s16 offset_div;
-       s16 slope_mult;
-       s16 slope_div;
-};
-
-struct nouveau_pm_threshold_temp {
-       s16 critical;
-       s16 down_clock;
-};
-
-struct nouveau_pm {
-       struct drm_device *dev;
-
-       struct nouveau_pm_voltage voltage;
-       struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL];
-       int nr_perflvl;
-       struct nouveau_pm_temp_sensor_constants sensor_constants;
-       struct nouveau_pm_threshold_temp threshold_temp;
-
-       struct nouveau_pm_profile *profile_ac;
-       struct nouveau_pm_profile *profile_dc;
-       struct nouveau_pm_profile *profile;
-       struct list_head profiles;
-
-       struct nouveau_pm_level boot;
-       struct nouveau_pm_level *cur;
-
-       struct device *hwmon;
-       struct notifier_block acpi_nb;
-
-       int  (*clocks_get)(struct drm_device *, struct nouveau_pm_level *);
-       void *(*clocks_pre)(struct drm_device *, struct nouveau_pm_level *);
-       int (*clocks_set)(struct drm_device *, void *);
-
-       int (*voltage_get)(struct drm_device *);
-       int (*voltage_set)(struct drm_device *, int voltage);
-};
-
-static inline struct nouveau_pm *
-nouveau_pm(struct drm_device *dev)
-{
-       return nouveau_drm(dev)->pm;
-}
-
-struct nouveau_mem_exec_func {
-       struct drm_device *dev;
-       void (*precharge)(struct nouveau_mem_exec_func *);
-       void (*refresh)(struct nouveau_mem_exec_func *);
-       void (*refresh_auto)(struct nouveau_mem_exec_func *, bool);
-       void (*refresh_self)(struct nouveau_mem_exec_func *, bool);
-       void (*wait)(struct nouveau_mem_exec_func *, u32 nsec);
-       u32  (*mrg)(struct nouveau_mem_exec_func *, int mr);
-       void (*mrs)(struct nouveau_mem_exec_func *, int mr, u32 data);
-       void (*clock_set)(struct nouveau_mem_exec_func *);
-       void (*timing_set)(struct nouveau_mem_exec_func *);
-       void *priv;
-};
-
-/* nouveau_mem.c */
-int  nouveau_mem_exec(struct nouveau_mem_exec_func *,
-                     struct nouveau_pm_level *);
-
-/* nouveau_pm.c */
-int  nouveau_pm_init(struct drm_device *dev);
-void nouveau_pm_fini(struct drm_device *dev);
-void nouveau_pm_resume(struct drm_device *dev);
-extern const struct nouveau_pm_profile_func nouveau_pm_static_profile_func;
-void nouveau_pm_trigger(struct drm_device *dev);
-
-/* nouveau_volt.c */
-void nouveau_volt_init(struct drm_device *);
-void nouveau_volt_fini(struct drm_device *);
-int  nouveau_volt_vid_lookup(struct drm_device *, int voltage);
-int  nouveau_volt_lvl_lookup(struct drm_device *, int vid);
-int  nouveau_voltage_gpio_get(struct drm_device *);
-int  nouveau_voltage_gpio_set(struct drm_device *, int voltage);
-
-/* nouveau_perf.c */
-void nouveau_perf_init(struct drm_device *);
-void nouveau_perf_fini(struct drm_device *);
-u8 *nouveau_perf_rammap(struct drm_device *, u32 freq, u8 *ver,
-                       u8 *hdr, u8 *cnt, u8 *len);
-u8 *nouveau_perf_ramcfg(struct drm_device *, u32 freq, u8 *ver, u8 *len);
-u8 *nouveau_perf_timing(struct drm_device *, u32 freq, u8 *ver, u8 *len);
-
-/* nouveau_mem.c */
-void nouveau_mem_timing_init(struct drm_device *);
-void nouveau_mem_timing_fini(struct drm_device *);
-
-/* nv04_pm.c */
-int nv04_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
-void *nv04_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *);
-int nv04_pm_clocks_set(struct drm_device *, void *);
-
-/* nv40_pm.c */
-int nv40_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
-void *nv40_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *);
-int nv40_pm_clocks_set(struct drm_device *, void *);
-int nv40_pm_pwm_get(struct drm_device *, int, u32 *, u32 *);
-int nv40_pm_pwm_set(struct drm_device *, int, u32, u32);
-
-/* nv50_pm.c */
-int nv50_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
-void *nv50_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *);
-int nv50_pm_clocks_set(struct drm_device *, void *);
-int nv50_pm_pwm_get(struct drm_device *, int, u32 *, u32 *);
-int nv50_pm_pwm_set(struct drm_device *, int, u32, u32);
-
-/* nva3_pm.c */
-int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
-void *nva3_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *);
-int nva3_pm_clocks_set(struct drm_device *, void *);
-
-/* nvc0_pm.c */
-int nvc0_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
-void *nvc0_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *);
-int nvc0_pm_clocks_set(struct drm_device *, void *);
-
-/* nouveau_mem.c */
-int  nouveau_mem_timing_calc(struct drm_device *, u32 freq,
-                            struct nouveau_pm_memtiming *);
-void nouveau_mem_timing_read(struct drm_device *,
-                            struct nouveau_pm_memtiming *);
-
-static inline int
-nva3_calc_pll(struct drm_device *dev, struct nvbios_pll *pll, u32 freq,
-             int *N, int *fN, int *M, int *P)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_clock *clk = nouveau_clock(device);
-       struct nouveau_pll_vals pv;
-       int ret;
-
-       ret = clk->pll_calc(clk, pll, freq, &pv);
-       *N = pv.N1;
-       *M = pv.M1;
-       *P = pv.log2P;
-       return ret;
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c
new file mode 100644 (file)
index 0000000..89201a1
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nouveau_sysfs.h"
+
+#include <core/object.h>
+#include <core/class.h>
+
+static inline struct drm_device *
+drm_device(struct device *d)
+{
+       return pci_get_drvdata(to_pci_dev(d));
+}
+
+#define snappendf(p,r,f,a...) do {                                             \
+       snprintf(p, r, f, ##a);                                                \
+       r -= strlen(p);                                                        \
+       p += strlen(p);                                                        \
+} while(0)
+
+static ssize_t
+nouveau_sysfs_pstate_get(struct device *d, struct device_attribute *a, char *b)
+{
+       struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d));
+       struct nv_control_pstate_info info;
+       size_t cnt = PAGE_SIZE;
+       char *buf = b;
+       int ret, i;
+
+       ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_INFO, &info, sizeof(info));
+       if (ret)
+               return ret;
+
+       for (i = 0; i < info.count + 1; i++) {
+               const s32 state = i < info.count ? i :
+                       NV_CONTROL_PSTATE_ATTR_STATE_CURRENT;
+               struct nv_control_pstate_attr attr = {
+                       .state = state,
+                       .index = 0,
+               };
+
+               ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_ATTR,
+                            &attr, sizeof(attr));
+               if (ret)
+                       return ret;
+
+               if (i < info.count)
+                       snappendf(buf, cnt, "%02x:", attr.state);
+               else
+                       snappendf(buf, cnt, "--:");
+
+               attr.index = 0;
+               do {
+                       attr.state = state;
+                       ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_ATTR,
+                                    &attr, sizeof(attr));
+                       if (ret)
+                               return ret;
+
+                       snappendf(buf, cnt, " %s %d", attr.name, attr.min);
+                       if (attr.min != attr.max)
+                               snappendf(buf, cnt, "-%d", attr.max);
+                       snappendf(buf, cnt, " %s", attr.unit);
+               } while (attr.index);
+
+               if ((state >= 0 && info.pstate == state) ||
+                   (state <  0 && info.ustate < 0))
+                       snappendf(buf, cnt, " *");
+               snappendf(buf, cnt, "\n");
+       }
+
+       return strlen(b);
+}
+
+static ssize_t
+nouveau_sysfs_pstate_set(struct device *d, struct device_attribute *a,
+                        const char *buf, size_t count)
+{
+       struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d));
+       struct nv_control_pstate_user args;
+       long value, ret;
+       char *tmp;
+
+       if ((tmp = strchr(buf, '\n')))
+               *tmp = '\0';
+
+       if (!strcasecmp(buf, "none"))
+               args.state = NV_CONTROL_PSTATE_USER_STATE_UNKNOWN;
+       else
+       if (!strcasecmp(buf, "auto"))
+               args.state = NV_CONTROL_PSTATE_USER_STATE_PERFMON;
+       else {
+               ret = kstrtol(buf, 16, &value);
+               if (ret)
+                       return ret;
+               args.state = value;
+       }
+
+       ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_USER, &args, sizeof(args));
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(pstate, S_IRUGO | S_IWUSR,
+                  nouveau_sysfs_pstate_get, nouveau_sysfs_pstate_set);
+
+void
+nouveau_sysfs_fini(struct drm_device *dev)
+{
+       struct nouveau_sysfs *sysfs = nouveau_sysfs(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+
+       if (sysfs->ctrl) {
+               device_remove_file(&dev->pdev->dev, &dev_attr_pstate);
+               nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL);
+       }
+
+       drm->sysfs = NULL;
+       kfree(sysfs);
+}
+
+int
+nouveau_sysfs_init(struct drm_device *dev)
+{
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_sysfs *sysfs;
+       int ret;
+
+       sysfs = drm->sysfs = kzalloc(sizeof(*sysfs), GFP_KERNEL);
+       if (!sysfs)
+               return -ENOMEM;
+
+       ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL,
+                                NV_CONTROL_CLASS, NULL, 0, &sysfs->ctrl);
+       if (ret == 0)
+               device_create_file(&dev->pdev->dev, &dev_attr_pstate);
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.h b/drivers/gpu/drm/nouveau/nouveau_sysfs.h
new file mode 100644 (file)
index 0000000..74b47f1
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __NOUVEAU_SYSFS_H__
+#define __NOUVEAU_SYSFS_H__
+
+#include "nouveau_drm.h"
+
+struct nouveau_sysfs {
+       struct nouveau_object *ctrl;
+};
+
+static inline struct nouveau_sysfs *
+nouveau_sysfs(struct drm_device *dev)
+{
+       return nouveau_drm(dev)->sysfs;
+}
+
+int  nouveau_sysfs_init(struct drm_device *);
+void nouveau_sysfs_fini(struct drm_device *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c
deleted file mode 100644 (file)
index 9976414..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <drm/drmP.h>
-
-#include "nouveau_drm.h"
-#include "nouveau_pm.h"
-
-#include <subdev/bios/gpio.h>
-#include <subdev/gpio.h>
-
-static const enum dcb_gpio_func_name vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 };
-static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]);
-
-int
-nouveau_voltage_gpio_get(struct drm_device *dev)
-{
-       struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage;
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_gpio *gpio = nouveau_gpio(device);
-       u8 vid = 0;
-       int i;
-
-       for (i = 0; i < nr_vidtag; i++) {
-               if (!(volt->vid_mask & (1 << i)))
-                       continue;
-
-               vid |= gpio->get(gpio, 0, vidtag[i], 0xff) << i;
-       }
-
-       return nouveau_volt_lvl_lookup(dev, vid);
-}
-
-int
-nouveau_voltage_gpio_set(struct drm_device *dev, int voltage)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_gpio *gpio = nouveau_gpio(device);
-       struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage;
-       int vid, i;
-
-       vid = nouveau_volt_vid_lookup(dev, voltage);
-       if (vid < 0)
-               return vid;
-
-       for (i = 0; i < nr_vidtag; i++) {
-               if (!(volt->vid_mask & (1 << i)))
-                       continue;
-
-               gpio->set(gpio, 0, vidtag[i], 0xff, !!(vid & (1 << i)));
-       }
-
-       return 0;
-}
-
-int
-nouveau_volt_vid_lookup(struct drm_device *dev, int voltage)
-{
-       struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage;
-       int i;
-
-       for (i = 0; i < volt->nr_level; i++) {
-               if (volt->level[i].voltage == voltage)
-                       return volt->level[i].vid;
-       }
-
-       return -ENOENT;
-}
-
-int
-nouveau_volt_lvl_lookup(struct drm_device *dev, int vid)
-{
-       struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage;
-       int i;
-
-       for (i = 0; i < volt->nr_level; i++) {
-               if (volt->level[i].vid == vid)
-                       return volt->level[i].voltage;
-       }
-
-       return -ENOENT;
-}
-
-void
-nouveau_volt_init(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
-       struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_pm_voltage *voltage = &pm->voltage;
-       struct nvbios *bios = &drm->vbios;
-       struct dcb_gpio_func func;
-       struct bit_entry P;
-       u8 *volt = NULL, *entry;
-       int i, headerlen, recordlen, entries, vidmask, vidshift;
-
-       if (bios->type == NVBIOS_BIT) {
-               if (bit_table(dev, 'P', &P))
-                       return;
-
-               if (P.version == 1)
-                       volt = ROMPTR(dev, P.data[16]);
-               else
-               if (P.version == 2)
-                       volt = ROMPTR(dev, P.data[12]);
-               else {
-                       NV_WARN(drm, "unknown volt for BIT P %d\n", P.version);
-               }
-       } else {
-               if (bios->data[bios->offset + 6] < 0x27) {
-                       NV_DEBUG(drm, "BMP version too old for voltage\n");
-                       return;
-               }
-
-               volt = ROMPTR(dev, bios->data[bios->offset + 0x98]);
-       }
-
-       if (!volt) {
-               NV_DEBUG(drm, "voltage table pointer invalid\n");
-               return;
-       }
-
-       switch (volt[0]) {
-       case 0x10:
-       case 0x11:
-       case 0x12:
-               headerlen = 5;
-               recordlen = volt[1];
-               entries   = volt[2];
-               vidshift  = 0;
-               vidmask   = volt[4];
-               break;
-       case 0x20:
-               headerlen = volt[1];
-               recordlen = volt[3];
-               entries   = volt[2];
-               vidshift  = 0; /* could be vidshift like 0x30? */
-               vidmask   = volt[5];
-               break;
-       case 0x30:
-               headerlen = volt[1];
-               recordlen = volt[2];
-               entries   = volt[3];
-               vidmask   = volt[4];
-               /* no longer certain what volt[5] is, if it's related to
-                * the vid shift then it's definitely not a function of
-                * how many bits are set.
-                *
-                * after looking at a number of nva3+ vbios images, they
-                * all seem likely to have a static shift of 2.. lets
-                * go with that for now until proven otherwise.
-                */
-               vidshift  = 2;
-               break;
-       case 0x40:
-               headerlen = volt[1];
-               recordlen = volt[2];
-               entries   = volt[3]; /* not a clue what the entries are for.. */
-               vidmask   = volt[11]; /* guess.. */
-               vidshift  = 0;
-               break;
-       default:
-               NV_WARN(drm, "voltage table 0x%02x unknown\n", volt[0]);
-               return;
-       }
-
-       /* validate vid mask */
-       voltage->vid_mask = vidmask;
-       if (!voltage->vid_mask)
-               return;
-
-       i = 0;
-       while (vidmask) {
-               if (i > nr_vidtag) {
-                       NV_DEBUG(drm, "vid bit %d unknown\n", i);
-                       return;
-               }
-
-               if (gpio && gpio->find(gpio, 0, vidtag[i], 0xff, &func)) {
-                       NV_DEBUG(drm, "vid bit %d has no gpio tag\n", i);
-                       return;
-               }
-
-               vidmask >>= 1;
-               i++;
-       }
-
-       /* parse vbios entries into common format */
-       voltage->version = volt[0];
-       if (voltage->version < 0x40) {
-               voltage->nr_level = entries;
-               voltage->level =
-                       kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL);
-               if (!voltage->level)
-                       return;
-
-               entry = volt + headerlen;
-               for (i = 0; i < entries; i++, entry += recordlen) {
-                       voltage->level[i].voltage = entry[0] * 10000;
-                       voltage->level[i].vid     = entry[1] >> vidshift;
-               }
-       } else {
-               u32 volt_uv = ROM32(volt[4]);
-               s16 step_uv = ROM16(volt[8]);
-               u8 vid;
-
-               voltage->nr_level = voltage->vid_mask + 1;
-               voltage->level = kcalloc(voltage->nr_level,
-                                        sizeof(*voltage->level), GFP_KERNEL);
-               if (!voltage->level)
-                       return;
-
-               for (vid = 0; vid <= voltage->vid_mask; vid++) {
-                       voltage->level[vid].voltage = volt_uv;
-                       voltage->level[vid].vid = vid;
-                       volt_uv += step_uv;
-               }
-       }
-
-       voltage->supported = true;
-}
-
-void
-nouveau_volt_fini(struct drm_device *dev)
-{
-       struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage;
-
-       kfree(volt->level);
-}
diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c
deleted file mode 100644 (file)
index 27afc0e..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <drm/drmP.h>
-#include "nouveau_drm.h"
-#include "nouveau_reg.h"
-#include "dispnv04/hw.h"
-#include "nouveau_pm.h"
-
-#include <subdev/bios/pll.h>
-#include <subdev/clock.h>
-#include <subdev/timer.h>
-
-int
-nv04_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       int ret;
-
-       ret = nouveau_hw_get_clock(dev, PLL_CORE);
-       if (ret < 0)
-               return ret;
-       perflvl->core = ret;
-
-       ret = nouveau_hw_get_clock(dev, PLL_MEMORY);
-       if (ret < 0)
-               return ret;
-       perflvl->memory = ret;
-
-       return 0;
-}
-
-struct nv04_pm_clock {
-       struct nvbios_pll pll;
-       struct nouveau_pll_vals calc;
-};
-
-struct nv04_pm_state {
-       struct nv04_pm_clock core;
-       struct nv04_pm_clock memory;
-};
-
-static int
-calc_pll(struct drm_device *dev, u32 id, int khz, struct nv04_pm_clock *clk)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_bios *bios = nouveau_bios(device);
-       struct nouveau_clock *pclk = nouveau_clock(device);
-       int ret;
-
-       ret = nvbios_pll_parse(bios, id, &clk->pll);
-       if (ret)
-               return ret;
-
-       ret = pclk->pll_calc(pclk, &clk->pll, khz, &clk->calc);
-       if (!ret)
-               return -EINVAL;
-
-       return 0;
-}
-
-void *
-nv04_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       struct nv04_pm_state *info;
-       int ret;
-
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return ERR_PTR(-ENOMEM);
-
-       ret = calc_pll(dev, PLL_CORE, perflvl->core, &info->core);
-       if (ret)
-               goto error;
-
-       if (perflvl->memory) {
-               ret = calc_pll(dev, PLL_MEMORY, perflvl->memory, &info->memory);
-               if (ret)
-                       goto error;
-       }
-
-       return info;
-error:
-       kfree(info);
-       return ERR_PTR(ret);
-}
-
-static void
-prog_pll(struct drm_device *dev, struct nv04_pm_clock *clk)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_clock *pclk = nouveau_clock(device);
-       u32 reg = clk->pll.reg;
-
-       /* thank the insane nouveau_hw_setpll() interface for this */
-       if (device->card_type >= NV_40)
-               reg += 4;
-
-       pclk->pll_prog(pclk, reg, &clk->calc);
-}
-
-int
-nv04_pm_clocks_set(struct drm_device *dev, void *pre_state)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_timer *ptimer = nouveau_timer(device);
-       struct nv04_pm_state *state = pre_state;
-
-       prog_pll(dev, &state->core);
-
-       if (state->memory.pll.reg) {
-               prog_pll(dev, &state->memory);
-               if (device->card_type < NV_30) {
-                       if (device->card_type == NV_20)
-                               nv_mask(device, 0x1002c4, 0, 1 << 20);
-
-                       /* Reset the DLLs */
-                       nv_mask(device, 0x1002c0, 0, 1 << 8);
-               }
-       }
-
-       nv_ofuncs(ptimer)->init(nv_object(ptimer));
-
-       kfree(state);
-       return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c
deleted file mode 100644 (file)
index 625f80d..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <drm/drmP.h>
-#include "nouveau_drm.h"
-#include "nouveau_bios.h"
-#include "nouveau_pm.h"
-#include "dispnv04/hw.h"
-
-#include <subdev/bios/pll.h>
-#include <subdev/clock.h>
-#include <subdev/timer.h>
-
-#include <engine/fifo.h>
-
-#define min2(a,b) ((a) < (b) ? (a) : (b))
-
-static u32
-read_pll_1(struct drm_device *dev, u32 reg)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 ctrl = nv_rd32(device, reg + 0x00);
-       int P = (ctrl & 0x00070000) >> 16;
-       int N = (ctrl & 0x0000ff00) >> 8;
-       int M = (ctrl & 0x000000ff) >> 0;
-       u32 ref = 27000, clk = 0;
-
-       if (ctrl & 0x80000000)
-               clk = ref * N / M;
-
-       return clk >> P;
-}
-
-static u32
-read_pll_2(struct drm_device *dev, u32 reg)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 ctrl = nv_rd32(device, reg + 0x00);
-       u32 coef = nv_rd32(device, reg + 0x04);
-       int N2 = (coef & 0xff000000) >> 24;
-       int M2 = (coef & 0x00ff0000) >> 16;
-       int N1 = (coef & 0x0000ff00) >> 8;
-       int M1 = (coef & 0x000000ff) >> 0;
-       int P = (ctrl & 0x00070000) >> 16;
-       u32 ref = 27000, clk = 0;
-
-       if ((ctrl & 0x80000000) && M1) {
-               clk = ref * N1 / M1;
-               if ((ctrl & 0x40000100) == 0x40000000) {
-                       if (M2)
-                               clk = clk * N2 / M2;
-                       else
-                               clk = 0;
-               }
-       }
-
-       return clk >> P;
-}
-
-static u32
-read_clk(struct drm_device *dev, u32 src)
-{
-       switch (src) {
-       case 3:
-               return read_pll_2(dev, 0x004000);
-       case 2:
-               return read_pll_1(dev, 0x004008);
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-int
-nv40_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 ctrl = nv_rd32(device, 0x00c040);
-
-       perflvl->core   = read_clk(dev, (ctrl & 0x00000003) >> 0);
-       perflvl->shader = read_clk(dev, (ctrl & 0x00000030) >> 4);
-       perflvl->memory = read_pll_2(dev, 0x4020);
-       return 0;
-}
-
-struct nv40_pm_state {
-       u32 ctrl;
-       u32 npll_ctrl;
-       u32 npll_coef;
-       u32 spll;
-       u32 mpll_ctrl;
-       u32 mpll_coef;
-};
-
-static int
-nv40_calc_pll(struct drm_device *dev, u32 reg, struct nvbios_pll *pll,
-             u32 clk, int *N1, int *M1, int *N2, int *M2, int *log2P)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_bios *bios = nouveau_bios(device);
-       struct nouveau_clock *pclk = nouveau_clock(device);
-       struct nouveau_pll_vals coef;
-       int ret;
-
-       ret = nvbios_pll_parse(bios, reg, pll);
-       if (ret)
-               return ret;
-
-       if (clk < pll->vco1.max_freq)
-               pll->vco2.max_freq = 0;
-
-       ret = pclk->pll_calc(pclk, pll, clk, &coef);
-       if (ret == 0)
-               return -ERANGE;
-
-       *N1 = coef.N1;
-       *M1 = coef.M1;
-       if (N2 && M2) {
-               if (pll->vco2.max_freq) {
-                       *N2 = coef.N2;
-                       *M2 = coef.M2;
-               } else {
-                       *N2 = 1;
-                       *M2 = 1;
-               }
-       }
-       *log2P = coef.log2P;
-       return 0;
-}
-
-void *
-nv40_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       struct nv40_pm_state *info;
-       struct nvbios_pll pll;
-       int N1, N2, M1, M2, log2P;
-       int ret;
-
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return ERR_PTR(-ENOMEM);
-
-       /* core/geometric clock */
-       ret = nv40_calc_pll(dev, 0x004000, &pll, perflvl->core,
-                           &N1, &M1, &N2, &M2, &log2P);
-       if (ret < 0)
-               goto out;
-
-       if (N2 == M2) {
-               info->npll_ctrl = 0x80000100 | (log2P << 16);
-               info->npll_coef = (N1 << 8) | M1;
-       } else {
-               info->npll_ctrl = 0xc0000000 | (log2P << 16);
-               info->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
-       }
-
-       /* use the second PLL for shader/rop clock, if it differs from core */
-       if (perflvl->shader && perflvl->shader != perflvl->core) {
-               ret = nv40_calc_pll(dev, 0x004008, &pll, perflvl->shader,
-                                   &N1, &M1, NULL, NULL, &log2P);
-               if (ret < 0)
-                       goto out;
-
-               info->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1;
-               info->ctrl = 0x00000223;
-       } else {
-               info->spll = 0x00000000;
-               info->ctrl = 0x00000333;
-       }
-
-       /* memory clock */
-       if (!perflvl->memory) {
-               info->mpll_ctrl = 0x00000000;
-               goto out;
-       }
-
-       ret = nv40_calc_pll(dev, 0x004020, &pll, perflvl->memory,
-                           &N1, &M1, &N2, &M2, &log2P);
-       if (ret < 0)
-               goto out;
-
-       info->mpll_ctrl  = 0x80000000 | (log2P << 16);
-       info->mpll_ctrl |= min2(pll.bias_p + log2P, pll.max_p) << 20;
-       if (N2 == M2) {
-               info->mpll_ctrl |= 0x00000100;
-               info->mpll_coef  = (N1 << 8) | M1;
-       } else {
-               info->mpll_ctrl |= 0x40000000;
-               info->mpll_coef  = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
-       }
-
-out:
-       if (ret < 0) {
-               kfree(info);
-               info = ERR_PTR(ret);
-       }
-       return info;
-}
-
-static bool
-nv40_pm_gr_idle(void *data)
-{
-       struct drm_device *dev = data;
-       struct nouveau_device *device = nouveau_dev(dev);
-
-       if ((nv_rd32(device, 0x400760) & 0x000000f0) >> 4 !=
-           (nv_rd32(device, 0x400760) & 0x0000000f))
-               return false;
-
-       if (nv_rd32(device, 0x400700))
-               return false;
-
-       return true;
-}
-
-int
-nv40_pm_clocks_set(struct drm_device *dev, void *pre_state)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_fifo *pfifo = nouveau_fifo(device);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nv40_pm_state *info = pre_state;
-       unsigned long flags;
-       struct bit_entry M;
-       u32 crtc_mask = 0;
-       u8 sr1[2];
-       int i, ret = -EAGAIN;
-
-       /* determine which CRTCs are active, fetch VGA_SR1 for each */
-       for (i = 0; i < 2; i++) {
-               u32 vbl = nv_rd32(device, 0x600808 + (i * 0x2000));
-               u32 cnt = 0;
-               do {
-                       if (vbl != nv_rd32(device, 0x600808 + (i * 0x2000))) {
-                               nv_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
-                               sr1[i] = nv_rd08(device, 0x0c03c5 + (i * 0x2000));
-                               if (!(sr1[i] & 0x20))
-                                       crtc_mask |= (1 << i);
-                               break;
-                       }
-                       udelay(1);
-               } while (cnt++ < 32);
-       }
-
-       /* halt and idle engines */
-       pfifo->pause(pfifo, &flags);
-
-       if (!nv_wait_cb(device, nv40_pm_gr_idle, dev))
-               goto resume;
-
-       ret = 0;
-
-       /* set engine clocks */
-       nv_mask(device, 0x00c040, 0x00000333, 0x00000000);
-       nv_wr32(device, 0x004004, info->npll_coef);
-       nv_mask(device, 0x004000, 0xc0070100, info->npll_ctrl);
-       nv_mask(device, 0x004008, 0xc007ffff, info->spll);
-       mdelay(5);
-       nv_mask(device, 0x00c040, 0x00000333, info->ctrl);
-
-       if (!info->mpll_ctrl)
-               goto resume;
-
-       /* wait for vblank start on active crtcs, disable memory access */
-       for (i = 0; i < 2; i++) {
-               if (!(crtc_mask & (1 << i)))
-                       continue;
-               nv_wait(device, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000);
-               nv_wait(device, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
-               nv_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
-               nv_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
-       }
-
-       /* prepare ram for reclocking */
-       nv_wr32(device, 0x1002d4, 0x00000001); /* precharge */
-       nv_wr32(device, 0x1002d0, 0x00000001); /* refresh */
-       nv_wr32(device, 0x1002d0, 0x00000001); /* refresh */
-       nv_mask(device, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
-       nv_wr32(device, 0x1002dc, 0x00000001); /* enable self-refresh */
-
-       /* change the PLL of each memory partition */
-       nv_mask(device, 0x00c040, 0x0000c000, 0x00000000);
-       switch (nv_device(drm->device)->chipset) {
-       case 0x40:
-       case 0x45:
-       case 0x41:
-       case 0x42:
-       case 0x47:
-               nv_mask(device, 0x004044, 0xc0771100, info->mpll_ctrl);
-               nv_mask(device, 0x00402c, 0xc0771100, info->mpll_ctrl);
-               nv_wr32(device, 0x004048, info->mpll_coef);
-               nv_wr32(device, 0x004030, info->mpll_coef);
-       case 0x43:
-       case 0x49:
-       case 0x4b:
-               nv_mask(device, 0x004038, 0xc0771100, info->mpll_ctrl);
-               nv_wr32(device, 0x00403c, info->mpll_coef);
-       default:
-               nv_mask(device, 0x004020, 0xc0771100, info->mpll_ctrl);
-               nv_wr32(device, 0x004024, info->mpll_coef);
-               break;
-       }
-       udelay(100);
-       nv_mask(device, 0x00c040, 0x0000c000, 0x0000c000);
-
-       /* re-enable normal operation of memory controller */
-       nv_wr32(device, 0x1002dc, 0x00000000);
-       nv_mask(device, 0x100210, 0x80000000, 0x80000000);
-       udelay(100);
-
-       /* execute memory reset script from vbios */
-       if (!bit_table(dev, 'M', &M))
-               nouveau_bios_run_init_table(dev, ROM16(M.data[0]), NULL, 0);
-
-       /* make sure we're in vblank (hopefully the same one as before), and
-        * then re-enable crtc memory access
-        */
-       for (i = 0; i < 2; i++) {
-               if (!(crtc_mask & (1 << i)))
-                       continue;
-               nv_wait(device, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
-               nv_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
-               nv_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i]);
-       }
-
-       /* resume engines */
-resume:
-       pfifo->start(pfifo, &flags);
-       kfree(info);
-       return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
deleted file mode 100644 (file)
index 4efc33f..0000000
+++ /dev/null
@@ -1,855 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <drm/drmP.h>
-#include "nouveau_drm.h"
-#include "nouveau_bios.h"
-#include "dispnv04/hw.h"
-#include "nouveau_pm.h"
-#include "nouveau_hwsq.h"
-
-#include "nv50_display.h"
-
-#include <subdev/bios/pll.h>
-#include <subdev/clock.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-enum clk_src {
-       clk_src_crystal,
-       clk_src_href,
-       clk_src_hclk,
-       clk_src_hclkm3,
-       clk_src_hclkm3d2,
-       clk_src_host,
-       clk_src_nvclk,
-       clk_src_sclk,
-       clk_src_mclk,
-       clk_src_vdec,
-       clk_src_dom6
-};
-
-static u32 read_clk(struct drm_device *, enum clk_src);
-
-static u32
-read_div(struct drm_device *dev)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-
-       switch (nv_device(drm->device)->chipset) {
-       case 0x50: /* it exists, but only has bit 31, not the dividers.. */
-       case 0x84:
-       case 0x86:
-       case 0x98:
-       case 0xa0:
-               return nv_rd32(device, 0x004700);
-       case 0x92:
-       case 0x94:
-       case 0x96:
-               return nv_rd32(device, 0x004800);
-       default:
-               return 0x00000000;
-       }
-}
-
-static u32
-read_pll_src(struct drm_device *dev, u32 base)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       u32 coef, ref = read_clk(dev, clk_src_crystal);
-       u32 rsel = nv_rd32(device, 0x00e18c);
-       int P, N, M, id;
-
-       switch (nv_device(drm->device)->chipset) {
-       case 0x50:
-       case 0xa0:
-               switch (base) {
-               case 0x4020:
-               case 0x4028: id = !!(rsel & 0x00000004); break;
-               case 0x4008: id = !!(rsel & 0x00000008); break;
-               case 0x4030: id = 0; break;
-               default:
-                       NV_ERROR(drm, "ref: bad pll 0x%06x\n", base);
-                       return 0;
-               }
-
-               coef = nv_rd32(device, 0x00e81c + (id * 0x0c));
-               ref *=  (coef & 0x01000000) ? 2 : 4;
-               P    =  (coef & 0x00070000) >> 16;
-               N    = ((coef & 0x0000ff00) >> 8) + 1;
-               M    = ((coef & 0x000000ff) >> 0) + 1;
-               break;
-       case 0x84:
-       case 0x86:
-       case 0x92:
-               coef = nv_rd32(device, 0x00e81c);
-               P    = (coef & 0x00070000) >> 16;
-               N    = (coef & 0x0000ff00) >> 8;
-               M    = (coef & 0x000000ff) >> 0;
-               break;
-       case 0x94:
-       case 0x96:
-       case 0x98:
-               rsel = nv_rd32(device, 0x00c050);
-               switch (base) {
-               case 0x4020: rsel = (rsel & 0x00000003) >> 0; break;
-               case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break;
-               case 0x4028: rsel = (rsel & 0x00001800) >> 11; break;
-               case 0x4030: rsel = 3; break;
-               default:
-                       NV_ERROR(drm, "ref: bad pll 0x%06x\n", base);
-                       return 0;
-               }
-
-               switch (rsel) {
-               case 0: id = 1; break;
-               case 1: return read_clk(dev, clk_src_crystal);
-               case 2: return read_clk(dev, clk_src_href);
-               case 3: id = 0; break;
-               }
-
-               coef =  nv_rd32(device, 0x00e81c + (id * 0x28));
-               P    = (nv_rd32(device, 0x00e824 + (id * 0x28)) >> 16) & 7;
-               P   += (coef & 0x00070000) >> 16;
-               N    = (coef & 0x0000ff00) >> 8;
-               M    = (coef & 0x000000ff) >> 0;
-               break;
-       default:
-               BUG_ON(1);
-       }
-
-       if (M)
-               return (ref * N / M) >> P;
-       return 0;
-}
-
-static u32
-read_pll_ref(struct drm_device *dev, u32 base)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       u32 src, mast = nv_rd32(device, 0x00c040);
-
-       switch (base) {
-       case 0x004028:
-               src = !!(mast & 0x00200000);
-               break;
-       case 0x004020:
-               src = !!(mast & 0x00400000);
-               break;
-       case 0x004008:
-               src = !!(mast & 0x00010000);
-               break;
-       case 0x004030:
-               src = !!(mast & 0x02000000);
-               break;
-       case 0x00e810:
-               return read_clk(dev, clk_src_crystal);
-       default:
-               NV_ERROR(drm, "bad pll 0x%06x\n", base);
-               return 0;
-       }
-
-       if (src)
-               return read_clk(dev, clk_src_href);
-       return read_pll_src(dev, base);
-}
-
-static u32
-read_pll(struct drm_device *dev, u32 base)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       u32 mast = nv_rd32(device, 0x00c040);
-       u32 ctrl = nv_rd32(device, base + 0);
-       u32 coef = nv_rd32(device, base + 4);
-       u32 ref = read_pll_ref(dev, base);
-       u32 clk = 0;
-       int N1, N2, M1, M2;
-
-       if (base == 0x004028 && (mast & 0x00100000)) {
-               /* wtf, appears to only disable post-divider on nva0 */
-               if (nv_device(drm->device)->chipset != 0xa0)
-                       return read_clk(dev, clk_src_dom6);
-       }
-
-       N2 = (coef & 0xff000000) >> 24;
-       M2 = (coef & 0x00ff0000) >> 16;
-       N1 = (coef & 0x0000ff00) >> 8;
-       M1 = (coef & 0x000000ff);
-       if ((ctrl & 0x80000000) && M1) {
-               clk = ref * N1 / M1;
-               if ((ctrl & 0x40000100) == 0x40000000) {
-                       if (M2)
-                               clk = clk * N2 / M2;
-                       else
-                               clk = 0;
-               }
-       }
-
-       return clk;
-}
-
-static u32
-read_clk(struct drm_device *dev, enum clk_src src)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       u32 mast = nv_rd32(device, 0x00c040);
-       u32 P = 0;
-
-       switch (src) {
-       case clk_src_crystal:
-               return device->crystal;
-       case clk_src_href:
-               return 100000; /* PCIE reference clock */
-       case clk_src_hclk:
-               return read_clk(dev, clk_src_href) * 27778 / 10000;
-       case clk_src_hclkm3:
-               return read_clk(dev, clk_src_hclk) * 3;
-       case clk_src_hclkm3d2:
-               return read_clk(dev, clk_src_hclk) * 3 / 2;
-       case clk_src_host:
-               switch (mast & 0x30000000) {
-               case 0x00000000: return read_clk(dev, clk_src_href);
-               case 0x10000000: break;
-               case 0x20000000: /* !0x50 */
-               case 0x30000000: return read_clk(dev, clk_src_hclk);
-               }
-               break;
-       case clk_src_nvclk:
-               if (!(mast & 0x00100000))
-                       P = (nv_rd32(device, 0x004028) & 0x00070000) >> 16;
-               switch (mast & 0x00000003) {
-               case 0x00000000: return read_clk(dev, clk_src_crystal) >> P;
-               case 0x00000001: return read_clk(dev, clk_src_dom6);
-               case 0x00000002: return read_pll(dev, 0x004020) >> P;
-               case 0x00000003: return read_pll(dev, 0x004028) >> P;
-               }
-               break;
-       case clk_src_sclk:
-               P = (nv_rd32(device, 0x004020) & 0x00070000) >> 16;
-               switch (mast & 0x00000030) {
-               case 0x00000000:
-                       if (mast & 0x00000080)
-                               return read_clk(dev, clk_src_host) >> P;
-                       return read_clk(dev, clk_src_crystal) >> P;
-               case 0x00000010: break;
-               case 0x00000020: return read_pll(dev, 0x004028) >> P;
-               case 0x00000030: return read_pll(dev, 0x004020) >> P;
-               }
-               break;
-       case clk_src_mclk:
-               P = (nv_rd32(device, 0x004008) & 0x00070000) >> 16;
-               if (nv_rd32(device, 0x004008) & 0x00000200) {
-                       switch (mast & 0x0000c000) {
-                       case 0x00000000:
-                               return read_clk(dev, clk_src_crystal) >> P;
-                       case 0x00008000:
-                       case 0x0000c000:
-                               return read_clk(dev, clk_src_href) >> P;
-                       }
-               } else {
-                       return read_pll(dev, 0x004008) >> P;
-               }
-               break;
-       case clk_src_vdec:
-               P = (read_div(dev) & 0x00000700) >> 8;
-               switch (nv_device(drm->device)->chipset) {
-               case 0x84:
-               case 0x86:
-               case 0x92:
-               case 0x94:
-               case 0x96:
-               case 0xa0:
-                       switch (mast & 0x00000c00) {
-                       case 0x00000000:
-                               if (nv_device(drm->device)->chipset == 0xa0) /* wtf?? */
-                                       return read_clk(dev, clk_src_nvclk) >> P;
-                               return read_clk(dev, clk_src_crystal) >> P;
-                       case 0x00000400:
-                               return 0;
-                       case 0x00000800:
-                               if (mast & 0x01000000)
-                                       return read_pll(dev, 0x004028) >> P;
-                               return read_pll(dev, 0x004030) >> P;
-                       case 0x00000c00:
-                               return read_clk(dev, clk_src_nvclk) >> P;
-                       }
-                       break;
-               case 0x98:
-                       switch (mast & 0x00000c00) {
-                       case 0x00000000:
-                               return read_clk(dev, clk_src_nvclk) >> P;
-                       case 0x00000400:
-                               return 0;
-                       case 0x00000800:
-                               return read_clk(dev, clk_src_hclkm3d2) >> P;
-                       case 0x00000c00:
-                               return read_clk(dev, clk_src_mclk) >> P;
-                       }
-                       break;
-               }
-               break;
-       case clk_src_dom6:
-               switch (nv_device(drm->device)->chipset) {
-               case 0x50:
-               case 0xa0:
-                       return read_pll(dev, 0x00e810) >> 2;
-               case 0x84:
-               case 0x86:
-               case 0x92:
-               case 0x94:
-               case 0x96:
-               case 0x98:
-                       P = (read_div(dev) & 0x00000007) >> 0;
-                       switch (mast & 0x0c000000) {
-                       case 0x00000000: return read_clk(dev, clk_src_href);
-                       case 0x04000000: break;
-                       case 0x08000000: return read_clk(dev, clk_src_hclk);
-                       case 0x0c000000:
-                               return read_clk(dev, clk_src_hclkm3) >> P;
-                       }
-                       break;
-               default:
-                       break;
-               }
-       default:
-               break;
-       }
-
-       NV_DEBUG(drm, "unknown clock source %d 0x%08x\n", src, mast);
-       return 0;
-}
-
-int
-nv50_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       if (nv_device(drm->device)->chipset == 0xaa ||
-           nv_device(drm->device)->chipset == 0xac)
-               return 0;
-
-       perflvl->core   = read_clk(dev, clk_src_nvclk);
-       perflvl->shader = read_clk(dev, clk_src_sclk);
-       perflvl->memory = read_clk(dev, clk_src_mclk);
-       if (nv_device(drm->device)->chipset != 0x50) {
-               perflvl->vdec = read_clk(dev, clk_src_vdec);
-               perflvl->dom6 = read_clk(dev, clk_src_dom6);
-       }
-
-       return 0;
-}
-
-struct nv50_pm_state {
-       struct nouveau_pm_level *perflvl;
-       struct hwsq_ucode eclk_hwsq;
-       struct hwsq_ucode mclk_hwsq;
-       u32 mscript;
-       u32 mmast;
-       u32 mctrl;
-       u32 mcoef;
-};
-
-static u32
-calc_pll(struct drm_device *dev, u32 reg, struct nvbios_pll *pll,
-        u32 clk, int *N1, int *M1, int *log2P)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_bios *bios = nouveau_bios(device);
-       struct nouveau_clock *pclk = nouveau_clock(device);
-       struct nouveau_pll_vals coef;
-       int ret;
-
-       ret = nvbios_pll_parse(bios, reg, pll);
-       if (ret)
-               return 0;
-
-       pll->vco2.max_freq = 0;
-       pll->refclk = read_pll_ref(dev, reg);
-       if (!pll->refclk)
-               return 0;
-
-       ret = pclk->pll_calc(pclk, pll, clk, &coef);
-       if (ret == 0)
-               return 0;
-
-       *N1 = coef.N1;
-       *M1 = coef.M1;
-       *log2P = coef.log2P;
-       return ret;
-}
-
-static inline u32
-calc_div(u32 src, u32 target, int *div)
-{
-       u32 clk0 = src, clk1 = src;
-       for (*div = 0; *div <= 7; (*div)++) {
-               if (clk0 <= target) {
-                       clk1 = clk0 << (*div ? 1 : 0);
-                       break;
-               }
-               clk0 >>= 1;
-       }
-
-       if (target - clk0 <= clk1 - target)
-               return clk0;
-       (*div)--;
-       return clk1;
-}
-
-static inline u32
-clk_same(u32 a, u32 b)
-{
-       return ((a / 1000) == (b / 1000));
-}
-
-static void
-mclk_precharge(struct nouveau_mem_exec_func *exec)
-{
-       struct nv50_pm_state *info = exec->priv;
-       struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-
-       hwsq_wr32(hwsq, 0x1002d4, 0x00000001);
-}
-
-static void
-mclk_refresh(struct nouveau_mem_exec_func *exec)
-{
-       struct nv50_pm_state *info = exec->priv;
-       struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-
-       hwsq_wr32(hwsq, 0x1002d0, 0x00000001);
-}
-
-static void
-mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable)
-{
-       struct nv50_pm_state *info = exec->priv;
-       struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-
-       hwsq_wr32(hwsq, 0x100210, enable ? 0x80000000 : 0x00000000);
-}
-
-static void
-mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable)
-{
-       struct nv50_pm_state *info = exec->priv;
-       struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-
-       hwsq_wr32(hwsq, 0x1002dc, enable ? 0x00000001 : 0x00000000);
-}
-
-static void
-mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec)
-{
-       struct nv50_pm_state *info = exec->priv;
-       struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-
-       if (nsec > 1000)
-               hwsq_usec(hwsq, (nsec + 500) / 1000);
-}
-
-static u32
-mclk_mrg(struct nouveau_mem_exec_func *exec, int mr)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       if (mr <= 1)
-               return nv_rd32(device, 0x1002c0 + ((mr - 0) * 4));
-       if (mr <= 3)
-               return nv_rd32(device, 0x1002e0 + ((mr - 2) * 4));
-       return 0;
-}
-
-static void
-mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nouveau_fb *pfb = nouveau_fb(device);
-       struct nv50_pm_state *info = exec->priv;
-       struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-
-       if (mr <= 1) {
-               if (pfb->ram->ranks > 1)
-                       hwsq_wr32(hwsq, 0x1002c8 + ((mr - 0) * 4), data);
-               hwsq_wr32(hwsq, 0x1002c0 + ((mr - 0) * 4), data);
-       } else
-       if (mr <= 3) {
-               if (pfb->ram->ranks > 1)
-                       hwsq_wr32(hwsq, 0x1002e8 + ((mr - 2) * 4), data);
-               hwsq_wr32(hwsq, 0x1002e0 + ((mr - 2) * 4), data);
-       }
-}
-
-static void
-mclk_clock_set(struct nouveau_mem_exec_func *exec)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nv50_pm_state *info = exec->priv;
-       struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-       u32 ctrl = nv_rd32(device, 0x004008);
-
-       info->mmast = nv_rd32(device, 0x00c040);
-       info->mmast &= ~0xc0000000; /* get MCLK_2 from HREF */
-       info->mmast |=  0x0000c000; /* use MCLK_2 as MPLL_BYPASS clock */
-
-       hwsq_wr32(hwsq, 0xc040, info->mmast);
-       hwsq_wr32(hwsq, 0x4008, ctrl | 0x00000200); /* bypass MPLL */
-       if (info->mctrl & 0x80000000)
-               hwsq_wr32(hwsq, 0x400c, info->mcoef);
-       hwsq_wr32(hwsq, 0x4008, info->mctrl);
-}
-
-static void
-mclk_timing_set(struct nouveau_mem_exec_func *exec)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nv50_pm_state *info = exec->priv;
-       struct nouveau_pm_level *perflvl = info->perflvl;
-       struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-       int i;
-
-       for (i = 0; i < 9; i++) {
-               u32 reg = 0x100220 + (i * 4);
-               u32 val = nv_rd32(device, reg);
-               if (val != perflvl->timing.reg[i])
-                       hwsq_wr32(hwsq, reg, perflvl->timing.reg[i]);
-       }
-}
-
-static int
-calc_mclk(struct drm_device *dev, struct nouveau_pm_level *perflvl,
-         struct nv50_pm_state *info)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 crtc_mask = 0; /*XXX: nv50_display_active_crtcs(dev); */
-       struct nouveau_mem_exec_func exec = {
-               .dev = dev,
-               .precharge = mclk_precharge,
-               .refresh = mclk_refresh,
-               .refresh_auto = mclk_refresh_auto,
-               .refresh_self = mclk_refresh_self,
-               .wait = mclk_wait,
-               .mrg = mclk_mrg,
-               .mrs = mclk_mrs,
-               .clock_set = mclk_clock_set,
-               .timing_set = mclk_timing_set,
-               .priv = info
-       };
-       struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-       struct nvbios_pll pll;
-       int N, M, P;
-       int ret;
-
-       /* use pcie refclock if possible, otherwise use mpll */
-       info->mctrl  = nv_rd32(device, 0x004008);
-       info->mctrl &= ~0x81ff0200;
-       if (clk_same(perflvl->memory, read_clk(dev, clk_src_href))) {
-               info->mctrl |= 0x00000200 | (pll.bias_p << 19);
-       } else {
-               ret = calc_pll(dev, 0x4008, &pll, perflvl->memory, &N, &M, &P);
-               if (ret == 0)
-                       return -EINVAL;
-
-               info->mctrl |= 0x80000000 | (P << 22) | (P << 16);
-               info->mctrl |= pll.bias_p << 19;
-               info->mcoef  = (N << 8) | M;
-       }
-
-       /* build the ucode which will reclock the memory for us */
-       hwsq_init(hwsq);
-       if (crtc_mask) {
-               hwsq_op5f(hwsq, crtc_mask, 0x00); /* wait for scanout */
-               hwsq_op5f(hwsq, crtc_mask, 0x01); /* wait for vblank */
-       }
-       if (nv_device(drm->device)->chipset >= 0x92)
-               hwsq_wr32(hwsq, 0x611200, 0x00003300); /* disable scanout */
-       hwsq_setf(hwsq, 0x10, 0); /* disable bus access */
-       hwsq_op5f(hwsq, 0x00, 0x01); /* no idea :s */
-
-       ret = nouveau_mem_exec(&exec, perflvl);
-       if (ret)
-               return ret;
-
-       hwsq_setf(hwsq, 0x10, 1); /* enable bus access */
-       hwsq_op5f(hwsq, 0x00, 0x00); /* no idea, reverse of 0x00, 0x01? */
-       if (nv_device(drm->device)->chipset >= 0x92)
-               hwsq_wr32(hwsq, 0x611200, 0x00003330); /* enable scanout */
-       hwsq_fini(hwsq);
-       return 0;
-}
-
-void *
-nv50_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nv50_pm_state *info;
-       struct hwsq_ucode *hwsq;
-       struct nvbios_pll pll;
-       u32 out, mast, divs, ctrl;
-       int clk, ret = -EINVAL;
-       int N, M, P1, P2;
-
-       if (nv_device(drm->device)->chipset == 0xaa ||
-           nv_device(drm->device)->chipset == 0xac)
-               return ERR_PTR(-ENODEV);
-
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return ERR_PTR(-ENOMEM);
-       info->perflvl = perflvl;
-
-       /* memory: build hwsq ucode which we'll use to reclock memory.
-        *         use pcie refclock if possible, otherwise use mpll */
-       info->mclk_hwsq.len = 0;
-       if (perflvl->memory) {
-               ret = calc_mclk(dev, perflvl, info);
-               if (ret)
-                       goto error;
-               info->mscript = perflvl->memscript;
-       }
-
-       divs = read_div(dev);
-       mast = info->mmast;
-
-       /* start building HWSQ script for engine reclocking */
-       hwsq = &info->eclk_hwsq;
-       hwsq_init(hwsq);
-       hwsq_setf(hwsq, 0x10, 0); /* disable bus access */
-       hwsq_op5f(hwsq, 0x00, 0x01); /* wait for access disabled? */
-
-       /* vdec/dom6: switch to "safe" clocks temporarily */
-       if (perflvl->vdec) {
-               mast &= ~0x00000c00;
-               divs &= ~0x00000700;
-       }
-
-       if (perflvl->dom6) {
-               mast &= ~0x0c000000;
-               divs &= ~0x00000007;
-       }
-
-       hwsq_wr32(hwsq, 0x00c040, mast);
-
-       /* vdec: avoid modifying xpll until we know exactly how the other
-        * clock domains work, i suspect at least some of them can also be
-        * tied to xpll...
-        */
-       if (perflvl->vdec) {
-               /* see how close we can get using nvclk as a source */
-               clk = calc_div(perflvl->core, perflvl->vdec, &P1);
-
-               /* see how close we can get using xpll/hclk as a source */
-               if (nv_device(drm->device)->chipset != 0x98)
-                       out = read_pll(dev, 0x004030);
-               else
-                       out = read_clk(dev, clk_src_hclkm3d2);
-               out = calc_div(out, perflvl->vdec, &P2);
-
-               /* select whichever gets us closest */
-               if (abs((int)perflvl->vdec - clk) <=
-                   abs((int)perflvl->vdec - out)) {
-                       if (nv_device(drm->device)->chipset != 0x98)
-                               mast |= 0x00000c00;
-                       divs |= P1 << 8;
-               } else {
-                       mast |= 0x00000800;
-                       divs |= P2 << 8;
-               }
-       }
-
-       /* dom6: nfi what this is, but we're limited to various combinations
-        * of the host clock frequency
-        */
-       if (perflvl->dom6) {
-               if (clk_same(perflvl->dom6, read_clk(dev, clk_src_href))) {
-                       mast |= 0x00000000;
-               } else
-               if (clk_same(perflvl->dom6, read_clk(dev, clk_src_hclk))) {
-                       mast |= 0x08000000;
-               } else {
-                       clk = read_clk(dev, clk_src_hclk) * 3;
-                       clk = calc_div(clk, perflvl->dom6, &P1);
-
-                       mast |= 0x0c000000;
-                       divs |= P1;
-               }
-       }
-
-       /* vdec/dom6: complete switch to new clocks */
-       switch (nv_device(drm->device)->chipset) {
-       case 0x92:
-       case 0x94:
-       case 0x96:
-               hwsq_wr32(hwsq, 0x004800, divs);
-               break;
-       default:
-               hwsq_wr32(hwsq, 0x004700, divs);
-               break;
-       }
-
-       hwsq_wr32(hwsq, 0x00c040, mast);
-
-       /* core/shader: make sure sclk/nvclk are disconnected from their
-        * PLLs (nvclk to dom6, sclk to hclk)
-        */
-       if (nv_device(drm->device)->chipset < 0x92)
-               mast = (mast & ~0x001000b0) | 0x00100080;
-       else
-               mast = (mast & ~0x000000b3) | 0x00000081;
-
-       hwsq_wr32(hwsq, 0x00c040, mast);
-
-       /* core: for the moment at least, always use nvpll */
-       clk = calc_pll(dev, 0x4028, &pll, perflvl->core, &N, &M, &P1);
-       if (clk == 0)
-               goto error;
-
-       ctrl  = nv_rd32(device, 0x004028) & ~0xc03f0100;
-       mast &= ~0x00100000;
-       mast |= 3;
-
-       hwsq_wr32(hwsq, 0x004028, 0x80000000 | (P1 << 19) | (P1 << 16) | ctrl);
-       hwsq_wr32(hwsq, 0x00402c, (N << 8) | M);
-
-       /* shader: tie to nvclk if possible, otherwise use spll.  have to be
-        * very careful that the shader clock is at least twice the core, or
-        * some chipsets will be very unhappy.  i expect most or all of these
-        * cases will be handled by tying to nvclk, but it's possible there's
-        * corners
-        */
-       ctrl = nv_rd32(device, 0x004020) & ~0xc03f0100;
-
-       if (P1-- && perflvl->shader == (perflvl->core << 1)) {
-               hwsq_wr32(hwsq, 0x004020, (P1 << 19) | (P1 << 16) | ctrl);
-               hwsq_wr32(hwsq, 0x00c040, 0x00000020 | mast);
-       } else {
-               clk = calc_pll(dev, 0x4020, &pll, perflvl->shader, &N, &M, &P1);
-               if (clk == 0)
-                       goto error;
-               ctrl |= 0x80000000;
-
-               hwsq_wr32(hwsq, 0x004020, (P1 << 19) | (P1 << 16) | ctrl);
-               hwsq_wr32(hwsq, 0x004024, (N << 8) | M);
-               hwsq_wr32(hwsq, 0x00c040, 0x00000030 | mast);
-       }
-
-       hwsq_setf(hwsq, 0x10, 1); /* enable bus access */
-       hwsq_op5f(hwsq, 0x00, 0x00); /* wait for access enabled? */
-       hwsq_fini(hwsq);
-
-       return info;
-error:
-       kfree(info);
-       return ERR_PTR(ret);
-}
-
-static int
-prog_hwsq(struct drm_device *dev, struct hwsq_ucode *hwsq)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       u32 hwsq_data, hwsq_kick;
-       int i;
-
-       if (nv_device(drm->device)->chipset < 0x94) {
-               hwsq_data = 0x001400;
-               hwsq_kick = 0x00000003;
-       } else {
-               hwsq_data = 0x080000;
-               hwsq_kick = 0x00000001;
-       }
-       /* upload hwsq ucode */
-       nv_mask(device, 0x001098, 0x00000008, 0x00000000);
-       nv_wr32(device, 0x001304, 0x00000000);
-       if (nv_device(drm->device)->chipset >= 0x92)
-               nv_wr32(device, 0x001318, 0x00000000);
-       for (i = 0; i < hwsq->len / 4; i++)
-               nv_wr32(device, hwsq_data + (i * 4), hwsq->ptr.u32[i]);
-       nv_mask(device, 0x001098, 0x00000018, 0x00000018);
-
-       /* launch, and wait for completion */
-       nv_wr32(device, 0x00130c, hwsq_kick);
-       if (!nv_wait(device, 0x001308, 0x00000100, 0x00000000)) {
-               NV_ERROR(drm, "hwsq ucode exec timed out\n");
-               NV_ERROR(drm, "0x001308: 0x%08x\n", nv_rd32(device, 0x001308));
-               for (i = 0; i < hwsq->len / 4; i++) {
-                       NV_ERROR(drm, "0x%06x: 0x%08x\n", 0x1400 + (i * 4),
-                                nv_rd32(device, 0x001400 + (i * 4)));
-               }
-
-               return -EIO;
-       }
-
-       return 0;
-}
-
-int
-nv50_pm_clocks_set(struct drm_device *dev, void *data)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nv50_pm_state *info = data;
-       struct bit_entry M;
-       int ret = -EBUSY;
-
-       /* halt and idle execution engines */
-       nv_mask(device, 0x002504, 0x00000001, 0x00000001);
-       if (!nv_wait(device, 0x002504, 0x00000010, 0x00000010))
-               goto resume;
-       if (!nv_wait(device, 0x00251c, 0x0000003f, 0x0000003f))
-               goto resume;
-
-       /* program memory clock, if necessary - must come before engine clock
-        * reprogramming due to how we construct the hwsq scripts in pre()
-        */
-#define nouveau_bios_init_exec(a,b) nouveau_bios_run_init_table((a), (b), NULL, 0)
-       if (info->mclk_hwsq.len) {
-               /* execute some scripts that do ??? from the vbios.. */
-               if (!bit_table(dev, 'M', &M) && M.version == 1) {
-                       if (M.length >= 6)
-                               nouveau_bios_init_exec(dev, ROM16(M.data[5]));
-                       if (M.length >= 8)
-                               nouveau_bios_init_exec(dev, ROM16(M.data[7]));
-                       if (M.length >= 10)
-                               nouveau_bios_init_exec(dev, ROM16(M.data[9]));
-                       nouveau_bios_init_exec(dev, info->mscript);
-               }
-
-               ret = prog_hwsq(dev, &info->mclk_hwsq);
-               if (ret)
-                       goto resume;
-       }
-
-       /* program engine clocks */
-       ret = prog_hwsq(dev, &info->eclk_hwsq);
-
-resume:
-       nv_mask(device, 0x002504, 0x00000001, 0x00000000);
-       kfree(info);
-       return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c
deleted file mode 100644 (file)
index 0d0ed59..0000000
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <drm/drmP.h>
-#include "nouveau_drm.h"
-#include "nouveau_bios.h"
-#include "nouveau_pm.h"
-
-#include <subdev/bios/pll.h>
-#include <subdev/bios.h>
-#include <subdev/clock.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-static u32 read_clk(struct drm_device *, int, bool);
-static u32 read_pll(struct drm_device *, int, u32);
-
-static u32
-read_vco(struct drm_device *dev, int clk)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 sctl = nv_rd32(device, 0x4120 + (clk * 4));
-       if ((sctl & 0x00000030) != 0x00000030)
-               return read_pll(dev, 0x41, 0x00e820);
-       return read_pll(dev, 0x42, 0x00e8a0);
-}
-
-static u32
-read_clk(struct drm_device *dev, int clk, bool ignore_en)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       u32 sctl, sdiv, sclk;
-
-       /* refclk for the 0xe8xx plls is a fixed frequency */
-       if (clk >= 0x40) {
-               if (nv_device(drm->device)->chipset == 0xaf) {
-                       /* no joke.. seriously.. sigh.. */
-                       return nv_rd32(device, 0x00471c) * 1000;
-               }
-
-               return device->crystal;
-       }
-
-       sctl = nv_rd32(device, 0x4120 + (clk * 4));
-       if (!ignore_en && !(sctl & 0x00000100))
-               return 0;
-
-       switch (sctl & 0x00003000) {
-       case 0x00000000:
-               return device->crystal;
-       case 0x00002000:
-               if (sctl & 0x00000040)
-                       return 108000;
-               return 100000;
-       case 0x00003000:
-               sclk = read_vco(dev, clk);
-               sdiv = ((sctl & 0x003f0000) >> 16) + 2;
-               return (sclk * 2) / sdiv;
-       default:
-               return 0;
-       }
-}
-
-static u32
-read_pll(struct drm_device *dev, int clk, u32 pll)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 ctrl = nv_rd32(device, pll + 0);
-       u32 sclk = 0, P = 1, N = 1, M = 1;
-
-       if (!(ctrl & 0x00000008)) {
-               if (ctrl & 0x00000001) {
-                       u32 coef = nv_rd32(device, pll + 4);
-                       M = (coef & 0x000000ff) >> 0;
-                       N = (coef & 0x0000ff00) >> 8;
-                       P = (coef & 0x003f0000) >> 16;
-
-                       /* no post-divider on these.. */
-                       if ((pll & 0x00ff00) == 0x00e800)
-                               P = 1;
-
-                       sclk = read_clk(dev, 0x00 + clk, false);
-               }
-       } else {
-               sclk = read_clk(dev, 0x10 + clk, false);
-       }
-
-       if (M * P)
-               return sclk * N / (M * P);
-       return 0;
-}
-
-struct creg {
-       u32 clk;
-       u32 pll;
-};
-
-static int
-calc_clk(struct drm_device *dev, int clk, u32 pll, u32 khz, struct creg *reg)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_bios *bios = nouveau_bios(device);
-       struct nvbios_pll limits;
-       u32 oclk, sclk, sdiv;
-       int P, N, M, diff;
-       int ret;
-
-       reg->pll = 0;
-       reg->clk = 0;
-       if (!khz) {
-               NV_DEBUG(drm, "no clock for 0x%04x/0x%02x\n", pll, clk);
-               return 0;
-       }
-
-       switch (khz) {
-       case 27000:
-               reg->clk = 0x00000100;
-               return khz;
-       case 100000:
-               reg->clk = 0x00002100;
-               return khz;
-       case 108000:
-               reg->clk = 0x00002140;
-               return khz;
-       default:
-               sclk = read_vco(dev, clk);
-               sdiv = min((sclk * 2) / (khz - 2999), (u32)65);
-               /* if the clock has a PLL attached, and we can get a within
-                * [-2, 3) MHz of a divider, we'll disable the PLL and use
-                * the divider instead.
-                *
-                * divider can go as low as 2, limited here because NVIDIA
-                * and the VBIOS on my NVA8 seem to prefer using the PLL
-                * for 810MHz - is there a good reason?
-                */
-               if (sdiv > 4) {
-                       oclk = (sclk * 2) / sdiv;
-                       diff = khz - oclk;
-                       if (!pll || (diff >= -2000 && diff < 3000)) {
-                               reg->clk = (((sdiv - 2) << 16) | 0x00003100);
-                               return oclk;
-                       }
-               }
-
-               if (!pll) {
-                       NV_ERROR(drm, "bad freq %02x: %d %d\n", clk, khz, sclk);
-                       return -ERANGE;
-               }
-
-               break;
-       }
-
-       ret = nvbios_pll_parse(bios, pll, &limits);
-       if (ret)
-               return ret;
-
-       limits.refclk = read_clk(dev, clk - 0x10, true);
-       if (!limits.refclk)
-               return -EINVAL;
-
-       ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P);
-       if (ret >= 0) {
-               reg->clk = nv_rd32(device, 0x4120 + (clk * 4));
-               reg->pll = (P << 16) | (N << 8) | M;
-       }
-
-       return ret;
-}
-
-static void
-prog_pll(struct drm_device *dev, int clk, u32 pll, struct creg *reg)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       const u32 src0 = 0x004120 + (clk * 4);
-       const u32 src1 = 0x004160 + (clk * 4);
-       const u32 ctrl = pll + 0;
-       const u32 coef = pll + 4;
-
-       if (!reg->clk && !reg->pll) {
-               NV_DEBUG(drm, "no clock for %02x\n", clk);
-               return;
-       }
-
-       if (reg->pll) {
-               nv_mask(device, src0, 0x00000101, 0x00000101);
-               nv_wr32(device, coef, reg->pll);
-               nv_mask(device, ctrl, 0x00000015, 0x00000015);
-               nv_mask(device, ctrl, 0x00000010, 0x00000000);
-               nv_wait(device, ctrl, 0x00020000, 0x00020000);
-               nv_mask(device, ctrl, 0x00000010, 0x00000010);
-               nv_mask(device, ctrl, 0x00000008, 0x00000000);
-               nv_mask(device, src1, 0x00000100, 0x00000000);
-               nv_mask(device, src1, 0x00000001, 0x00000000);
-       } else {
-               nv_mask(device, src1, 0x003f3141, 0x00000101 | reg->clk);
-               nv_mask(device, ctrl, 0x00000018, 0x00000018);
-               udelay(20);
-               nv_mask(device, ctrl, 0x00000001, 0x00000000);
-               nv_mask(device, src0, 0x00000100, 0x00000000);
-               nv_mask(device, src0, 0x00000001, 0x00000000);
-       }
-}
-
-static void
-prog_clk(struct drm_device *dev, int clk, struct creg *reg)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-
-       if (!reg->clk) {
-               NV_DEBUG(drm, "no clock for %02x\n", clk);
-               return;
-       }
-
-       nv_mask(device, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | reg->clk);
-}
-
-int
-nva3_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       perflvl->core   = read_pll(dev, 0x00, 0x4200);
-       perflvl->shader = read_pll(dev, 0x01, 0x4220);
-       perflvl->memory = read_pll(dev, 0x02, 0x4000);
-       perflvl->unka0  = read_clk(dev, 0x20, false);
-       perflvl->vdec   = read_clk(dev, 0x21, false);
-       perflvl->daemon = read_clk(dev, 0x25, false);
-       perflvl->copy   = perflvl->core;
-       return 0;
-}
-
-struct nva3_pm_state {
-       struct nouveau_pm_level *perflvl;
-
-       struct creg nclk;
-       struct creg sclk;
-       struct creg vdec;
-       struct creg unka0;
-
-       struct creg mclk;
-       u8 *rammap;
-       u8  rammap_ver;
-       u8  rammap_len;
-       u8 *ramcfg;
-       u8  ramcfg_len;
-       u32 r004018;
-       u32 r100760;
-};
-
-void *
-nva3_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       struct nva3_pm_state *info;
-       u8 ramcfg_cnt;
-       int ret;
-
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return ERR_PTR(-ENOMEM);
-
-       ret = calc_clk(dev, 0x10, 0x4200, perflvl->core, &info->nclk);
-       if (ret < 0)
-               goto out;
-
-       ret = calc_clk(dev, 0x11, 0x4220, perflvl->shader, &info->sclk);
-       if (ret < 0)
-               goto out;
-
-       ret = calc_clk(dev, 0x12, 0x4000, perflvl->memory, &info->mclk);
-       if (ret < 0)
-               goto out;
-
-       ret = calc_clk(dev, 0x20, 0x0000, perflvl->unka0, &info->unka0);
-       if (ret < 0)
-               goto out;
-
-       ret = calc_clk(dev, 0x21, 0x0000, perflvl->vdec, &info->vdec);
-       if (ret < 0)
-               goto out;
-
-       info->rammap = nouveau_perf_rammap(dev, perflvl->memory,
-                                          &info->rammap_ver,
-                                          &info->rammap_len,
-                                          &ramcfg_cnt, &info->ramcfg_len);
-       if (info->rammap_ver != 0x10 || info->rammap_len < 5)
-               info->rammap = NULL;
-
-       info->ramcfg = nouveau_perf_ramcfg(dev, perflvl->memory,
-                                          &info->rammap_ver,
-                                          &info->ramcfg_len);
-       if (info->rammap_ver != 0x10)
-               info->ramcfg = NULL;
-
-       info->perflvl = perflvl;
-out:
-       if (ret < 0) {
-               kfree(info);
-               info = ERR_PTR(ret);
-       }
-       return info;
-}
-
-static bool
-nva3_pm_grcp_idle(void *data)
-{
-       struct drm_device *dev = data;
-       struct nouveau_device *device = nouveau_dev(dev);
-
-       if (!(nv_rd32(device, 0x400304) & 0x00000001))
-               return true;
-       if (nv_rd32(device, 0x400308) == 0x0050001c)
-               return true;
-       return false;
-}
-
-static void
-mclk_precharge(struct nouveau_mem_exec_func *exec)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       nv_wr32(device, 0x1002d4, 0x00000001);
-}
-
-static void
-mclk_refresh(struct nouveau_mem_exec_func *exec)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       nv_wr32(device, 0x1002d0, 0x00000001);
-}
-
-static void
-mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       nv_wr32(device, 0x100210, enable ? 0x80000000 : 0x00000000);
-}
-
-static void
-mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       nv_wr32(device, 0x1002dc, enable ? 0x00000001 : 0x00000000);
-}
-
-static void
-mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       volatile u32 post = nv_rd32(device, 0); (void)post;
-       udelay((nsec + 500) / 1000);
-}
-
-static u32
-mclk_mrg(struct nouveau_mem_exec_func *exec, int mr)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       if (mr <= 1)
-               return nv_rd32(device, 0x1002c0 + ((mr - 0) * 4));
-       if (mr <= 3)
-               return nv_rd32(device, 0x1002e0 + ((mr - 2) * 4));
-       return 0;
-}
-
-static void
-mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nouveau_fb *pfb = nouveau_fb(device);
-       if (mr <= 1) {
-               if (pfb->ram->ranks > 1)
-                       nv_wr32(device, 0x1002c8 + ((mr - 0) * 4), data);
-               nv_wr32(device, 0x1002c0 + ((mr - 0) * 4), data);
-       } else
-       if (mr <= 3) {
-               if (pfb->ram->ranks > 1)
-                       nv_wr32(device, 0x1002e8 + ((mr - 2) * 4), data);
-               nv_wr32(device, 0x1002e0 + ((mr - 2) * 4), data);
-       }
-}
-
-static void
-mclk_clock_set(struct nouveau_mem_exec_func *exec)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nva3_pm_state *info = exec->priv;
-       u32 ctrl;
-
-       ctrl = nv_rd32(device, 0x004000);
-       if (!(ctrl & 0x00000008) && info->mclk.pll) {
-               nv_wr32(device, 0x004000, (ctrl |=  0x00000008));
-               nv_mask(device, 0x1110e0, 0x00088000, 0x00088000);
-               nv_wr32(device, 0x004018, 0x00001000);
-               nv_wr32(device, 0x004000, (ctrl &= ~0x00000001));
-               nv_wr32(device, 0x004004, info->mclk.pll);
-               nv_wr32(device, 0x004000, (ctrl |=  0x00000001));
-               udelay(64);
-               nv_wr32(device, 0x004018, 0x00005000 | info->r004018);
-               udelay(20);
-       } else
-       if (!info->mclk.pll) {
-               nv_mask(device, 0x004168, 0x003f3040, info->mclk.clk);
-               nv_wr32(device, 0x004000, (ctrl |= 0x00000008));
-               nv_mask(device, 0x1110e0, 0x00088000, 0x00088000);
-               nv_wr32(device, 0x004018, 0x0000d000 | info->r004018);
-       }
-
-       if (info->rammap) {
-               if (info->ramcfg && (info->rammap[4] & 0x08)) {
-                       u32 unk5a0 = (ROM16(info->ramcfg[5]) << 8) |
-                                     info->ramcfg[5];
-                       u32 unk5a4 = ROM16(info->ramcfg[7]);
-                       u32 unk804 = (info->ramcfg[9] & 0xf0) << 16 |
-                                    (info->ramcfg[3] & 0x0f) << 16 |
-                                    (info->ramcfg[9] & 0x0f) |
-                                    0x80000000;
-                       nv_wr32(device, 0x1005a0, unk5a0);
-                       nv_wr32(device, 0x1005a4, unk5a4);
-                       nv_wr32(device, 0x10f804, unk804);
-                       nv_mask(device, 0x10053c, 0x00001000, 0x00000000);
-               } else {
-                       nv_mask(device, 0x10053c, 0x00001000, 0x00001000);
-                       nv_mask(device, 0x10f804, 0x80000000, 0x00000000);
-                       nv_mask(device, 0x100760, 0x22222222, info->r100760);
-                       nv_mask(device, 0x1007a0, 0x22222222, info->r100760);
-                       nv_mask(device, 0x1007e0, 0x22222222, info->r100760);
-               }
-       }
-
-       if (info->mclk.pll) {
-               nv_mask(device, 0x1110e0, 0x00088000, 0x00011000);
-               nv_wr32(device, 0x004000, (ctrl &= ~0x00000008));
-       }
-}
-
-static void
-mclk_timing_set(struct nouveau_mem_exec_func *exec)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nva3_pm_state *info = exec->priv;
-       struct nouveau_pm_level *perflvl = info->perflvl;
-       int i;
-
-       for (i = 0; i < 9; i++)
-               nv_wr32(device, 0x100220 + (i * 4), perflvl->timing.reg[i]);
-
-       if (info->ramcfg) {
-               u32 data = (info->ramcfg[2] & 0x08) ? 0x00000000 : 0x00001000;
-               nv_mask(device, 0x100200, 0x00001000, data);
-       }
-
-       if (info->ramcfg) {
-               u32 unk714 = nv_rd32(device, 0x100714) & ~0xf0000010;
-               u32 unk718 = nv_rd32(device, 0x100718) & ~0x00000100;
-               u32 unk71c = nv_rd32(device, 0x10071c) & ~0x00000100;
-               if ( (info->ramcfg[2] & 0x20))
-                       unk714 |= 0xf0000000;
-               if (!(info->ramcfg[2] & 0x04))
-                       unk714 |= 0x00000010;
-               nv_wr32(device, 0x100714, unk714);
-
-               if (info->ramcfg[2] & 0x01)
-                       unk71c |= 0x00000100;
-               nv_wr32(device, 0x10071c, unk71c);
-
-               if (info->ramcfg[2] & 0x02)
-                       unk718 |= 0x00000100;
-               nv_wr32(device, 0x100718, unk718);
-
-               if (info->ramcfg[2] & 0x10)
-                       nv_wr32(device, 0x111100, 0x48000000); /*XXX*/
-       }
-}
-
-static void
-prog_mem(struct drm_device *dev, struct nva3_pm_state *info)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_mem_exec_func exec = {
-               .dev = dev,
-               .precharge = mclk_precharge,
-               .refresh = mclk_refresh,
-               .refresh_auto = mclk_refresh_auto,
-               .refresh_self = mclk_refresh_self,
-               .wait = mclk_wait,
-               .mrg = mclk_mrg,
-               .mrs = mclk_mrs,
-               .clock_set = mclk_clock_set,
-               .timing_set = mclk_timing_set,
-               .priv = info
-       };
-       u32 ctrl;
-
-       /* XXX: where the fuck does 750MHz come from? */
-       if (info->perflvl->memory <= 750000) {
-               info->r004018 = 0x10000000;
-               info->r100760 = 0x22222222;
-       }
-
-       ctrl = nv_rd32(device, 0x004000);
-       if (ctrl & 0x00000008) {
-               if (info->mclk.pll) {
-                       nv_mask(device, 0x004128, 0x00000101, 0x00000101);
-                       nv_wr32(device, 0x004004, info->mclk.pll);
-                       nv_wr32(device, 0x004000, (ctrl |= 0x00000001));
-                       nv_wr32(device, 0x004000, (ctrl &= 0xffffffef));
-                       nv_wait(device, 0x004000, 0x00020000, 0x00020000);
-                       nv_wr32(device, 0x004000, (ctrl |= 0x00000010));
-                       nv_wr32(device, 0x004018, 0x00005000 | info->r004018);
-                       nv_wr32(device, 0x004000, (ctrl |= 0x00000004));
-               }
-       } else {
-               u32 ssel = 0x00000101;
-               if (info->mclk.clk)
-                       ssel |= info->mclk.clk;
-               else
-                       ssel |= 0x00080000; /* 324MHz, shouldn't matter... */
-               nv_mask(device, 0x004168, 0x003f3141, ctrl);
-       }
-
-       if (info->ramcfg) {
-               if (info->ramcfg[2] & 0x10) {
-                       nv_mask(device, 0x111104, 0x00000600, 0x00000000);
-               } else {
-                       nv_mask(device, 0x111100, 0x40000000, 0x40000000);
-                       nv_mask(device, 0x111104, 0x00000180, 0x00000000);
-               }
-       }
-       if (info->rammap && !(info->rammap[4] & 0x02))
-               nv_mask(device, 0x100200, 0x00000800, 0x00000000);
-       nv_wr32(device, 0x611200, 0x00003300);
-       if (!(info->ramcfg[2] & 0x10))
-               nv_wr32(device, 0x111100, 0x4c020000); /*XXX*/
-
-       nouveau_mem_exec(&exec, info->perflvl);
-
-       nv_wr32(device, 0x611200, 0x00003330);
-       if (info->rammap && (info->rammap[4] & 0x02))
-               nv_mask(device, 0x100200, 0x00000800, 0x00000800);
-       if (info->ramcfg) {
-               if (info->ramcfg[2] & 0x10) {
-                       nv_mask(device, 0x111104, 0x00000180, 0x00000180);
-                       nv_mask(device, 0x111100, 0x40000000, 0x00000000);
-               } else {
-                       nv_mask(device, 0x111104, 0x00000600, 0x00000600);
-               }
-       }
-
-       if (info->mclk.pll) {
-               nv_mask(device, 0x004168, 0x00000001, 0x00000000);
-               nv_mask(device, 0x004168, 0x00000100, 0x00000000);
-       } else {
-               nv_mask(device, 0x004000, 0x00000001, 0x00000000);
-               nv_mask(device, 0x004128, 0x00000001, 0x00000000);
-               nv_mask(device, 0x004128, 0x00000100, 0x00000000);
-       }
-}
-
-int
-nva3_pm_clocks_set(struct drm_device *dev, void *pre_state)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nva3_pm_state *info = pre_state;
-       int ret = -EAGAIN;
-
-       /* prevent any new grctx switches from starting */
-       nv_wr32(device, 0x400324, 0x00000000);
-       nv_wr32(device, 0x400328, 0x0050001c); /* wait flag 0x1c */
-       /* wait for any pending grctx switches to complete */
-       if (!nv_wait_cb(device, nva3_pm_grcp_idle, dev)) {
-               NV_ERROR(drm, "pm: ctxprog didn't go idle\n");
-               goto cleanup;
-       }
-       /* freeze PFIFO */
-       nv_mask(device, 0x002504, 0x00000001, 0x00000001);
-       if (!nv_wait(device, 0x002504, 0x00000010, 0x00000010)) {
-               NV_ERROR(drm, "pm: fifo didn't go idle\n");
-               goto cleanup;
-       }
-
-       prog_pll(dev, 0x00, 0x004200, &info->nclk);
-       prog_pll(dev, 0x01, 0x004220, &info->sclk);
-       prog_clk(dev, 0x20, &info->unka0);
-       prog_clk(dev, 0x21, &info->vdec);
-
-       if (info->mclk.clk || info->mclk.pll)
-               prog_mem(dev, info);
-
-       ret = 0;
-
-cleanup:
-       /* unfreeze PFIFO */
-       nv_mask(device, 0x002504, 0x00000001, 0x00000000);
-       /* restore ctxprog to normal */
-       nv_wr32(device, 0x400324, 0x00000000);
-       nv_wr32(device, 0x400328, 0x0070009c); /* set flag 0x1c */
-       /* unblock it if necessary */
-       if (nv_rd32(device, 0x400308) == 0x0050001c)
-               nv_mask(device, 0x400824, 0x10000000, 0x10000000);
-       kfree(info);
-       return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c
deleted file mode 100644 (file)
index 3b7041c..0000000
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nouveau_drm.h"
-#include "nouveau_bios.h"
-#include "nouveau_pm.h"
-
-#include <subdev/bios/pll.h>
-#include <subdev/bios.h>
-#include <subdev/clock.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-static u32 read_div(struct drm_device *, int, u32, u32);
-static u32 read_pll(struct drm_device *, u32);
-
-static u32
-read_vco(struct drm_device *dev, u32 dsrc)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 ssrc = nv_rd32(device, dsrc);
-       if (!(ssrc & 0x00000100))
-               return read_pll(dev, 0x00e800);
-       return read_pll(dev, 0x00e820);
-}
-
-static u32
-read_pll(struct drm_device *dev, u32 pll)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 ctrl = nv_rd32(device, pll + 0);
-       u32 coef = nv_rd32(device, pll + 4);
-       u32 P = (coef & 0x003f0000) >> 16;
-       u32 N = (coef & 0x0000ff00) >> 8;
-       u32 M = (coef & 0x000000ff) >> 0;
-       u32 sclk, doff;
-
-       if (!(ctrl & 0x00000001))
-               return 0;
-
-       switch (pll & 0xfff000) {
-       case 0x00e000:
-               sclk = 27000;
-               P = 1;
-               break;
-       case 0x137000:
-               doff = (pll - 0x137000) / 0x20;
-               sclk = read_div(dev, doff, 0x137120, 0x137140);
-               break;
-       case 0x132000:
-               switch (pll) {
-               case 0x132000:
-                       sclk = read_pll(dev, 0x132020);
-                       break;
-               case 0x132020:
-                       sclk = read_div(dev, 0, 0x137320, 0x137330);
-                       break;
-               default:
-                       return 0;
-               }
-               break;
-       default:
-               return 0;
-       }
-
-       return sclk * N / M / P;
-}
-
-static u32
-read_div(struct drm_device *dev, int doff, u32 dsrc, u32 dctl)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 ssrc = nv_rd32(device, dsrc + (doff * 4));
-       u32 sctl = nv_rd32(device, dctl + (doff * 4));
-
-       switch (ssrc & 0x00000003) {
-       case 0:
-               if ((ssrc & 0x00030000) != 0x00030000)
-                       return 27000;
-               return 108000;
-       case 2:
-               return 100000;
-       case 3:
-               if (sctl & 0x80000000) {
-                       u32 sclk = read_vco(dev, dsrc + (doff * 4));
-                       u32 sdiv = (sctl & 0x0000003f) + 2;
-                       return (sclk * 2) / sdiv;
-               }
-
-               return read_vco(dev, dsrc + (doff * 4));
-       default:
-               return 0;
-       }
-}
-
-static u32
-read_mem(struct drm_device *dev)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 ssel = nv_rd32(device, 0x1373f0);
-       if (ssel & 0x00000001)
-               return read_div(dev, 0, 0x137300, 0x137310);
-       return read_pll(dev, 0x132000);
-}
-
-static u32
-read_clk(struct drm_device *dev, int clk)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       u32 sctl = nv_rd32(device, 0x137250 + (clk * 4));
-       u32 ssel = nv_rd32(device, 0x137100);
-       u32 sclk, sdiv;
-
-       if (ssel & (1 << clk)) {
-               if (clk < 7)
-                       sclk = read_pll(dev, 0x137000 + (clk * 0x20));
-               else
-                       sclk = read_pll(dev, 0x1370e0);
-               sdiv = ((sctl & 0x00003f00) >> 8) + 2;
-       } else {
-               sclk = read_div(dev, clk, 0x137160, 0x1371d0);
-               sdiv = ((sctl & 0x0000003f) >> 0) + 2;
-       }
-
-       if (sctl & 0x80000000)
-               return (sclk * 2) / sdiv;
-       return sclk;
-}
-
-int
-nvc0_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       perflvl->shader = read_clk(dev, 0x00);
-       perflvl->core   = perflvl->shader / 2;
-       perflvl->memory = read_mem(dev);
-       perflvl->rop    = read_clk(dev, 0x01);
-       perflvl->hub07  = read_clk(dev, 0x02);
-       perflvl->hub06  = read_clk(dev, 0x07);
-       perflvl->hub01  = read_clk(dev, 0x08);
-       perflvl->copy   = read_clk(dev, 0x09);
-       perflvl->daemon = read_clk(dev, 0x0c);
-       perflvl->vdec   = read_clk(dev, 0x0e);
-       return 0;
-}
-
-struct nvc0_pm_clock {
-       u32 freq;
-       u32 ssel;
-       u32 mdiv;
-       u32 dsrc;
-       u32 ddiv;
-       u32 coef;
-};
-
-struct nvc0_pm_state {
-       struct nouveau_pm_level *perflvl;
-       struct nvc0_pm_clock eng[16];
-       struct nvc0_pm_clock mem;
-};
-
-static u32
-calc_div(struct drm_device *dev, int clk, u32 ref, u32 freq, u32 *ddiv)
-{
-       u32 div = min((ref * 2) / freq, (u32)65);
-       if (div < 2)
-               div = 2;
-
-       *ddiv = div - 2;
-       return (ref * 2) / div;
-}
-
-static u32
-calc_src(struct drm_device *dev, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
-{
-       u32 sclk;
-
-       /* use one of the fixed frequencies if possible */
-       *ddiv = 0x00000000;
-       switch (freq) {
-       case  27000:
-       case 108000:
-               *dsrc = 0x00000000;
-               if (freq == 108000)
-                       *dsrc |= 0x00030000;
-               return freq;
-       case 100000:
-               *dsrc = 0x00000002;
-               return freq;
-       default:
-               *dsrc = 0x00000003;
-               break;
-       }
-
-       /* otherwise, calculate the closest divider */
-       sclk = read_vco(dev, clk);
-       if (clk < 7)
-               sclk = calc_div(dev, clk, sclk, freq, ddiv);
-       return sclk;
-}
-
-static u32
-calc_pll(struct drm_device *dev, int clk, u32 freq, u32 *coef)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_bios *bios = nouveau_bios(device);
-       struct nvbios_pll limits;
-       int N, M, P, ret;
-
-       ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
-       if (ret)
-               return 0;
-
-       limits.refclk = read_div(dev, clk, 0x137120, 0x137140);
-       if (!limits.refclk)
-               return 0;
-
-       ret = nva3_calc_pll(dev, &limits, freq, &N, NULL, &M, &P);
-       if (ret <= 0)
-               return 0;
-
-       *coef = (P << 16) | (N << 8) | M;
-       return ret;
-}
-
-/* A (likely rather simplified and incomplete) view of the clock tree
- *
- * Key:
- *
- * S: source select
- * D: divider
- * P: pll
- * F: switch
- *
- * Engine clocks:
- *
- * 137250(D) ---- 137100(F0) ---- 137160(S)/1371d0(D) ------------------- ref
- *                      (F1) ---- 1370X0(P) ---- 137120(S)/137140(D) ---- ref
- *
- * Not all registers exist for all clocks.  For example: clocks >= 8 don't
- * have their own PLL (all tied to clock 7's PLL when in PLL mode), nor do
- * they have the divider at 1371d0, though the source selection at 137160
- * still exists.  You must use the divider at 137250 for these instead.
- *
- * Memory clock:
- *
- * TBD, read_mem() above is likely very wrong...
- *
- */
-
-static int
-calc_clk(struct drm_device *dev, int clk, struct nvc0_pm_clock *info, u32 freq)
-{
-       u32 src0, div0, div1D, div1P = 0;
-       u32 clk0, clk1 = 0;
-
-       /* invalid clock domain */
-       if (!freq)
-               return 0;
-
-       /* first possible path, using only dividers */
-       clk0 = calc_src(dev, clk, freq, &src0, &div0);
-       clk0 = calc_div(dev, clk, clk0, freq, &div1D);
-
-       /* see if we can get any closer using PLLs */
-       if (clk0 != freq && (0x00004387 & (1 << clk))) {
-               if (clk < 7)
-                       clk1 = calc_pll(dev, clk, freq, &info->coef);
-               else
-                       clk1 = read_pll(dev, 0x1370e0);
-               clk1 = calc_div(dev, clk, clk1, freq, &div1P);
-       }
-
-       /* select the method which gets closest to target freq */
-       if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
-               info->dsrc = src0;
-               if (div0) {
-                       info->ddiv |= 0x80000000;
-                       info->ddiv |= div0 << 8;
-                       info->ddiv |= div0;
-               }
-               if (div1D) {
-                       info->mdiv |= 0x80000000;
-                       info->mdiv |= div1D;
-               }
-               info->ssel = 0;
-               info->freq = clk0;
-       } else {
-               if (div1P) {
-                       info->mdiv |= 0x80000000;
-                       info->mdiv |= div1P << 8;
-               }
-               info->ssel = (1 << clk);
-               info->freq = clk1;
-       }
-
-       return 0;
-}
-
-static int
-calc_mem(struct drm_device *dev, struct nvc0_pm_clock *info, u32 freq)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_bios *bios = nouveau_bios(device);
-       struct nvbios_pll pll;
-       int N, M, P, ret;
-       u32 ctrl;
-
-       /* mclk pll input freq comes from another pll, make sure it's on */
-       ctrl = nv_rd32(device, 0x132020);
-       if (!(ctrl & 0x00000001)) {
-               /* if not, program it to 567MHz.  nfi where this value comes
-                * from - it looks like it's in the pll limits table for
-                * 132000 but the binary driver ignores all my attempts to
-                * change this value.
-                */
-               nv_wr32(device, 0x137320, 0x00000103);
-               nv_wr32(device, 0x137330, 0x81200606);
-               nv_wait(device, 0x132020, 0x00010000, 0x00010000);
-               nv_wr32(device, 0x132024, 0x0001150f);
-               nv_mask(device, 0x132020, 0x00000001, 0x00000001);
-               nv_wait(device, 0x137390, 0x00020000, 0x00020000);
-               nv_mask(device, 0x132020, 0x00000004, 0x00000004);
-       }
-
-       /* for the moment, until the clock tree is better understood, use
-        * pll mode for all clock frequencies
-        */
-       ret = nvbios_pll_parse(bios, 0x132000, &pll);
-       if (ret == 0) {
-               pll.refclk = read_pll(dev, 0x132020);
-               if (pll.refclk) {
-                       ret = nva3_calc_pll(dev, &pll, freq, &N, NULL, &M, &P);
-                       if (ret > 0) {
-                               info->coef = (P << 16) | (N << 8) | M;
-                               return 0;
-                       }
-               }
-       }
-
-       return -EINVAL;
-}
-
-void *
-nvc0_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nvc0_pm_state *info;
-       int ret;
-
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return ERR_PTR(-ENOMEM);
-
-       /* NFI why this is still in the performance table, the ROPCs appear
-        * to get their clock from clock 2 ("hub07", actually hub05 on this
-        * chip, but, anyway...) as well.  nvatiming confirms hub05 and ROP
-        * are always the same freq with the binary driver even when the
-        * performance table says they should differ.
-        */
-       if (device->chipset == 0xd9)
-               perflvl->rop = 0;
-
-       if ((ret = calc_clk(dev, 0x00, &info->eng[0x00], perflvl->shader)) ||
-           (ret = calc_clk(dev, 0x01, &info->eng[0x01], perflvl->rop)) ||
-           (ret = calc_clk(dev, 0x02, &info->eng[0x02], perflvl->hub07)) ||
-           (ret = calc_clk(dev, 0x07, &info->eng[0x07], perflvl->hub06)) ||
-           (ret = calc_clk(dev, 0x08, &info->eng[0x08], perflvl->hub01)) ||
-           (ret = calc_clk(dev, 0x09, &info->eng[0x09], perflvl->copy)) ||
-           (ret = calc_clk(dev, 0x0c, &info->eng[0x0c], perflvl->daemon)) ||
-           (ret = calc_clk(dev, 0x0e, &info->eng[0x0e], perflvl->vdec))) {
-               kfree(info);
-               return ERR_PTR(ret);
-       }
-
-       if (perflvl->memory) {
-               ret = calc_mem(dev, &info->mem, perflvl->memory);
-               if (ret) {
-                       kfree(info);
-                       return ERR_PTR(ret);
-               }
-       }
-
-       info->perflvl = perflvl;
-       return info;
-}
-
-static void
-prog_clk(struct drm_device *dev, int clk, struct nvc0_pm_clock *info)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-
-       /* program dividers at 137160/1371d0 first */
-       if (clk < 7 && !info->ssel) {
-               nv_mask(device, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv);
-               nv_wr32(device, 0x137160 + (clk * 0x04), info->dsrc);
-       }
-
-       /* switch clock to non-pll mode */
-       nv_mask(device, 0x137100, (1 << clk), 0x00000000);
-       nv_wait(device, 0x137100, (1 << clk), 0x00000000);
-
-       /* reprogram pll */
-       if (clk < 7) {
-               /* make sure it's disabled first... */
-               u32 base = 0x137000 + (clk * 0x20);
-               u32 ctrl = nv_rd32(device, base + 0x00);
-               if (ctrl & 0x00000001) {
-                       nv_mask(device, base + 0x00, 0x00000004, 0x00000000);
-                       nv_mask(device, base + 0x00, 0x00000001, 0x00000000);
-               }
-               /* program it to new values, if necessary */
-               if (info->ssel) {
-                       nv_wr32(device, base + 0x04, info->coef);
-                       nv_mask(device, base + 0x00, 0x00000001, 0x00000001);
-                       nv_wait(device, base + 0x00, 0x00020000, 0x00020000);
-                       nv_mask(device, base + 0x00, 0x00020004, 0x00000004);
-               }
-       }
-
-       /* select pll/non-pll mode, and program final clock divider */
-       nv_mask(device, 0x137100, (1 << clk), info->ssel);
-       nv_wait(device, 0x137100, (1 << clk), info->ssel);
-       nv_mask(device, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv);
-}
-
-static void
-mclk_precharge(struct nouveau_mem_exec_func *exec)
-{
-}
-
-static void
-mclk_refresh(struct nouveau_mem_exec_func *exec)
-{
-}
-
-static void
-mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       nv_wr32(device, 0x10f210, enable ? 0x80000000 : 0x00000000);
-}
-
-static void
-mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable)
-{
-}
-
-static void
-mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec)
-{
-       udelay((nsec + 500) / 1000);
-}
-
-static u32
-mclk_mrg(struct nouveau_mem_exec_func *exec, int mr)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nouveau_fb *pfb = nouveau_fb(device);
-       if (pfb->ram->type != NV_MEM_TYPE_GDDR5) {
-               if (mr <= 1)
-                       return nv_rd32(device, 0x10f300 + ((mr - 0) * 4));
-               return nv_rd32(device, 0x10f320 + ((mr - 2) * 4));
-       } else {
-               if (mr == 0)
-                       return nv_rd32(device, 0x10f300 + (mr * 4));
-               else
-               if (mr <= 7)
-                       return nv_rd32(device, 0x10f32c + (mr * 4));
-               return nv_rd32(device, 0x10f34c);
-       }
-}
-
-static void
-mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nouveau_fb *pfb = nouveau_fb(device);
-       if (pfb->ram->type != NV_MEM_TYPE_GDDR5) {
-               if (mr <= 1) {
-                       nv_wr32(device, 0x10f300 + ((mr - 0) * 4), data);
-                       if (pfb->ram->ranks > 1)
-                               nv_wr32(device, 0x10f308 + ((mr - 0) * 4), data);
-               } else
-               if (mr <= 3) {
-                       nv_wr32(device, 0x10f320 + ((mr - 2) * 4), data);
-                       if (pfb->ram->ranks > 1)
-                               nv_wr32(device, 0x10f328 + ((mr - 2) * 4), data);
-               }
-       } else {
-               if      (mr ==  0) nv_wr32(device, 0x10f300 + (mr * 4), data);
-               else if (mr <=  7) nv_wr32(device, 0x10f32c + (mr * 4), data);
-               else if (mr == 15) nv_wr32(device, 0x10f34c, data);
-       }
-}
-
-static void
-mclk_clock_set(struct nouveau_mem_exec_func *exec)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nvc0_pm_state *info = exec->priv;
-       u32 ctrl = nv_rd32(device, 0x132000);
-
-       nv_wr32(device, 0x137360, 0x00000001);
-       nv_wr32(device, 0x137370, 0x00000000);
-       nv_wr32(device, 0x137380, 0x00000000);
-       if (ctrl & 0x00000001)
-               nv_wr32(device, 0x132000, (ctrl &= ~0x00000001));
-
-       nv_wr32(device, 0x132004, info->mem.coef);
-       nv_wr32(device, 0x132000, (ctrl |= 0x00000001));
-       nv_wait(device, 0x137390, 0x00000002, 0x00000002);
-       nv_wr32(device, 0x132018, 0x00005000);
-
-       nv_wr32(device, 0x137370, 0x00000001);
-       nv_wr32(device, 0x137380, 0x00000001);
-       nv_wr32(device, 0x137360, 0x00000000);
-}
-
-static void
-mclk_timing_set(struct nouveau_mem_exec_func *exec)
-{
-       struct nouveau_device *device = nouveau_dev(exec->dev);
-       struct nvc0_pm_state *info = exec->priv;
-       struct nouveau_pm_level *perflvl = info->perflvl;
-       int i;
-
-       for (i = 0; i < 5; i++)
-               nv_wr32(device, 0x10f290 + (i * 4), perflvl->timing.reg[i]);
-}
-
-static void
-prog_mem(struct drm_device *dev, struct nvc0_pm_state *info)
-{
-       struct nouveau_device *device = nouveau_dev(dev);
-       struct nouveau_mem_exec_func exec = {
-               .dev = dev,
-               .precharge = mclk_precharge,
-               .refresh = mclk_refresh,
-               .refresh_auto = mclk_refresh_auto,
-               .refresh_self = mclk_refresh_self,
-               .wait = mclk_wait,
-               .mrg = mclk_mrg,
-               .mrs = mclk_mrs,
-               .clock_set = mclk_clock_set,
-               .timing_set = mclk_timing_set,
-               .priv = info
-       };
-
-       if (device->chipset < 0xd0)
-               nv_wr32(device, 0x611200, 0x00003300);
-       else
-               nv_wr32(device, 0x62c000, 0x03030000);
-
-       nouveau_mem_exec(&exec, info->perflvl);
-
-       if (device->chipset < 0xd0)
-               nv_wr32(device, 0x611200, 0x00003330);
-       else
-               nv_wr32(device, 0x62c000, 0x03030300);
-}
-int
-nvc0_pm_clocks_set(struct drm_device *dev, void *data)
-{
-       struct nvc0_pm_state *info = data;
-       int i;
-
-       if (info->mem.coef)
-               prog_mem(dev, info);
-
-       for (i = 0; i < 16; i++) {
-               if (!info->eng[i].freq)
-                       continue;
-               prog_clk(dev, i, &info->eng[i]);
-       }
-
-       kfree(info);
-       return 0;
-}
index af10f85..92be50c 100644 (file)
@@ -1711,7 +1711,9 @@ typedef struct _PIXEL_CLOCK_PARAMETERS_V6
 #define PIXEL_CLOCK_V6_MISC_HDMI_BPP_MASK           0x0c
 #define PIXEL_CLOCK_V6_MISC_HDMI_24BPP              0x00
 #define PIXEL_CLOCK_V6_MISC_HDMI_36BPP              0x04
+#define PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6           0x08    //for V6, the correct defintion for 36bpp should be 2 for 36bpp(2:1)
 #define PIXEL_CLOCK_V6_MISC_HDMI_30BPP              0x08
+#define PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6           0x04    //for V6, the correct defintion for 30bpp should be 1 for 36bpp(5:4)
 #define PIXEL_CLOCK_V6_MISC_HDMI_48BPP              0x0c
 #define PIXEL_CLOCK_V6_MISC_REF_DIV_SRC             0x10
 #define PIXEL_CLOCK_V6_MISC_GEN_DPREFCLK            0x40
@@ -2223,7 +2225,7 @@ typedef struct    _SET_VOLTAGE_PARAMETERS_V2
   USHORT   usVoltageLevel;              // real voltage level
 }SET_VOLTAGE_PARAMETERS_V2;
 
-
+// used by both SetVoltageTable v1.3 and v1.4
 typedef struct _SET_VOLTAGE_PARAMETERS_V1_3
 {
   UCHAR    ucVoltageType;               // To tell which voltage to set up, VDDC/MVDDC/MVDDQ/VDDCI
@@ -2290,15 +2292,36 @@ typedef struct  _GET_LEAKAGE_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_1
 #define        ATOM_GET_VOLTAGE_VID                0x00
 #define ATOM_GET_VOTLAGE_INIT_SEQ           0x03
 #define ATOM_GET_VOLTTAGE_PHASE_PHASE_VID   0x04
-// for SI, this state map to 0xff02 voltage state in Power Play table, which is power boost state
-#define        ATOM_GET_VOLTAGE_STATE0_LEAKAGE_VID 0x10
+#define ATOM_GET_VOLTAGE_SVID2              0x07        //Get SVI2 Regulator Info
 
+// for SI, this state map to 0xff02 voltage state in Power Play table, which is power boost state
+#define ATOM_GET_VOLTAGE_STATE0_LEAKAGE_VID 0x10
 // for SI, this state map to 0xff01 voltage state in Power Play table, which is performance state
 #define        ATOM_GET_VOLTAGE_STATE1_LEAKAGE_VID 0x11
-// undefined power state
+
 #define        ATOM_GET_VOLTAGE_STATE2_LEAKAGE_VID 0x12
 #define        ATOM_GET_VOLTAGE_STATE3_LEAKAGE_VID 0x13
 
+// New Added from CI Hawaii for GetVoltageInfoTable, input parameter structure
+typedef struct  _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2
+{
+  UCHAR    ucVoltageType;               // Input: To tell which voltage to set up, VDDC/MVDDC/MVDDQ/VDDCI
+  UCHAR    ucVoltageMode;               // Input: Indicate action: Get voltage info
+  USHORT   usVoltageLevel;              // Input: real voltage level in unit of mv or Voltage Phase (0, 1, 2, .. ) or Leakage Id 
+  ULONG    ulSCLKFreq;                  // Input: when ucVoltageMode= ATOM_GET_VOLTAGE_EVV_VOLTAGE, DPM state SCLK frequency, Define in PPTable SCLK/Voltage dependence table
+}GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2;
+
+// New in GetVoltageInfo v1.2 ucVoltageMode
+#define ATOM_GET_VOLTAGE_EVV_VOLTAGE        0x09        
+
+// New Added from CI Hawaii for EVV feature 
+typedef struct  _GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2
+{
+  USHORT   usVoltageLevel;                               // real voltage level in unit of mv
+  USHORT   usVoltageId;                                  // Voltage Id programmed in Voltage Regulator
+  ULONG    ulReseved;
+}GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2;
+
 /****************************************************************************/ 
 // Structures used by TVEncoderControlTable
 /****************************************************************************/ 
@@ -3864,6 +3887,8 @@ typedef struct _ATOM_GPIO_PIN_ASSIGNMENT
 #define PP_AC_DC_SWITCH_GPIO_PINID          60
 //from SMU7.x, if ucGPIO_ID=VDDC_REGULATOR_VRHOT_GPIO_PINID in GPIO_LUTable, VRHot feature is enable
 #define VDDC_VRHOT_GPIO_PINID               61
+//if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable, Peak Current Control feature is enabled
+#define VDDC_PCC_GPIO_PINID                 62
 
 typedef struct _ATOM_GPIO_PIN_LUT
 {
@@ -4169,10 +4194,10 @@ typedef struct _ATOM_COMMON_RECORD_HEADER
 #define ATOM_OBJECT_LINK_RECORD_TYPE                   18 //Once this record is present under one object, it indicats the oobject is linked to another obj described by the record
 #define ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE          19
 #define ATOM_ENCODER_CAP_RECORD_TYPE                   20
-
+#define ATOM_BRACKET_LAYOUT_RECORD_TYPE                21
 
 //Must be updated when new record type is added,equal to that record definition!
-#define ATOM_MAX_OBJECT_RECORD_NUMBER             ATOM_ENCODER_CAP_RECORD_TYPE
+#define ATOM_MAX_OBJECT_RECORD_NUMBER             ATOM_BRACKET_LAYOUT_RECORD_TYPE
 
 typedef struct  _ATOM_I2C_RECORD
 {
@@ -4397,6 +4422,31 @@ typedef struct _ATOM_CONNECTOR_REMOTE_CAP_RECORD
   USHORT                      usReserved;
 }ATOM_CONNECTOR_REMOTE_CAP_RECORD;
 
+typedef struct  _ATOM_CONNECTOR_LAYOUT_INFO
+{
+   USHORT usConnectorObjectId;
+   UCHAR  ucConnectorType;
+   UCHAR  ucPosition;
+}ATOM_CONNECTOR_LAYOUT_INFO;
+
+// define ATOM_CONNECTOR_LAYOUT_INFO.ucConnectorType to describe the display connector size
+#define CONNECTOR_TYPE_DVI_D                 1
+#define CONNECTOR_TYPE_DVI_I                 2
+#define CONNECTOR_TYPE_VGA                   3
+#define CONNECTOR_TYPE_HDMI                  4
+#define CONNECTOR_TYPE_DISPLAY_PORT          5
+#define CONNECTOR_TYPE_MINI_DISPLAY_PORT     6
+
+typedef struct  _ATOM_BRACKET_LAYOUT_RECORD
+{
+  ATOM_COMMON_RECORD_HEADER   sheader;
+  UCHAR                       ucLength;
+  UCHAR                       ucWidth;
+  UCHAR                       ucConnNum;
+  UCHAR                       ucReserved;
+  ATOM_CONNECTOR_LAYOUT_INFO  asConnInfo[1];
+}ATOM_BRACKET_LAYOUT_RECORD;
+
 /****************************************************************************/ 
 // ASIC voltage data table
 /****************************************************************************/ 
@@ -4524,8 +4574,9 @@ typedef struct _ATOM_VOLTAGE_OBJECT_HEADER_V3{
 #define VOLTAGE_OBJ_VR_I2C_INIT_SEQ          3        //VOLTAGE REGULATOR INIT sequece through I2C -> ATOM_I2C_VOLTAGE_OBJECT_V3
 #define VOLTAGE_OBJ_PHASE_LUT                4        //Set Vregulator Phase lookup table ->ATOM_GPIO_VOLTAGE_OBJECT_V3
 #define VOLTAGE_OBJ_SVID2                    7        //Indicate voltage control by SVID2 ->ATOM_SVID2_VOLTAGE_OBJECT_V3
-#define        VOLTAGE_OBJ_PWRBOOST_LEAKAGE_LUT     0x10     //Powerboost Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
-#define        VOLTAGE_OBJ_HIGH_STATE_LEAKAGE_LUT   0x11     //High voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_EVV                      8 
+#define VOLTAGE_OBJ_PWRBOOST_LEAKAGE_LUT     0x10     //Powerboost Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_HIGH_STATE_LEAKAGE_LUT   0x11     //High voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
 #define VOLTAGE_OBJ_HIGH1_STATE_LEAKAGE_LUT  0x12     //High1 voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
 
 typedef struct  _VOLTAGE_LUT_ENTRY_V2
@@ -4552,6 +4603,10 @@ typedef struct  _ATOM_I2C_VOLTAGE_OBJECT_V3
    VOLTAGE_LUT_ENTRY asVolI2cLut[1];        // end with 0xff
 }ATOM_I2C_VOLTAGE_OBJECT_V3;
 
+// ATOM_I2C_VOLTAGE_OBJECT_V3.ucVoltageControlFlag
+#define VOLTAGE_DATA_ONE_BYTE                0
+#define VOLTAGE_DATA_TWO_BYTE                1
+
 typedef struct  _ATOM_GPIO_VOLTAGE_OBJECT_V3
 {
    ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;   // voltage mode = VOLTAGE_OBJ_GPIO_LUT or VOLTAGE_OBJ_PHASE_LUT
@@ -4584,7 +4639,8 @@ typedef struct  _ATOM_SVID2_VOLTAGE_OBJECT_V3
 // 1:0 \96 offset trim, 
    USHORT   usLoadLine_PSI;    
 // GPU GPIO pin Id to SVID2 regulator VRHot pin. possible value 0~31. 0 means GPIO0, 31 means GPIO31
-   UCHAR    ucReserved[2];
+   UCHAR    ucSVDGpioId;     //0~31 indicate GPIO0~31
+   UCHAR    ucSVCGpioId;     //0~31 indicate GPIO0~31
    ULONG    ulReserved;
 }ATOM_SVID2_VOLTAGE_OBJECT_V3;
 
@@ -4637,6 +4693,49 @@ typedef struct  _ATOM_ASIC_PROFILING_INFO_V2_1
   USHORT usElbVDDCI_LevelArrayOffset;    // offset of 2 dimension voltage level USHORT array
 }ATOM_ASIC_PROFILING_INFO_V2_1;
 
+typedef struct  _ATOM_ASIC_PROFILING_INFO_V3_1
+{
+  ATOM_COMMON_TABLE_HEADER         asHeader; 
+  ULONG  ulEvvDerateTdp;
+  ULONG  ulEvvDerateTdc;
+  ULONG  ulBoardCoreTemp;
+  ULONG  ulMaxVddc;
+  ULONG  ulMinVddc;
+  ULONG  ulLoadLineSlop;
+  ULONG  ulLeakageTemp;
+  ULONG  ulLeakageVoltage;
+  ULONG  ulCACmEncodeRange;
+  ULONG  ulCACmEncodeAverage;
+  ULONG  ulCACbEncodeRange;
+  ULONG  ulCACbEncodeAverage;
+  ULONG  ulKt_bEncodeRange;
+  ULONG  ulKt_bEncodeAverage;
+  ULONG  ulKv_mEncodeRange;
+  ULONG  ulKv_mEncodeAverage;
+  ULONG  ulKv_bEncodeRange;
+  ULONG  ulKv_bEncodeAverage;
+  ULONG  ulLkgEncodeLn_MaxDivMin;
+  ULONG  ulLkgEncodeMin;
+  ULONG  ulEfuseLogisticAlpha;
+  USHORT usPowerDpm0;
+  USHORT usCurrentDpm0;
+  USHORT usPowerDpm1;
+  USHORT usCurrentDpm1;
+  USHORT usPowerDpm2;
+  USHORT usCurrentDpm2;
+  USHORT usPowerDpm3;
+  USHORT usCurrentDpm3;
+  USHORT usPowerDpm4;
+  USHORT usCurrentDpm4;
+  USHORT usPowerDpm5;
+  USHORT usCurrentDpm5;
+  USHORT usPowerDpm6;
+  USHORT usCurrentDpm6;
+  USHORT usPowerDpm7;
+  USHORT usCurrentDpm7;
+}ATOM_ASIC_PROFILING_INFO_V3_1;
+
+
 typedef struct _ATOM_POWER_SOURCE_OBJECT
 {
        UCHAR   ucPwrSrcId;                                                                                                     // Power source
@@ -5808,6 +5907,8 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3
 #define ATOM_S7_DOS_MODE_PIXEL_DEPTHb0      0x0C
 #define ATOM_S7_DOS_MODE_PIXEL_FORMATb0     0xF0
 #define ATOM_S7_DOS_8BIT_DAC_ENb1           0x01
+#define ATOM_S7_ASIC_INIT_COMPLETEb1        0x02
+#define ATOM_S7_ASIC_INIT_COMPLETE_MASK     0x00000200
 #define ATOM_S7_DOS_MODE_NUMBERw1           0x0FFFF
 
 #define ATOM_S7_DOS_8BIT_DAC_EN_SHIFT       8
@@ -6242,6 +6343,7 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE
 #define _128Mx32            0x53
 #define _256Mx8             0x61
 #define _256Mx16            0x62
+#define _512Mx8             0x71
 
 #define SAMSUNG             0x1
 #define INFINEON            0x2
@@ -6987,9 +7089,10 @@ typedef struct _ATOM_DISP_OUT_INFO_V3
   UCHAR  ucMaxDispEngineNum;
   UCHAR  ucMaxActiveDispEngineNum;
   UCHAR  ucMaxPPLLNum;
-  UCHAR  ucCoreRefClkSource;                          // value of CORE_REF_CLK_SOURCE
-  UCHAR  ucReserved[3];
-       ASIC_TRANSMITTER_INFO_V2  asTransmitterInfo[1];     // for alligment only
+  UCHAR  ucCoreRefClkSource;                    // value of CORE_REF_CLK_SOURCE
+  UCHAR  ucDispCaps;
+  UCHAR  ucReserved[2];
+  ASIC_TRANSMITTER_INFO_V2  asTransmitterInfo[1];     // for alligment only
 }ATOM_DISP_OUT_INFO_V3;
 
 //ucDispCaps
index 86d9ee0..80a2012 100644 (file)
@@ -1910,6 +1910,21 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
        int i;
 
        atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+       if (crtc->fb) {
+               int r;
+               struct radeon_framebuffer *radeon_fb;
+               struct radeon_bo *rbo;
+
+               radeon_fb = to_radeon_framebuffer(crtc->fb);
+               rbo = gem_to_radeon_bo(radeon_fb->obj);
+               r = radeon_bo_reserve(rbo, false);
+               if (unlikely(r))
+                       DRM_ERROR("failed to reserve rbo before unpin\n");
+               else {
+                       radeon_bo_unpin(rbo);
+                       radeon_bo_unreserve(rbo);
+               }
+       }
        /* disable the GRPH */
        if (ASIC_IS_DCE4(rdev))
                WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 0);
@@ -1940,7 +1955,9 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
                break;
        case ATOM_PPLL0:
                /* disable the ppll */
-               if ((rdev->family == CHIP_ARUBA) || (rdev->family == CHIP_BONAIRE))
+               if ((rdev->family == CHIP_ARUBA) ||
+                   (rdev->family == CHIP_BONAIRE) ||
+                   (rdev->family == CHIP_HAWAII))
                        atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
                                                  0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
                break;
index eb3ba60..a42d615 100644 (file)
@@ -707,24 +707,37 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        switch (connector->connector_type) {
        case DRM_MODE_CONNECTOR_DVII:
        case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
-               if ((radeon_connector->audio == RADEON_AUDIO_ENABLE) ||
-                   (drm_detect_hdmi_monitor(radeon_connector->edid) &&
-                    (radeon_connector->audio == RADEON_AUDIO_AUTO)))
-                       return ATOM_ENCODER_MODE_HDMI;
-               else if (radeon_connector->use_digital)
+               if (radeon_audio != 0) {
+                       if (radeon_connector->use_digital &&
+                           (radeon_connector->audio == RADEON_AUDIO_ENABLE))
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
+                                (radeon_connector->audio == RADEON_AUDIO_AUTO))
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else if (radeon_connector->use_digital)
+                               return ATOM_ENCODER_MODE_DVI;
+                       else
+                               return ATOM_ENCODER_MODE_CRT;
+               } else if (radeon_connector->use_digital) {
                        return ATOM_ENCODER_MODE_DVI;
-               else
+               } else {
                        return ATOM_ENCODER_MODE_CRT;
+               }
                break;
        case DRM_MODE_CONNECTOR_DVID:
        case DRM_MODE_CONNECTOR_HDMIA:
        default:
-               if ((radeon_connector->audio == RADEON_AUDIO_ENABLE) ||
-                   (drm_detect_hdmi_monitor(radeon_connector->edid) &&
-                    (radeon_connector->audio == RADEON_AUDIO_AUTO)))
-                       return ATOM_ENCODER_MODE_HDMI;
-               else
+               if (radeon_audio != 0) {
+                       if (radeon_connector->audio == RADEON_AUDIO_ENABLE)
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
+                                (radeon_connector->audio == RADEON_AUDIO_AUTO))
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else
+                               return ATOM_ENCODER_MODE_DVI;
+               } else {
                        return ATOM_ENCODER_MODE_DVI;
+               }
                break;
        case DRM_MODE_CONNECTOR_LVDS:
                return ATOM_ENCODER_MODE_LVDS;
@@ -732,14 +745,19 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        case DRM_MODE_CONNECTOR_DisplayPort:
                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))
+                   (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
                        return ATOM_ENCODER_MODE_DP;
-               else if ((radeon_connector->audio == RADEON_AUDIO_ENABLE) ||
-                        (drm_detect_hdmi_monitor(radeon_connector->edid) &&
-                         (radeon_connector->audio == RADEON_AUDIO_AUTO)))
-                       return ATOM_ENCODER_MODE_HDMI;
-               else
+               } else if (radeon_audio != 0) {
+                       if (radeon_connector->audio == RADEON_AUDIO_ENABLE)
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
+                                (radeon_connector->audio == RADEON_AUDIO_AUTO))
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else
+                               return ATOM_ENCODER_MODE_DVI;
+               } else {
                        return ATOM_ENCODER_MODE_DVI;
+               }
                break;
        case DRM_MODE_CONNECTOR_eDP:
                return ATOM_ENCODER_MODE_DP;
index b162e98..9b6950d 100644 (file)
@@ -1930,7 +1930,7 @@ static int btc_set_mc_special_registers(struct radeon_device *rdev,
                        }
                        j++;
 
-                       if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+                       if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
                                return -EINVAL;
 
                        tmp = RREG32(MC_PMG_CMD_MRS);
@@ -1945,7 +1945,7 @@ static int btc_set_mc_special_registers(struct radeon_device *rdev,
                        }
                        j++;
 
-                       if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+                       if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
                                return -EINVAL;
                        break;
                case MC_SEQ_RESERVE_M >> 2:
@@ -1959,7 +1959,7 @@ static int btc_set_mc_special_registers(struct radeon_device *rdev,
                        }
                        j++;
 
-                       if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+                       if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
                                return -EINVAL;
                        break;
                default:
index 51e947a..1ed4799 100644 (file)
 #define VOLTAGE_VID_OFFSET_SCALE1    625
 #define VOLTAGE_VID_OFFSET_SCALE2    100
 
+static const struct ci_pt_defaults defaults_hawaii_xt =
+{
+       1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000,
+       { 0x84,  0x0,   0x0,   0x7F,  0x0,   0x0,   0x5A,  0x60,  0x51,  0x8E,  0x79,  0x6B,  0x5F,  0x90,  0x79  },
+       { 0x1EA, 0x1EA, 0x1EA, 0x224, 0x224, 0x224, 0x24F, 0x24F, 0x24F, 0x28E, 0x28E, 0x28E, 0x2BC, 0x2BC, 0x2BC }
+};
+
+static const struct ci_pt_defaults defaults_hawaii_pro =
+{
+       1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062,
+       { 0x93,  0x0,   0x0,   0x97,  0x0,   0x0,   0x6B,  0x60,  0x51,  0x95,  0x79,  0x6B,  0x5F,  0x90,  0x79  },
+       { 0x1EA, 0x1EA, 0x1EA, 0x224, 0x224, 0x224, 0x24F, 0x24F, 0x24F, 0x28E, 0x28E, 0x28E, 0x2BC, 0x2BC, 0x2BC }
+};
+
 static const struct ci_pt_defaults defaults_bonaire_xt =
 {
        1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
@@ -187,22 +201,38 @@ static void ci_initialize_powertune_defaults(struct radeon_device *rdev)
        struct ci_power_info *pi = ci_get_pi(rdev);
 
        switch (rdev->pdev->device) {
-        case 0x6650:
-        case 0x6658:
-        case 0x665C:
-        default:
+       case 0x6650:
+       case 0x6658:
+       case 0x665C:
+       default:
                pi->powertune_defaults = &defaults_bonaire_xt;
                break;
-        case 0x6651:
-        case 0x665D:
+       case 0x6651:
+       case 0x665D:
                pi->powertune_defaults = &defaults_bonaire_pro;
                break;
-        case 0x6640:
+       case 0x6640:
                pi->powertune_defaults = &defaults_saturn_xt;
                break;
-        case 0x6641:
+       case 0x6641:
                pi->powertune_defaults = &defaults_saturn_pro;
                break;
+       case 0x67B8:
+       case 0x67B0:
+       case 0x67A0:
+       case 0x67A1:
+       case 0x67A2:
+       case 0x67A8:
+       case 0x67A9:
+       case 0x67AA:
+       case 0x67B9:
+       case 0x67BE:
+               pi->powertune_defaults = &defaults_hawaii_xt;
+               break;
+       case 0x67BA:
+       case 0x67B1:
+               pi->powertune_defaults = &defaults_hawaii_pro;
+               break;
        }
 
        pi->dte_tj_offset = 0;
@@ -5142,9 +5172,15 @@ int ci_dpm_init(struct radeon_device *rdev)
        rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
        rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
 
-       pi->thermal_temp_setting.temperature_low = 99500;
-       pi->thermal_temp_setting.temperature_high = 100000;
-       pi->thermal_temp_setting.temperature_shutdown = 104000;
+       if (rdev->family == CHIP_HAWAII) {
+               pi->thermal_temp_setting.temperature_low = 94500;
+               pi->thermal_temp_setting.temperature_high = 95000;
+               pi->thermal_temp_setting.temperature_shutdown = 104000;
+       } else {
+               pi->thermal_temp_setting.temperature_low = 99500;
+               pi->thermal_temp_setting.temperature_high = 100000;
+               pi->thermal_temp_setting.temperature_shutdown = 104000;
+       }
 
        pi->uvd_enabled = false;
 
index 252e10a..9c745dd 100644 (file)
@@ -217,6 +217,10 @@ int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
                ucode_start_address = BONAIRE_SMC_UCODE_START;
                ucode_size = BONAIRE_SMC_UCODE_SIZE;
                break;
+       case CHIP_HAWAII:
+               ucode_start_address = HAWAII_SMC_UCODE_START;
+               ucode_size = HAWAII_SMC_UCODE_SIZE;
+               break;
        default:
                DRM_ERROR("unknown asic in smc ucode loader\n");
                BUG();
index 2e48f90..ae92aa0 100644 (file)
@@ -41,6 +41,14 @@ MODULE_FIRMWARE("radeon/BONAIRE_mc.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_rlc.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_sdma.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_smc.bin");
+MODULE_FIRMWARE("radeon/HAWAII_pfp.bin");
+MODULE_FIRMWARE("radeon/HAWAII_me.bin");
+MODULE_FIRMWARE("radeon/HAWAII_ce.bin");
+MODULE_FIRMWARE("radeon/HAWAII_mec.bin");
+MODULE_FIRMWARE("radeon/HAWAII_mc.bin");
+MODULE_FIRMWARE("radeon/HAWAII_rlc.bin");
+MODULE_FIRMWARE("radeon/HAWAII_sdma.bin");
+MODULE_FIRMWARE("radeon/HAWAII_smc.bin");
 MODULE_FIRMWARE("radeon/KAVERI_pfp.bin");
 MODULE_FIRMWARE("radeon/KAVERI_me.bin");
 MODULE_FIRMWARE("radeon/KAVERI_ce.bin");
@@ -72,6 +80,8 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev);
 static void cik_program_aspm(struct radeon_device *rdev);
 static void cik_init_pg(struct radeon_device *rdev);
 static void cik_init_cg(struct radeon_device *rdev);
+static void cik_fini_pg(struct radeon_device *rdev);
+static void cik_fini_cg(struct radeon_device *rdev);
 static void cik_enable_gui_idle_interrupt(struct radeon_device *rdev,
                                          bool enable);
 
@@ -1295,6 +1305,171 @@ static const u32 kalindi_mgcg_cgcg_init[] =
        0xd80c, 0xff000ff0, 0x00000100
 };
 
+static const u32 hawaii_golden_spm_registers[] =
+{
+       0x30800, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 hawaii_golden_common_registers[] =
+{
+       0x30800, 0xffffffff, 0xe0000000,
+       0x28350, 0xffffffff, 0x3a00161a,
+       0x28354, 0xffffffff, 0x0000002e,
+       0x9a10, 0xffffffff, 0x00018208,
+       0x98f8, 0xffffffff, 0x12011003
+};
+
+static const u32 hawaii_golden_registers[] =
+{
+       0x3354, 0x00000333, 0x00000333,
+       0x9a10, 0x00010000, 0x00058208,
+       0x9830, 0xffffffff, 0x00000000,
+       0x9834, 0xf00fffff, 0x00000400,
+       0x9838, 0x0002021c, 0x00020200,
+       0xc78, 0x00000080, 0x00000000,
+       0x5bb0, 0x000000f0, 0x00000070,
+       0x5bc0, 0xf0311fff, 0x80300000,
+       0x350c, 0x00810000, 0x408af000,
+       0x7030, 0x31000111, 0x00000011,
+       0x2f48, 0x73773777, 0x12010001,
+       0x2120, 0x0000007f, 0x0000001b,
+       0x21dc, 0x00007fb6, 0x00002191,
+       0x3628, 0x0000003f, 0x0000000a,
+       0x362c, 0x0000003f, 0x0000000a,
+       0x2ae4, 0x00073ffe, 0x000022a2,
+       0x240c, 0x000007ff, 0x00000000,
+       0x8bf0, 0x00002001, 0x00000001,
+       0x8b24, 0xffffffff, 0x00ffffff,
+       0x30a04, 0x0000ff0f, 0x00000000,
+       0x28a4c, 0x07ffffff, 0x06000000,
+       0x3e78, 0x00000001, 0x00000002,
+       0xc768, 0x00000008, 0x00000008,
+       0xc770, 0x00000f00, 0x00000800,
+       0xc774, 0x00000f00, 0x00000800,
+       0xc798, 0x00ffffff, 0x00ff7fbf,
+       0xc79c, 0x00ffffff, 0x00ff7faf,
+       0x8c00, 0x000000ff, 0x00000800,
+       0xe40, 0x00001fff, 0x00001fff,
+       0x9060, 0x0000007f, 0x00000020,
+       0x9508, 0x00010000, 0x00010000,
+       0xae00, 0x00100000, 0x000ff07c,
+       0xac14, 0x000003ff, 0x0000000f,
+       0xac10, 0xffffffff, 0x7564fdec,
+       0xac0c, 0xffffffff, 0x3120b9a8,
+       0xac08, 0x20000000, 0x0f9c0000
+};
+
+static const u32 hawaii_mgcg_cgcg_init[] =
+{
+       0xc420, 0xffffffff, 0xfffffffd,
+       0x30800, 0xffffffff, 0xe0000000,
+       0x3c2a0, 0xffffffff, 0x00000100,
+       0x3c208, 0xffffffff, 0x00000100,
+       0x3c2c0, 0xffffffff, 0x00000100,
+       0x3c2c8, 0xffffffff, 0x00000100,
+       0x3c2c4, 0xffffffff, 0x00000100,
+       0x55e4, 0xffffffff, 0x00200100,
+       0x3c280, 0xffffffff, 0x00000100,
+       0x3c214, 0xffffffff, 0x06000100,
+       0x3c220, 0xffffffff, 0x00000100,
+       0x3c218, 0xffffffff, 0x06000100,
+       0x3c204, 0xffffffff, 0x00000100,
+       0x3c2e0, 0xffffffff, 0x00000100,
+       0x3c224, 0xffffffff, 0x00000100,
+       0x3c200, 0xffffffff, 0x00000100,
+       0x3c230, 0xffffffff, 0x00000100,
+       0x3c234, 0xffffffff, 0x00000100,
+       0x3c250, 0xffffffff, 0x00000100,
+       0x3c254, 0xffffffff, 0x00000100,
+       0x3c258, 0xffffffff, 0x00000100,
+       0x3c25c, 0xffffffff, 0x00000100,
+       0x3c260, 0xffffffff, 0x00000100,
+       0x3c27c, 0xffffffff, 0x00000100,
+       0x3c278, 0xffffffff, 0x00000100,
+       0x3c210, 0xffffffff, 0x06000100,
+       0x3c290, 0xffffffff, 0x00000100,
+       0x3c274, 0xffffffff, 0x00000100,
+       0x3c2b4, 0xffffffff, 0x00000100,
+       0x3c2b0, 0xffffffff, 0x00000100,
+       0x3c270, 0xffffffff, 0x00000100,
+       0x30800, 0xffffffff, 0xe0000000,
+       0x3c020, 0xffffffff, 0x00010000,
+       0x3c024, 0xffffffff, 0x00030002,
+       0x3c028, 0xffffffff, 0x00040007,
+       0x3c02c, 0xffffffff, 0x00060005,
+       0x3c030, 0xffffffff, 0x00090008,
+       0x3c034, 0xffffffff, 0x00010000,
+       0x3c038, 0xffffffff, 0x00030002,
+       0x3c03c, 0xffffffff, 0x00040007,
+       0x3c040, 0xffffffff, 0x00060005,
+       0x3c044, 0xffffffff, 0x00090008,
+       0x3c048, 0xffffffff, 0x00010000,
+       0x3c04c, 0xffffffff, 0x00030002,
+       0x3c050, 0xffffffff, 0x00040007,
+       0x3c054, 0xffffffff, 0x00060005,
+       0x3c058, 0xffffffff, 0x00090008,
+       0x3c05c, 0xffffffff, 0x00010000,
+       0x3c060, 0xffffffff, 0x00030002,
+       0x3c064, 0xffffffff, 0x00040007,
+       0x3c068, 0xffffffff, 0x00060005,
+       0x3c06c, 0xffffffff, 0x00090008,
+       0x3c070, 0xffffffff, 0x00010000,
+       0x3c074, 0xffffffff, 0x00030002,
+       0x3c078, 0xffffffff, 0x00040007,
+       0x3c07c, 0xffffffff, 0x00060005,
+       0x3c080, 0xffffffff, 0x00090008,
+       0x3c084, 0xffffffff, 0x00010000,
+       0x3c088, 0xffffffff, 0x00030002,
+       0x3c08c, 0xffffffff, 0x00040007,
+       0x3c090, 0xffffffff, 0x00060005,
+       0x3c094, 0xffffffff, 0x00090008,
+       0x3c098, 0xffffffff, 0x00010000,
+       0x3c09c, 0xffffffff, 0x00030002,
+       0x3c0a0, 0xffffffff, 0x00040007,
+       0x3c0a4, 0xffffffff, 0x00060005,
+       0x3c0a8, 0xffffffff, 0x00090008,
+       0x3c0ac, 0xffffffff, 0x00010000,
+       0x3c0b0, 0xffffffff, 0x00030002,
+       0x3c0b4, 0xffffffff, 0x00040007,
+       0x3c0b8, 0xffffffff, 0x00060005,
+       0x3c0bc, 0xffffffff, 0x00090008,
+       0x3c0c0, 0xffffffff, 0x00010000,
+       0x3c0c4, 0xffffffff, 0x00030002,
+       0x3c0c8, 0xffffffff, 0x00040007,
+       0x3c0cc, 0xffffffff, 0x00060005,
+       0x3c0d0, 0xffffffff, 0x00090008,
+       0x3c0d4, 0xffffffff, 0x00010000,
+       0x3c0d8, 0xffffffff, 0x00030002,
+       0x3c0dc, 0xffffffff, 0x00040007,
+       0x3c0e0, 0xffffffff, 0x00060005,
+       0x3c0e4, 0xffffffff, 0x00090008,
+       0x3c0e8, 0xffffffff, 0x00010000,
+       0x3c0ec, 0xffffffff, 0x00030002,
+       0x3c0f0, 0xffffffff, 0x00040007,
+       0x3c0f4, 0xffffffff, 0x00060005,
+       0x3c0f8, 0xffffffff, 0x00090008,
+       0xc318, 0xffffffff, 0x00020200,
+       0x3350, 0xffffffff, 0x00000200,
+       0x15c0, 0xffffffff, 0x00000400,
+       0x55e8, 0xffffffff, 0x00000000,
+       0x2f50, 0xffffffff, 0x00000902,
+       0x3c000, 0xffffffff, 0x96940200,
+       0x8708, 0xffffffff, 0x00900100,
+       0xc424, 0xffffffff, 0x0020003f,
+       0x38, 0xffffffff, 0x0140001c,
+       0x3c, 0x000f0000, 0x000f0000,
+       0x220, 0xffffffff, 0xc060000c,
+       0x224, 0xc0000fff, 0x00000100,
+       0xf90, 0xffffffff, 0x00000100,
+       0xf98, 0x00000101, 0x00000000,
+       0x20a8, 0xffffffff, 0x00000104,
+       0x55e4, 0xff000fff, 0x00000100,
+       0x30cc, 0xc0000fff, 0x00000104,
+       0xc1e4, 0x00000001, 0x00000001,
+       0xd00c, 0xff000ff0, 0x00000100,
+       0xd80c, 0xff000ff0, 0x00000100
+};
+
 static void cik_init_golden_registers(struct radeon_device *rdev)
 {
        switch (rdev->family) {
@@ -1340,6 +1515,20 @@ static void cik_init_golden_registers(struct radeon_device *rdev)
                                                 spectre_golden_spm_registers,
                                                 (const u32)ARRAY_SIZE(spectre_golden_spm_registers));
                break;
+       case CHIP_HAWAII:
+               radeon_program_register_sequence(rdev,
+                                                hawaii_mgcg_cgcg_init,
+                                                (const u32)ARRAY_SIZE(hawaii_mgcg_cgcg_init));
+               radeon_program_register_sequence(rdev,
+                                                hawaii_golden_registers,
+                                                (const u32)ARRAY_SIZE(hawaii_golden_registers));
+               radeon_program_register_sequence(rdev,
+                                                hawaii_golden_common_registers,
+                                                (const u32)ARRAY_SIZE(hawaii_golden_common_registers));
+               radeon_program_register_sequence(rdev,
+                                                hawaii_golden_spm_registers,
+                                                (const u32)ARRAY_SIZE(hawaii_golden_spm_registers));
+               break;
        default:
                break;
        }
@@ -1447,6 +1636,35 @@ static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
        {0x0000009f, 0x00b48000}
 };
 
+#define HAWAII_IO_MC_REGS_SIZE 22
+
+static const u32 hawaii_io_mc_regs[HAWAII_IO_MC_REGS_SIZE][2] =
+{
+       {0x0000007d, 0x40000000},
+       {0x0000007e, 0x40180304},
+       {0x0000007f, 0x0000ff00},
+       {0x00000081, 0x00000000},
+       {0x00000083, 0x00000800},
+       {0x00000086, 0x00000000},
+       {0x00000087, 0x00000100},
+       {0x00000088, 0x00020100},
+       {0x00000089, 0x00000000},
+       {0x0000008b, 0x00040000},
+       {0x0000008c, 0x00000100},
+       {0x0000008e, 0xff010000},
+       {0x00000090, 0xffffefff},
+       {0x00000091, 0xfff3efff},
+       {0x00000092, 0xfff3efbf},
+       {0x00000093, 0xf7ffffff},
+       {0x00000094, 0xffffff7f},
+       {0x00000095, 0x00000fff},
+       {0x00000096, 0x00116fff},
+       {0x00000097, 0x60010000},
+       {0x00000098, 0x10010000},
+       {0x0000009f, 0x00c79000}
+};
+
+
 /**
  * cik_srbm_select - select specific register instances
  *
@@ -1491,11 +1709,17 @@ static int ci_mc_load_microcode(struct radeon_device *rdev)
 
        switch (rdev->family) {
        case CHIP_BONAIRE:
-       default:
                io_mc_regs = (u32 *)&bonaire_io_mc_regs;
                ucode_size = CIK_MC_UCODE_SIZE;
                regs_size = BONAIRE_IO_MC_REGS_SIZE;
                break;
+       case CHIP_HAWAII:
+               io_mc_regs = (u32 *)&hawaii_io_mc_regs;
+               ucode_size = HAWAII_MC_UCODE_SIZE;
+               regs_size = HAWAII_IO_MC_REGS_SIZE;
+               break;
+       default:
+               return -EINVAL;
        }
 
        running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK;
@@ -1557,8 +1781,8 @@ static int cik_init_microcode(struct radeon_device *rdev)
 {
        const char *chip_name;
        size_t pfp_req_size, me_req_size, ce_req_size,
-               mec_req_size, rlc_req_size, mc_req_size,
-               sdma_req_size, smc_req_size;
+               mec_req_size, rlc_req_size, mc_req_size = 0,
+               sdma_req_size, smc_req_size = 0;
        char fw_name[30];
        int err;
 
@@ -1576,6 +1800,17 @@ static int cik_init_microcode(struct radeon_device *rdev)
                sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
                smc_req_size = ALIGN(BONAIRE_SMC_UCODE_SIZE, 4);
                break;
+       case CHIP_HAWAII:
+               chip_name = "HAWAII";
+               pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
+               me_req_size = CIK_ME_UCODE_SIZE * 4;
+               ce_req_size = CIK_CE_UCODE_SIZE * 4;
+               mec_req_size = CIK_MEC_UCODE_SIZE * 4;
+               rlc_req_size = BONAIRE_RLC_UCODE_SIZE * 4;
+               mc_req_size = HAWAII_MC_UCODE_SIZE * 4;
+               sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
+               smc_req_size = ALIGN(HAWAII_SMC_UCODE_SIZE, 4);
+               break;
        case CHIP_KAVERI:
                chip_name = "KAVERI";
                pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
@@ -1687,6 +1922,7 @@ static int cik_init_microcode(struct radeon_device *rdev)
                               fw_name);
                        release_firmware(rdev->smc_fw);
                        rdev->smc_fw = NULL;
+                       err = 0;
                } else if (rdev->smc_fw->size != smc_req_size) {
                        printk(KERN_ERR
                               "cik_smc: Bogus length %zu in firmware \"%s\"\n",
@@ -1755,9 +1991,227 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
 
        num_pipe_configs = rdev->config.cik.max_tile_pipes;
        if (num_pipe_configs > 8)
-               num_pipe_configs = 8; /* ??? */
+               num_pipe_configs = 16;
 
-       if (num_pipe_configs == 8) {
+       if (num_pipe_configs == 16) {
+               for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+                       switch (reg_offset) {
+                       case 0:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B));
+                               break;
+                       case 1:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B));
+                               break;
+                       case 2:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+                               break;
+                       case 3:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B));
+                               break;
+                       case 4:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                TILE_SPLIT(split_equal_to_row_size));
+                               break;
+                       case 5:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+                               break;
+                       case 6:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+                               break;
+                       case 7:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                TILE_SPLIT(split_equal_to_row_size));
+                               break;
+                       case 8:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16));
+                               break;
+                       case 9:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
+                               break;
+                       case 10:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 11:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) |
+                                                SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 12:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 13:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
+                               break;
+                       case 14:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 16:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) |
+                                                SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 17:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 27:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
+                               break;
+                       case 28:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 29:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) |
+                                                SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 30:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                                SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       default:
+                               gb_tile_moden = 0;
+                               break;
+                       }
+                       rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
+                       WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+               }
+               for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
+                       switch (reg_offset) {
+                       case 0:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK));
+                               break;
+                       case 1:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK));
+                               break;
+                       case 2:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK));
+                               break;
+                       case 3:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK));
+                               break;
+                       case 4:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                                NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 5:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                                NUM_BANKS(ADDR_SURF_4_BANK));
+                               break;
+                       case 6:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                                NUM_BANKS(ADDR_SURF_2_BANK));
+                               break;
+                       case 8:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK));
+                               break;
+                       case 9:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK));
+                               break;
+                       case 10:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK));
+                               break;
+                       case 11:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                                NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 12:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                                NUM_BANKS(ADDR_SURF_4_BANK));
+                               break;
+                       case 13:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                                NUM_BANKS(ADDR_SURF_2_BANK));
+                               break;
+                       case 14:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                                NUM_BANKS(ADDR_SURF_2_BANK));
+                               break;
+                       default:
+                               gb_tile_moden = 0;
+                               break;
+                       }
+                       WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+               }
+       } else if (num_pipe_configs == 8) {
                for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
                        switch (reg_offset) {
                        case 0:
@@ -2642,7 +3096,10 @@ static void cik_setup_rb(struct radeon_device *rdev,
                for (j = 0; j < sh_per_se; j++) {
                        cik_select_se_sh(rdev, i, j);
                        data = cik_get_rb_disabled(rdev, max_rb_num, se_num, sh_per_se);
-                       disabled_rbs |= data << ((i * sh_per_se + j) * CIK_RB_BITMAP_WIDTH_PER_SH);
+                       if (rdev->family == CHIP_HAWAII)
+                               disabled_rbs |= data << ((i * sh_per_se + j) * HAWAII_RB_BITMAP_WIDTH_PER_SH);
+                       else
+                               disabled_rbs |= data << ((i * sh_per_se + j) * CIK_RB_BITMAP_WIDTH_PER_SH);
                }
        }
        cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
@@ -2659,6 +3116,12 @@ static void cik_setup_rb(struct radeon_device *rdev,
                data = 0;
                for (j = 0; j < sh_per_se; j++) {
                        switch (enabled_rbs & 3) {
+                       case 0:
+                               if (j == 0)
+                                       data |= PKR_MAP(RASTER_CONFIG_RB_MAP_3);
+                               else
+                                       data |= PKR_MAP(RASTER_CONFIG_RB_MAP_0);
+                               break;
                        case 1:
                                data |= (RASTER_CONFIG_RB_MAP_0 << (i * sh_per_se + j) * 2);
                                break;
@@ -2711,6 +3174,23 @@ static void cik_gpu_init(struct radeon_device *rdev)
                rdev->config.cik.sc_earlyz_tile_fifo_size = 0x130;
                gb_addr_config = BONAIRE_GB_ADDR_CONFIG_GOLDEN;
                break;
+       case CHIP_HAWAII:
+               rdev->config.cik.max_shader_engines = 4;
+               rdev->config.cik.max_tile_pipes = 16;
+               rdev->config.cik.max_cu_per_sh = 11;
+               rdev->config.cik.max_sh_per_se = 1;
+               rdev->config.cik.max_backends_per_se = 4;
+               rdev->config.cik.max_texture_channel_caches = 16;
+               rdev->config.cik.max_gprs = 256;
+               rdev->config.cik.max_gs_threads = 32;
+               rdev->config.cik.max_hw_contexts = 8;
+
+               rdev->config.cik.sc_prim_fifo_size_frontend = 0x20;
+               rdev->config.cik.sc_prim_fifo_size_backend = 0x100;
+               rdev->config.cik.sc_hiz_tile_fifo_size = 0x30;
+               rdev->config.cik.sc_earlyz_tile_fifo_size = 0x130;
+               gb_addr_config = HAWAII_GB_ADDR_CONFIG_GOLDEN;
+               break;
        case CHIP_KAVERI:
                rdev->config.cik.max_shader_engines = 1;
                rdev->config.cik.max_tile_pipes = 4;
@@ -3254,6 +3734,7 @@ int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
        r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
        if (r) {
                DRM_ERROR("radeon: failed to get ib (%d).\n", r);
+               radeon_scratch_free(rdev, scratch);
                return r;
        }
        ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1);
@@ -3270,6 +3751,8 @@ int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
        r = radeon_fence_wait(ib.fence, false);
        if (r) {
                DRM_ERROR("radeon: fence wait failed (%d).\n", r);
+               radeon_scratch_free(rdev, scratch);
+               radeon_ib_free(rdev, &ib);
                return r;
        }
        for (i = 0; i < rdev->usec_timeout; i++) {
@@ -3471,7 +3954,8 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)
        int r;
 
        WREG32(CP_SEM_WAIT_TIMER, 0x0);
-       WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0);
+       if (rdev->family != CHIP_HAWAII)
+               WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0);
 
        /* Set the write pointer delay */
        WREG32(CP_RB_WPTR_DELAY, 0);
@@ -4259,6 +4743,10 @@ static void cik_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
        dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
                 RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
 
+       /* disable CG/PG */
+       cik_fini_pg(rdev);
+       cik_fini_cg(rdev);
+
        /* stop the rlc */
        cik_rlc_stop(rdev);
 
@@ -4804,12 +5292,17 @@ void cik_vm_fini(struct radeon_device *rdev)
 static void cik_vm_decode_fault(struct radeon_device *rdev,
                                u32 status, u32 addr, u32 mc_client)
 {
-       u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT;
+       u32 mc_id;
        u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT;
        u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT;
        char block[5] = { mc_client >> 24, (mc_client >> 16) & 0xff,
                (mc_client >> 8) & 0xff, mc_client & 0xff, 0 };
 
+       if (rdev->family == CHIP_HAWAII)
+               mc_id = (status & HAWAII_MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT;
+       else
+               mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT;
+
        printk("VM fault (0x%02x, vmid %d) at page %u, %s from '%s' (0x%08x) (%d)\n",
               protections, vmid, addr,
               (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read",
@@ -5066,6 +5559,7 @@ static int cik_rlc_resume(struct radeon_device *rdev)
 
        switch (rdev->family) {
        case CHIP_BONAIRE:
+       case CHIP_HAWAII:
        default:
                size = BONAIRE_RLC_UCODE_SIZE;
                break;
@@ -5822,6 +6316,10 @@ void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer)
                buffer[count++] = cpu_to_le32(0x00000000); /* XXX */
                buffer[count++] = cpu_to_le32(0x00000000);
                break;
+       case CHIP_HAWAII:
+               buffer[count++] = 0x3a00161a;
+               buffer[count++] = 0x0000002e;
+               break;
        default:
                buffer[count++] = cpu_to_le32(0x00000000);
                buffer[count++] = cpu_to_le32(0x00000000);
index 8d84ebe..9c9529d 100644 (file)
@@ -102,14 +102,6 @@ void cik_sdma_fence_ring_emit(struct radeon_device *rdev,
 {
        struct radeon_ring *ring = &rdev->ring[fence->ring];
        u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
-       u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) |
-                         SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */
-       u32 ref_and_mask;
-
-       if (fence->ring == R600_RING_TYPE_DMA_INDEX)
-               ref_and_mask = SDMA0;
-       else
-               ref_and_mask = SDMA1;
 
        /* write the fence */
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_FENCE, 0, 0));
@@ -119,12 +111,12 @@ void cik_sdma_fence_ring_emit(struct radeon_device *rdev,
        /* generate an interrupt */
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_TRAP, 0, 0));
        /* flush HDP */
-       radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
-       radeon_ring_write(ring, GPU_HDP_FLUSH_DONE);
-       radeon_ring_write(ring, GPU_HDP_FLUSH_REQ);
-       radeon_ring_write(ring, ref_and_mask); /* REFERENCE */
-       radeon_ring_write(ring, ref_and_mask); /* MASK */
-       radeon_ring_write(ring, (4 << 16) | 10); /* RETRY_COUNT, POLL_INTERVAL */
+       /* We should be using the new POLL_REG_MEM special op packet here
+        * but it causes sDMA to hang sometimes
+        */
+       radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+       radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+       radeon_ring_write(ring, 0);
 }
 
 /**
@@ -720,18 +712,10 @@ void cik_sdma_vm_set_page(struct radeon_device *rdev,
 void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 {
        struct radeon_ring *ring = &rdev->ring[ridx];
-       u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) |
-                         SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */
-       u32 ref_and_mask;
 
        if (vm == NULL)
                return;
 
-       if (ridx == R600_RING_TYPE_DMA_INDEX)
-               ref_and_mask = SDMA0;
-       else
-               ref_and_mask = SDMA1;
-
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
        if (vm->id < 8) {
                radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
@@ -766,12 +750,12 @@ void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm
        radeon_ring_write(ring, VMID(0));
 
        /* flush HDP */
-       radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
-       radeon_ring_write(ring, GPU_HDP_FLUSH_DONE);
-       radeon_ring_write(ring, GPU_HDP_FLUSH_REQ);
-       radeon_ring_write(ring, ref_and_mask); /* REFERENCE */
-       radeon_ring_write(ring, ref_and_mask); /* MASK */
-       radeon_ring_write(ring, (4 << 16) | 10); /* RETRY_COUNT, POLL_INTERVAL */
+       /* We should be using the new POLL_REG_MEM special op packet here
+        * but it causes sDMA to hang sometimes
+        */
+       radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+       radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+       radeon_ring_write(ring, 0);
 
        /* flush TLB */
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
index 380cea3..5964af5 100644 (file)
 #define CIK_H
 
 #define BONAIRE_GB_ADDR_CONFIG_GOLDEN        0x12010001
+#define HAWAII_GB_ADDR_CONFIG_GOLDEN         0x12011003
 
-#define CIK_RB_BITMAP_WIDTH_PER_SH  2
+#define CIK_RB_BITMAP_WIDTH_PER_SH     2
+#define HAWAII_RB_BITMAP_WIDTH_PER_SH  4
 
 /* DIDT IND registers */
 #define DIDT_SQ_CTRL0                                     0x0
                 * bit 4: write
                 */
 #define                MEMORY_CLIENT_ID_MASK                   (0xff << 12)
+#define                HAWAII_MEMORY_CLIENT_ID_MASK            (0x1ff << 12)
 #define                MEMORY_CLIENT_ID_SHIFT                  12
 #define                MEMORY_CLIENT_RW_MASK                   (1 << 24)
 #define                MEMORY_CLIENT_RW_SHIFT                  24
 #              define  ADDR_SURF_P8_32x32_16x16                12
 #              define  ADDR_SURF_P8_32x32_16x32                13
 #              define  ADDR_SURF_P8_32x64_32x32                14
+#              define  ADDR_SURF_P16_32x32_8x16                16
+#              define  ADDR_SURF_P16_32x32_16x16               17
 #       define TILE_SPLIT(x)                                   ((x) << 11)
 #              define  ADDR_SURF_TILE_SPLIT_64B                0
 #              define  ADDR_SURF_TILE_SPLIT_128B               1
 #       define RASTER_CONFIG_RB_MAP_1                   1
 #       define RASTER_CONFIG_RB_MAP_2                   2
 #       define RASTER_CONFIG_RB_MAP_3                   3
+#define                PKR_MAP(x)                              ((x) << 8)
 
 #define VGT_EVENT_INITIATOR                             0x28a90
 #       define SAMPLE_STREAMOUTSTATS1                   (1 << 0)
index 5929056..009f46e 100644 (file)
@@ -241,20 +241,30 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)
 
        for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
                u32 value = 0;
+               u8 stereo_freqs = 0;
+               int max_channels = -1;
                int j;
 
                for (j = 0; j < sad_count; j++) {
                        struct cea_sad *sad = &sads[j];
 
                        if (sad->format == eld_reg_to_type[i][1]) {
-                               value = MAX_CHANNELS(sad->channels) |
-                                       DESCRIPTOR_BYTE_2(sad->byte2) |
-                                       SUPPORTED_FREQUENCIES(sad->freq);
+                               if (sad->channels > max_channels) {
+                                       value = MAX_CHANNELS(sad->channels) |
+                                               DESCRIPTOR_BYTE_2(sad->byte2) |
+                                               SUPPORTED_FREQUENCIES(sad->freq);
+                                       max_channels = sad->channels;
+                               }
+
                                if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
-                                       value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq);
-                               break;
+                                       stereo_freqs |= sad->freq;
+                               else
+                                       break;
                        }
                }
+
+               value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
+
                WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);
        }
 
index 7a84d0c..52f1ae1 100644 (file)
@@ -3187,7 +3187,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
                rdev->config.evergreen.sx_max_export_size = 256;
                rdev->config.evergreen.sx_max_export_pos_size = 64;
                rdev->config.evergreen.sx_max_export_smx_size = 192;
-               rdev->config.evergreen.max_hw_contexts = 8;
+               rdev->config.evergreen.max_hw_contexts = 4;
                rdev->config.evergreen.sq_num_cf_insts = 2;
 
                rdev->config.evergreen.sc_prim_fifo_size = 0x40;
index 6787365..aa695c4 100644 (file)
@@ -181,20 +181,30 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)
 
        for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
                u32 value = 0;
+               u8 stereo_freqs = 0;
+               int max_channels = -1;
                int j;
 
                for (j = 0; j < sad_count; j++) {
                        struct cea_sad *sad = &sads[j];
 
                        if (sad->format == eld_reg_to_type[i][1]) {
-                               value = MAX_CHANNELS(sad->channels) |
-                                       DESCRIPTOR_BYTE_2(sad->byte2) |
-                                       SUPPORTED_FREQUENCIES(sad->freq);
+                               if (sad->channels > max_channels) {
+                                       value = MAX_CHANNELS(sad->channels) |
+                                               DESCRIPTOR_BYTE_2(sad->byte2) |
+                                               SUPPORTED_FREQUENCIES(sad->freq);
+                                       max_channels = sad->channels;
+                               }
+
                                if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
-                                       value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq);
-                               break;
+                                       stereo_freqs |= sad->freq;
+                               else
+                                       break;
                        }
                }
+
+               value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
+
                WREG32(eld_reg_to_type[i][0], value);
        }
 
@@ -330,8 +340,8 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
        /* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */
 
        WREG32(HDMI_ACR_PACKET_CONTROL + offset,
-              HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */
-              HDMI_ACR_SOURCE); /* select SW CTS value */
+              HDMI_ACR_SOURCE | /* select SW CTS value */
+              HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
 
        evergreen_hdmi_update_ACR(encoder, mode->clock);
 
index 11e002a..17f9907 100644 (file)
  * 6. COMMAND [29:22] | BYTE_COUNT [20:0]
  */
 #              define PACKET3_CP_DMA_DST_SEL(x)    ((x) << 20)
-                /* 0 - SRC_ADDR
+                /* 0 - DST_ADDR
                 * 1 - GDS
                 */
 #              define PACKET3_CP_DMA_ENGINE(x)     ((x) << 27)
 #              define PACKET3_CP_DMA_CP_SYNC       (1 << 31)
 /* COMMAND */
 #              define PACKET3_CP_DMA_DIS_WC        (1 << 21)
-#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23)
+#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 22)
                 /* 0 - none
                 * 1 - 8 in 16
                 * 2 - 8 in 32
index 7139906..b419055 100644 (file)
@@ -2635,7 +2635,7 @@ int kv_dpm_init(struct radeon_device *rdev)
        pi->caps_sclk_ds = true;
        pi->enable_auto_thermal_throttling = true;
        pi->disable_nb_ps3_in_battery = false;
-       pi->bapm_enable = true;
+       pi->bapm_enable = false;
        pi->voltage_drop_t = 0;
        pi->caps_sclk_throttle_low_notification = false;
        pi->caps_fps = false; /* true? */
index e299a38..11aab2a 100644 (file)
@@ -799,6 +799,7 @@ int ni_init_microcode(struct radeon_device *rdev)
                               fw_name);
                        release_firmware(rdev->smc_fw);
                        rdev->smc_fw = NULL;
+                       err = 0;
                } else if (rdev->smc_fw->size != smc_req_size) {
                        printk(KERN_ERR
                               "ni_mc: Bogus length %zu in firmware \"%s\"\n",
index af922e2..4e609e8 100644 (file)
@@ -2355,6 +2355,7 @@ int r600_init_microcode(struct radeon_device *rdev)
                               fw_name);
                        release_firmware(rdev->smc_fw);
                        rdev->smc_fw = NULL;
+                       err = 0;
                } else if (rdev->smc_fw->size != smc_req_size) {
                        printk(KERN_ERR
                               "smc: Bogus length %zu in firmware \"%s\"\n",
index 21f2b74..4b89262 100644 (file)
@@ -24,6 +24,7 @@
  * Authors: Christian König
  */
 #include <linux/hdmi.h>
+#include <linux/gcd.h>
 #include <drm/drmP.h>
 #include <drm/radeon_drm.h>
 #include "radeon.h"
@@ -57,28 +58,57 @@ enum r600_hdmi_iec_status_bits {
 static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
     /*      32kHz        44.1kHz       48kHz    */
     /* Clock      N     CTS      N     CTS      N     CTS */
-    {  25174,  4576,  28125,  7007,  31250,  6864,  28125 }, /*  25,20/1.001 MHz */
+    {  25175,  4096,  25175, 28224, 125875,  6144,  25175 }, /*  25,20/1.001 MHz */
     {  25200,  4096,  25200,  6272,  28000,  6144,  25200 }, /*  25.20       MHz */
     {  27000,  4096,  27000,  6272,  30000,  6144,  27000 }, /*  27.00       MHz */
     {  27027,  4096,  27027,  6272,  30030,  6144,  27027 }, /*  27.00*1.001 MHz */
     {  54000,  4096,  54000,  6272,  60000,  6144,  54000 }, /*  54.00       MHz */
     {  54054,  4096,  54054,  6272,  60060,  6144,  54054 }, /*  54.00*1.001 MHz */
-    {  74175, 11648, 210937, 17836, 234375, 11648, 140625 }, /*  74.25/1.001 MHz */
+    {  74176,  4096,  74176,  5733,  75335,  6144,  74176 }, /*  74.25/1.001 MHz */
     {  74250,  4096,  74250,  6272,  82500,  6144,  74250 }, /*  74.25       MHz */
-    { 148351, 11648, 421875,  8918, 234375,  5824, 140625 }, /* 148.50/1.001 MHz */
+    { 148352,  4096, 148352,  5733, 150670,  6144, 148352 }, /* 148.50/1.001 MHz */
     { 148500,  4096, 148500,  6272, 165000,  6144, 148500 }, /* 148.50       MHz */
-    {      0,  4096,      0,  6272,      0,  6144,      0 }  /* Other */
 };
 
+
 /*
- * calculate CTS value if it's not found in the table
+ * calculate CTS and N values if they are not found in the table
  */
-static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int N, int freq)
+static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int *N, int freq)
 {
-       if (*CTS == 0)
-               *CTS = clock * N / (128 * freq) * 1000;
-       DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n",
-                 N, *CTS, freq);
+       int n, cts;
+       unsigned long div, mul;
+
+       /* Safe, but overly large values */
+       n = 128 * freq;
+       cts = clock * 1000;
+
+       /* Smallest valid fraction */
+       div = gcd(n, cts);
+
+       n /= div;
+       cts /= div;
+
+       /*
+        * The optimal N is 128*freq/1000. Calculate the closest larger
+        * value that doesn't truncate any bits.
+        */
+       mul = ((128*freq/1000) + (n-1))/n;
+
+       n *= mul;
+       cts *= mul;
+
+       /* Check that we are in spec (not always possible) */
+       if (n < (128*freq/1500))
+               printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n");
+       if (n > (128*freq/300))
+               printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n");
+
+       *N = n;
+       *CTS = cts;
+
+       DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
+                 *N, *CTS, freq);
 }
 
 struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)
@@ -86,15 +116,16 @@ struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)
        struct radeon_hdmi_acr res;
        u8 i;
 
-       for (i = 0; r600_hdmi_predefined_acr[i].clock != clock &&
-            r600_hdmi_predefined_acr[i].clock != 0; i++)
-               ;
-       res = r600_hdmi_predefined_acr[i];
+       /* Precalculated values for common clocks */
+       for (i = 0; i < ARRAY_SIZE(r600_hdmi_predefined_acr); i++) {
+               if (r600_hdmi_predefined_acr[i].clock == clock)
+                       return r600_hdmi_predefined_acr[i];
+       }
 
-       /* In case some CTS are missing */
-       r600_hdmi_calc_cts(clock, &res.cts_32khz, res.n_32khz, 32000);
-       r600_hdmi_calc_cts(clock, &res.cts_44_1khz, res.n_44_1khz, 44100);
-       r600_hdmi_calc_cts(clock, &res.cts_48khz, res.n_48khz, 48000);
+       /* And odd clocks get manually calculated */
+       r600_hdmi_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
+       r600_hdmi_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
+       r600_hdmi_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
 
        return res;
 }
@@ -302,6 +333,9 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
        u8 *sadb;
        int sad_count;
 
+       /* XXX: setting this register causes hangs on some asics */
+       return;
+
        list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
                if (connector->encoder == encoder) {
                        radeon_connector = to_radeon_connector(connector);
@@ -378,20 +412,30 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
 
        for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
                u32 value = 0;
+               u8 stereo_freqs = 0;
+               int max_channels = -1;
                int j;
 
                for (j = 0; j < sad_count; j++) {
                        struct cea_sad *sad = &sads[j];
 
                        if (sad->format == eld_reg_to_type[i][1]) {
-                               value = MAX_CHANNELS(sad->channels) |
-                                       DESCRIPTOR_BYTE_2(sad->byte2) |
-                                       SUPPORTED_FREQUENCIES(sad->freq);
+                               if (sad->channels > max_channels) {
+                                       value = MAX_CHANNELS(sad->channels) |
+                                               DESCRIPTOR_BYTE_2(sad->byte2) |
+                                               SUPPORTED_FREQUENCIES(sad->freq);
+                                       max_channels = sad->channels;
+                               }
+
                                if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
-                                       value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq);
-                               break;
+                                       stereo_freqs |= sad->freq;
+                               else
+                                       break;
                        }
                }
+
+               value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
+
                WREG32(eld_reg_to_type[i][0], value);
        }
 
@@ -448,8 +492,8 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
        }
 
        WREG32(HDMI0_ACR_PACKET_CONTROL + offset,
-              HDMI0_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */
-              HDMI0_ACR_SOURCE); /* select SW CTS value */
+              HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
+              HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
 
        WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
               HDMI0_NULL_SEND | /* send null packets when required */
index 8e01b12..ebe3872 100644 (file)
  */
 #              define PACKET3_CP_DMA_CP_SYNC       (1 << 31)
 /* COMMAND */
-#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23)
+#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 22)
                 /* 0 - none
                 * 1 - 8 in 16
                 * 2 - 8 in 32
index b264af6..b9ee992 100644 (file)
@@ -1281,8 +1281,8 @@ struct radeon_blacklist_clocks
 struct radeon_clock_and_voltage_limits {
        u32 sclk;
        u32 mclk;
-       u32 vddc;
-       u32 vddci;
+       u16 vddc;
+       u16 vddci;
 };
 
 struct radeon_clock_array {
index d4b9167..50853c0 100644 (file)
@@ -2437,27 +2437,48 @@ int radeon_asic_init(struct radeon_device *rdev)
                }
                break;
        case CHIP_BONAIRE:
+       case CHIP_HAWAII:
                rdev->asic = &ci_asic;
                rdev->num_crtc = 6;
                rdev->has_uvd = true;
-               rdev->cg_flags =
-                       RADEON_CG_SUPPORT_GFX_MGCG |
-                       RADEON_CG_SUPPORT_GFX_MGLS |
-                       /*RADEON_CG_SUPPORT_GFX_CGCG |*/
-                       RADEON_CG_SUPPORT_GFX_CGLS |
-                       RADEON_CG_SUPPORT_GFX_CGTS |
-                       RADEON_CG_SUPPORT_GFX_CGTS_LS |
-                       RADEON_CG_SUPPORT_GFX_CP_LS |
-                       RADEON_CG_SUPPORT_MC_LS |
-                       RADEON_CG_SUPPORT_MC_MGCG |
-                       RADEON_CG_SUPPORT_SDMA_MGCG |
-                       RADEON_CG_SUPPORT_SDMA_LS |
-                       RADEON_CG_SUPPORT_BIF_LS |
-                       RADEON_CG_SUPPORT_VCE_MGCG |
-                       RADEON_CG_SUPPORT_UVD_MGCG |
-                       RADEON_CG_SUPPORT_HDP_LS |
-                       RADEON_CG_SUPPORT_HDP_MGCG;
-               rdev->pg_flags = 0;
+               if (rdev->family == CHIP_BONAIRE) {
+                       rdev->cg_flags =
+                               RADEON_CG_SUPPORT_GFX_MGCG |
+                               RADEON_CG_SUPPORT_GFX_MGLS |
+                               /*RADEON_CG_SUPPORT_GFX_CGCG |*/
+                               RADEON_CG_SUPPORT_GFX_CGLS |
+                               RADEON_CG_SUPPORT_GFX_CGTS |
+                               RADEON_CG_SUPPORT_GFX_CGTS_LS |
+                               RADEON_CG_SUPPORT_GFX_CP_LS |
+                               RADEON_CG_SUPPORT_MC_LS |
+                               RADEON_CG_SUPPORT_MC_MGCG |
+                               RADEON_CG_SUPPORT_SDMA_MGCG |
+                               RADEON_CG_SUPPORT_SDMA_LS |
+                               RADEON_CG_SUPPORT_BIF_LS |
+                               RADEON_CG_SUPPORT_VCE_MGCG |
+                               RADEON_CG_SUPPORT_UVD_MGCG |
+                               RADEON_CG_SUPPORT_HDP_LS |
+                               RADEON_CG_SUPPORT_HDP_MGCG;
+                       rdev->pg_flags = 0;
+               } else {
+                       rdev->cg_flags =
+                               RADEON_CG_SUPPORT_GFX_MGCG |
+                               RADEON_CG_SUPPORT_GFX_MGLS |
+                               /*RADEON_CG_SUPPORT_GFX_CGCG |*/
+                               RADEON_CG_SUPPORT_GFX_CGLS |
+                               RADEON_CG_SUPPORT_GFX_CGTS |
+                               RADEON_CG_SUPPORT_GFX_CP_LS |
+                               RADEON_CG_SUPPORT_MC_LS |
+                               RADEON_CG_SUPPORT_MC_MGCG |
+                               RADEON_CG_SUPPORT_SDMA_MGCG |
+                               RADEON_CG_SUPPORT_SDMA_LS |
+                               RADEON_CG_SUPPORT_BIF_LS |
+                               RADEON_CG_SUPPORT_VCE_MGCG |
+                               RADEON_CG_SUPPORT_UVD_MGCG |
+                               RADEON_CG_SUPPORT_HDP_LS |
+                               RADEON_CG_SUPPORT_HDP_MGCG;
+                       rdev->pg_flags = 0;
+               }
                break;
        case CHIP_KAVERI:
        case CHIP_KABINI:
index e972143..20a768a 100644 (file)
@@ -1720,12 +1720,16 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_object_attach_property(&radeon_connector->base.base,
                                                      rdev->mode_info.underscan_vborder_property,
                                                      0);
-                       drm_object_attach_property(&radeon_connector->base.base,
-                                                  rdev->mode_info.audio_property,
-                                                  RADEON_AUDIO_AUTO);
+
                        drm_object_attach_property(&radeon_connector->base.base,
                                                   rdev->mode_info.dither_property,
                                                   RADEON_FMT_DITHER_DISABLE);
+
+                       if (radeon_audio != 0)
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.audio_property,
+                                                          RADEON_AUDIO_AUTO);
+
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
@@ -1819,10 +1823,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
                        }
-                       if (ASIC_IS_DCE2(rdev)) {
+                       if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
                                drm_object_attach_property(&radeon_connector->base.base,
-                                                             rdev->mode_info.audio_property,
-                                                             RADEON_AUDIO_AUTO);
+                                                          rdev->mode_info.audio_property,
+                                                          RADEON_AUDIO_AUTO);
                        }
                        if (ASIC_IS_AVIVO(rdev)) {
                                drm_object_attach_property(&radeon_connector->base.base,
@@ -1869,10 +1873,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
                        }
-                       if (ASIC_IS_DCE2(rdev)) {
+                       if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
                                drm_object_attach_property(&radeon_connector->base.base,
-                                                             rdev->mode_info.audio_property,
-                                                             RADEON_AUDIO_AUTO);
+                                                          rdev->mode_info.audio_property,
+                                                          RADEON_AUDIO_AUTO);
                        }
                        if (ASIC_IS_AVIVO(rdev)) {
                                drm_object_attach_property(&radeon_connector->base.base,
@@ -1918,15 +1922,16 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
                        }
-                       if (ASIC_IS_DCE2(rdev)) {
+                       if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
                                drm_object_attach_property(&radeon_connector->base.base,
-                                                             rdev->mode_info.audio_property,
-                                                             RADEON_AUDIO_AUTO);
+                                                          rdev->mode_info.audio_property,
+                                                          RADEON_AUDIO_AUTO);
                        }
                        if (ASIC_IS_AVIVO(rdev)) {
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.dither_property,
                                                           RADEON_FMT_DITHER_DISABLE);
+
                        }
                        connector->interlace_allowed = true;
                        /* in theory with a DP to VGA converter... */
index c8ab019..26ca223 100644 (file)
@@ -85,9 +85,8 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                   VRAM, also but everything into VRAM on AGP cards to avoid
                   image corruptions */
                if (p->ring == R600_RING_TYPE_UVD_INDEX &&
-                   p->rdev->family < CHIP_PALM &&
                    (i == 0 || drm_pci_device_is_agp(p->rdev->ddev))) {
-
+                       /* TODO: is this still needed for NI+ ? */
                        p->relocs[i].lobj.domain =
                                RADEON_GEM_DOMAIN_VRAM;
 
index 61dbdd9..b9234c4 100644 (file)
@@ -98,6 +98,7 @@ static const char radeon_family_name[][16] = {
        "BONAIRE",
        "KAVERI",
        "KABINI",
+       "HAWAII",
        "LAST",
 };
 
index aab2417..1aee322 100644 (file)
@@ -156,7 +156,7 @@ int radeon_benchmarking = 0;
 int radeon_testing = 0;
 int radeon_connector_table = 0;
 int radeon_tv = 1;
-int radeon_audio = 1;
+int radeon_audio = -1;
 int radeon_disp_priority = 0;
 int radeon_hw_i2c = 0;
 int radeon_pcie_gen2 = -1;
@@ -200,7 +200,7 @@ module_param_named(connector_table, radeon_connector_table, int, 0444);
 MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
 module_param_named(tv, radeon_tv, int, 0444);
 
-MODULE_PARM_DESC(audio, "Audio enable (1 = enable)");
+MODULE_PARM_DESC(audio, "Audio enable (-1 = auto, 0 = disable, 1 = enable)");
 module_param_named(audio, radeon_audio, int, 0444);
 
 MODULE_PARM_DESC(disp_priority, "Display Priority (0 = auto, 1 = normal, 2 = high)");
index 3c82890..614ad54 100644 (file)
@@ -96,6 +96,7 @@ enum radeon_family {
        CHIP_BONAIRE,
        CHIP_KAVERI,
        CHIP_KABINI,
+       CHIP_HAWAII,
        CHIP_LAST,
 };
 
index 7cb178a..0c7b8c6 100644 (file)
@@ -1056,6 +1056,26 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)
        }
 }
 
+static void radeon_crtc_disable(struct drm_crtc *crtc)
+{
+       radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+       if (crtc->fb) {
+               int r;
+               struct radeon_framebuffer *radeon_fb;
+               struct radeon_bo *rbo;
+
+               radeon_fb = to_radeon_framebuffer(crtc->fb);
+               rbo = gem_to_radeon_bo(radeon_fb->obj);
+               r = radeon_bo_reserve(rbo, false);
+               if (unlikely(r))
+                       DRM_ERROR("failed to reserve rbo before unpin\n");
+               else {
+                       radeon_bo_unpin(rbo);
+                       radeon_bo_unreserve(rbo);
+               }
+       }
+}
+
 static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
        .dpms = radeon_crtc_dpms,
        .mode_fixup = radeon_crtc_mode_fixup,
@@ -1065,6 +1085,7 @@ static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
        .prepare = radeon_crtc_prepare,
        .commit = radeon_crtc_commit,
        .load_lut = radeon_crtc_load_lut,
+       .disable = radeon_crtc_disable
 };
 
 
index 981fd06..866ace0 100644 (file)
@@ -954,6 +954,8 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
                if (enable) {
                        mutex_lock(&rdev->pm.mutex);
                        rdev->pm.dpm.uvd_active = true;
+                       /* disable this for now */
+#if 0
                        if ((rdev->pm.dpm.sd == 1) && (rdev->pm.dpm.hd == 0))
                                dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_SD;
                        else if ((rdev->pm.dpm.sd == 2) && (rdev->pm.dpm.hd == 0))
@@ -963,6 +965,7 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
                        else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 2))
                                dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD2;
                        else
+#endif
                                dpm_state = POWER_STATE_TYPE_INTERNAL_UVD;
                        rdev->pm.dpm.state = dpm_state;
                        mutex_unlock(&rdev->pm.mutex);
@@ -1253,6 +1256,7 @@ int radeon_pm_init(struct radeon_device *rdev)
        case CHIP_BONAIRE:
        case CHIP_KABINI:
        case CHIP_KAVERI:
+       case CHIP_HAWAII:
                /* DPM requires the RLC, RV770+ dGPU requires SMC */
                if (!rdev->rlc_fw)
                        rdev->pm.pm_method = PM_METHOD_PROFILE;
index f4d6bce..12e8099 100644 (file)
@@ -36,8 +36,8 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
        struct radeon_bo *vram_obj = NULL;
        struct radeon_bo **gtt_obj = NULL;
        uint64_t gtt_addr, vram_addr;
-       unsigned i, n, size;
-       int r, ring;
+       unsigned n, size;
+       int i, r, ring;
 
        switch (flag) {
        case RADEON_TEST_COPY_DMA:
index 3385836..a77cd27 100644 (file)
@@ -59,6 +59,7 @@
 #define SI_MC_UCODE_SIZE             7769
 #define OLAND_MC_UCODE_SIZE          7863
 #define CIK_MC_UCODE_SIZE            7866
+#define HAWAII_MC_UCODE_SIZE         7933
 
 /* SDMA */
 #define CIK_SDMA_UCODE_SIZE          1050
 #define BONAIRE_SMC_UCODE_START      0x20000
 #define BONAIRE_SMC_UCODE_SIZE       0x1FDEC
 
+#define HAWAII_SMC_UCODE_START       0x20000
+#define HAWAII_SMC_UCODE_SIZE        0x1FDEC
+
 #endif
index 234b2a3..373d088 100644 (file)
@@ -97,6 +97,7 @@ int radeon_uvd_init(struct radeon_device *rdev)
        case CHIP_BONAIRE:
        case CHIP_KABINI:
        case CHIP_KAVERI:
+       case CHIP_HAWAII:
                fw_name = FIRMWARE_BONAIRE;
                break;
 
@@ -478,7 +479,8 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
                return -EINVAL;
        }
 
-       if (p->rdev->family < CHIP_PALM && (cmd == 0 || cmd == 0x3) &&
+       /* TODO: is this still necessary on NI+ ? */
+       if ((cmd == 0 || cmd == 0x3) &&
            (start >> 28) != (p->rdev->uvd.gpu_addr >> 28)) {
                DRM_ERROR("msg/fb buffer %LX-%LX out of 256MB segment!\n",
                          start, end);
@@ -800,7 +802,8 @@ void radeon_uvd_note_usage(struct radeon_device *rdev)
                    (rdev->pm.dpm.hd != hd)) {
                        rdev->pm.dpm.sd = sd;
                        rdev->pm.dpm.hd = hd;
-                       streams_changed = true;
+                       /* disable this for now */
+                       /*streams_changed = true;*/
                }
        }
 
index 1447d79..1c56062 100644 (file)
@@ -345,9 +345,11 @@ static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
                if (max_bandwidth.full > rdev->pm.sideport_bandwidth.full &&
                        rdev->pm.sideport_bandwidth.full)
                        max_bandwidth = rdev->pm.sideport_bandwidth;
-               read_delay_latency.full = dfixed_const(370 * 800 * 1000);
-               read_delay_latency.full = dfixed_div(read_delay_latency,
-                       rdev->pm.igp_sideport_mclk);
+               read_delay_latency.full = dfixed_const(370 * 800);
+               a.full = dfixed_const(1000);
+               b.full = dfixed_div(rdev->pm.igp_sideport_mclk, a);
+               read_delay_latency.full = dfixed_div(read_delay_latency, b);
+               read_delay_latency.full = dfixed_mul(read_delay_latency, a);
        } else {
                if (max_bandwidth.full > rdev->pm.k8_bandwidth.full &&
                        rdev->pm.k8_bandwidth.full)
@@ -488,14 +490,10 @@ static void rs690_compute_mode_priority(struct radeon_device *rdev,
                }
                if (wm0->priority_mark.full > priority_mark02.full)
                        priority_mark02.full = wm0->priority_mark.full;
-               if (dfixed_trunc(priority_mark02) < 0)
-                       priority_mark02.full = 0;
                if (wm0->priority_mark_max.full > priority_mark02.full)
                        priority_mark02.full = wm0->priority_mark_max.full;
                if (wm1->priority_mark.full > priority_mark12.full)
                        priority_mark12.full = wm1->priority_mark.full;
-               if (dfixed_trunc(priority_mark12) < 0)
-                       priority_mark12.full = 0;
                if (wm1->priority_mark_max.full > priority_mark12.full)
                        priority_mark12.full = wm1->priority_mark_max.full;
                *d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
@@ -526,8 +524,6 @@ static void rs690_compute_mode_priority(struct radeon_device *rdev,
                }
                if (wm0->priority_mark.full > priority_mark02.full)
                        priority_mark02.full = wm0->priority_mark.full;
-               if (dfixed_trunc(priority_mark02) < 0)
-                       priority_mark02.full = 0;
                if (wm0->priority_mark_max.full > priority_mark02.full)
                        priority_mark02.full = wm0->priority_mark_max.full;
                *d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
@@ -555,8 +551,6 @@ static void rs690_compute_mode_priority(struct radeon_device *rdev,
                }
                if (wm1->priority_mark.full > priority_mark12.full)
                        priority_mark12.full = wm1->priority_mark.full;
-               if (dfixed_trunc(priority_mark12) < 0)
-                       priority_mark12.full = 0;
                if (wm1->priority_mark_max.full > priority_mark12.full)
                        priority_mark12.full = wm1->priority_mark_max.full;
                *d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
index 873eb4b..5d1c316 100644 (file)
@@ -1155,14 +1155,10 @@ static void rv515_compute_mode_priority(struct radeon_device *rdev,
                }
                if (wm0->priority_mark.full > priority_mark02.full)
                        priority_mark02.full = wm0->priority_mark.full;
-               if (dfixed_trunc(priority_mark02) < 0)
-                       priority_mark02.full = 0;
                if (wm0->priority_mark_max.full > priority_mark02.full)
                        priority_mark02.full = wm0->priority_mark_max.full;
                if (wm1->priority_mark.full > priority_mark12.full)
                        priority_mark12.full = wm1->priority_mark.full;
-               if (dfixed_trunc(priority_mark12) < 0)
-                       priority_mark12.full = 0;
                if (wm1->priority_mark_max.full > priority_mark12.full)
                        priority_mark12.full = wm1->priority_mark_max.full;
                *d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
@@ -1193,8 +1189,6 @@ static void rv515_compute_mode_priority(struct radeon_device *rdev,
                }
                if (wm0->priority_mark.full > priority_mark02.full)
                        priority_mark02.full = wm0->priority_mark.full;
-               if (dfixed_trunc(priority_mark02) < 0)
-                       priority_mark02.full = 0;
                if (wm0->priority_mark_max.full > priority_mark02.full)
                        priority_mark02.full = wm0->priority_mark_max.full;
                *d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
@@ -1222,8 +1216,6 @@ static void rv515_compute_mode_priority(struct radeon_device *rdev,
                }
                if (wm1->priority_mark.full > priority_mark12.full)
                        priority_mark12.full = wm1->priority_mark.full;
-               if (dfixed_trunc(priority_mark12) < 0)
-                       priority_mark12.full = 0;
                if (wm1->priority_mark_max.full > priority_mark12.full)
                        priority_mark12.full = wm1->priority_mark_max.full;
                *d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
index 2acfe56..6a64cca 100644 (file)
@@ -80,6 +80,9 @@ extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev);
 extern bool evergreen_is_display_hung(struct radeon_device *rdev);
 static void si_enable_gui_idle_interrupt(struct radeon_device *rdev,
                                         bool enable);
+static void si_fini_pg(struct radeon_device *rdev);
+static void si_fini_cg(struct radeon_device *rdev);
+static void si_rlc_stop(struct radeon_device *rdev);
 
 static const u32 verde_rlc_save_restore_register_list[] =
 {
@@ -1673,6 +1676,7 @@ static int si_init_microcode(struct radeon_device *rdev)
                       fw_name);
                release_firmware(rdev->smc_fw);
                rdev->smc_fw = NULL;
+               err = 0;
        } else if (rdev->smc_fw->size != smc_req_size) {
                printk(KERN_ERR
                       "si_smc: Bogus length %zu in firmware \"%s\"\n",
@@ -3603,6 +3607,13 @@ static void si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
        dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
                 RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
 
+       /* disable PG/CG */
+       si_fini_pg(rdev);
+       si_fini_cg(rdev);
+
+       /* stop the rlc */
+       si_rlc_stop(rdev);
+
        /* Disable CP parsing/prefetching */
        WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
 
index a24ada4..0b00c79 100644 (file)
@@ -5213,7 +5213,7 @@ static int si_set_mc_special_registers(struct radeon_device *rdev,
                                        table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
                        }
                        j++;
-                       if (j > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                       if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
                                return -EINVAL;
 
                        if (!pi->mem_gddr5) {
@@ -5223,7 +5223,7 @@ static int si_set_mc_special_registers(struct radeon_device *rdev,
                                        table->mc_reg_table_entry[k].mc_data[j] =
                                                (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
                                j++;
-                               if (j > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                               if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
                                        return -EINVAL;
                        }
                        break;
@@ -5236,7 +5236,7 @@ static int si_set_mc_special_registers(struct radeon_device *rdev,
                                        (temp_reg & 0xffff0000) |
                                        (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
                        j++;
-                       if (j > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                       if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
                                return -EINVAL;
                        break;
                default:
index 5691a7c..b322acc 100644 (file)
  * 6. COMMAND [30:21] | BYTE_COUNT [20:0]
  */
 #              define PACKET3_CP_DMA_DST_SEL(x)    ((x) << 20)
-                /* 0 - SRC_ADDR
+                /* 0 - DST_ADDR
                 * 1 - GDS
                 */
 #              define PACKET3_CP_DMA_ENGINE(x)     ((x) << 27)
 #              define PACKET3_CP_DMA_CP_SYNC       (1 << 31)
 /* COMMAND */
 #              define PACKET3_CP_DMA_DIS_WC        (1 << 21)
-#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23)
+#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 22)
                 /* 0 - none
                 * 1 - 8 in 16
                 * 2 - 8 in 32
index 7f998bf..9364129 100644 (file)
@@ -1868,7 +1868,7 @@ int trinity_dpm_init(struct radeon_device *rdev)
        for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
                pi->at[i] = TRINITY_AT_DFLT;
 
-       pi->enable_bapm = true;
+       pi->enable_bapm = false;
        pi->enable_nbps_policy = true;
        pi->enable_sclk_ds = true;
        pi->enable_gfx_power_gating = true;
index 3100fa9..7266805 100644 (file)
@@ -212,8 +212,8 @@ int uvd_v1_0_start(struct radeon_device *rdev)
        /* enable VCPU clock */
        WREG32(UVD_VCPU_CNTL,  1 << 9);
 
-       /* enable UMC and NC0 */
-       WREG32_P(UVD_LMI_CTRL2, 1 << 13, ~((1 << 8) | (1 << 13)));
+       /* enable UMC */
+       WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
 
        /* boot up the VCPU */
        WREG32(UVD_SOFT_RESET, 0);
index 54bad98..562f9a4 100644 (file)
@@ -40,7 +40,7 @@
 static void shmob_drm_clk_on(struct shmob_drm_device *sdev)
 {
        if (sdev->clock)
-               clk_enable(sdev->clock);
+               clk_prepare_enable(sdev->clock);
 #if 0
        if (sdev->meram_dev && sdev->meram_dev->pdev)
                pm_runtime_get_sync(&sdev->meram_dev->pdev->dev);
@@ -54,7 +54,7 @@ static void shmob_drm_clk_off(struct shmob_drm_device *sdev)
                pm_runtime_put_sync(&sdev->meram_dev->pdev->dev);
 #endif
        if (sdev->clock)
-               clk_disable(sdev->clock);
+               clk_disable_unprepare(sdev->clock);
 }
 
 /* -----------------------------------------------------------------------------
index b2b33dd..b433b9f 100644 (file)
@@ -5,10 +5,6 @@ ccflags-y := -Iinclude/drm
 ttm-y := ttm_agp_backend.o ttm_memory.o ttm_tt.o ttm_bo.o \
        ttm_bo_util.o ttm_bo_vm.o ttm_module.o \
        ttm_object.o ttm_lock.o ttm_execbuf_util.o ttm_page_alloc.o \
-       ttm_bo_manager.o
-
-ifeq ($(CONFIG_SWIOTLB),y)
-ttm-y += ttm_page_alloc_dma.o
-endif
+       ttm_bo_manager.o ttm_page_alloc_dma.o
 
 obj-$(CONFIG_DRM_TTM) += ttm.o
index 7957bee..fb8259f 100644 (file)
@@ -33,6 +33,7 @@
  *   when freed).
  */
 
+#if defined(CONFIG_SWIOTLB) || defined(CONFIG_INTEL_IOMMU)
 #define pr_fmt(fmt) "[TTM] " fmt
 
 #include <linux/dma-mapping.h>
@@ -1142,3 +1143,5 @@ int ttm_dma_page_alloc_debugfs(struct seq_file *m, void *data)
        return 0;
 }
 EXPORT_SYMBOL_GPL(ttm_dma_page_alloc_debugfs);
+
+#endif
index 96dc84d..7776e6f 100644 (file)
@@ -141,37 +141,374 @@ struct ttm_placement vmw_srf_placement = {
 };
 
 struct vmw_ttm_tt {
-       struct ttm_tt ttm;
+       struct ttm_dma_tt dma_ttm;
        struct vmw_private *dev_priv;
        int gmr_id;
+       struct sg_table sgt;
+       struct vmw_sg_table vsgt;
+       uint64_t sg_alloc_size;
+       bool mapped;
 };
 
+/**
+ * Helper functions to advance a struct vmw_piter iterator.
+ *
+ * @viter: Pointer to the iterator.
+ *
+ * These functions return false if past the end of the list,
+ * true otherwise. Functions are selected depending on the current
+ * DMA mapping mode.
+ */
+static bool __vmw_piter_non_sg_next(struct vmw_piter *viter)
+{
+       return ++(viter->i) < viter->num_pages;
+}
+
+static bool __vmw_piter_sg_next(struct vmw_piter *viter)
+{
+       return __sg_page_iter_next(&viter->iter);
+}
+
+
+/**
+ * Helper functions to return a pointer to the current page.
+ *
+ * @viter: Pointer to the iterator
+ *
+ * These functions return a pointer to the page currently
+ * pointed to by @viter. Functions are selected depending on the
+ * current mapping mode.
+ */
+static struct page *__vmw_piter_non_sg_page(struct vmw_piter *viter)
+{
+       return viter->pages[viter->i];
+}
+
+static struct page *__vmw_piter_sg_page(struct vmw_piter *viter)
+{
+       return sg_page_iter_page(&viter->iter);
+}
+
+
+/**
+ * Helper functions to return the DMA address of the current page.
+ *
+ * @viter: Pointer to the iterator
+ *
+ * These functions return the DMA address of the page currently
+ * pointed to by @viter. Functions are selected depending on the
+ * current mapping mode.
+ */
+static dma_addr_t __vmw_piter_phys_addr(struct vmw_piter *viter)
+{
+       return page_to_phys(viter->pages[viter->i]);
+}
+
+static dma_addr_t __vmw_piter_dma_addr(struct vmw_piter *viter)
+{
+       return viter->addrs[viter->i];
+}
+
+static dma_addr_t __vmw_piter_sg_addr(struct vmw_piter *viter)
+{
+       return sg_page_iter_dma_address(&viter->iter);
+}
+
+
+/**
+ * vmw_piter_start - Initialize a struct vmw_piter.
+ *
+ * @viter: Pointer to the iterator to initialize
+ * @vsgt: Pointer to a struct vmw_sg_table to initialize from
+ *
+ * Note that we're following the convention of __sg_page_iter_start, so that
+ * the iterator doesn't point to a valid page after initialization; it has
+ * to be advanced one step first.
+ */
+void vmw_piter_start(struct vmw_piter *viter, const struct vmw_sg_table *vsgt,
+                    unsigned long p_offset)
+{
+       viter->i = p_offset - 1;
+       viter->num_pages = vsgt->num_pages;
+       switch (vsgt->mode) {
+       case vmw_dma_phys:
+               viter->next = &__vmw_piter_non_sg_next;
+               viter->dma_address = &__vmw_piter_phys_addr;
+               viter->page = &__vmw_piter_non_sg_page;
+               viter->pages = vsgt->pages;
+               break;
+       case vmw_dma_alloc_coherent:
+               viter->next = &__vmw_piter_non_sg_next;
+               viter->dma_address = &__vmw_piter_dma_addr;
+               viter->page = &__vmw_piter_non_sg_page;
+               viter->addrs = vsgt->addrs;
+               break;
+       case vmw_dma_map_populate:
+       case vmw_dma_map_bind:
+               viter->next = &__vmw_piter_sg_next;
+               viter->dma_address = &__vmw_piter_sg_addr;
+               viter->page = &__vmw_piter_sg_page;
+               __sg_page_iter_start(&viter->iter, vsgt->sgt->sgl,
+                                    vsgt->sgt->orig_nents, p_offset);
+               break;
+       default:
+               BUG();
+       }
+}
+
+/**
+ * vmw_ttm_unmap_from_dma - unmap  device addresses previsouly mapped for
+ * TTM pages
+ *
+ * @vmw_tt: Pointer to a struct vmw_ttm_backend
+ *
+ * Used to free dma mappings previously mapped by vmw_ttm_map_for_dma.
+ */
+static void vmw_ttm_unmap_from_dma(struct vmw_ttm_tt *vmw_tt)
+{
+       struct device *dev = vmw_tt->dev_priv->dev->dev;
+
+       dma_unmap_sg(dev, vmw_tt->sgt.sgl, vmw_tt->sgt.nents,
+               DMA_BIDIRECTIONAL);
+       vmw_tt->sgt.nents = vmw_tt->sgt.orig_nents;
+}
+
+/**
+ * vmw_ttm_map_for_dma - map TTM pages to get device addresses
+ *
+ * @vmw_tt: Pointer to a struct vmw_ttm_backend
+ *
+ * This function is used to get device addresses from the kernel DMA layer.
+ * However, it's violating the DMA API in that when this operation has been
+ * performed, it's illegal for the CPU to write to the pages without first
+ * unmapping the DMA mappings, or calling dma_sync_sg_for_cpu(). It is
+ * therefore only legal to call this function if we know that the function
+ * dma_sync_sg_for_cpu() is a NOP, and dma_sync_sg_for_device() is at most
+ * a CPU write buffer flush.
+ */
+static int vmw_ttm_map_for_dma(struct vmw_ttm_tt *vmw_tt)
+{
+       struct device *dev = vmw_tt->dev_priv->dev->dev;
+       int ret;
+
+       ret = dma_map_sg(dev, vmw_tt->sgt.sgl, vmw_tt->sgt.orig_nents,
+                        DMA_BIDIRECTIONAL);
+       if (unlikely(ret == 0))
+               return -ENOMEM;
+
+       vmw_tt->sgt.nents = ret;
+
+       return 0;
+}
+
+/**
+ * vmw_ttm_map_dma - Make sure TTM pages are visible to the device
+ *
+ * @vmw_tt: Pointer to a struct vmw_ttm_tt
+ *
+ * Select the correct function for and make sure the TTM pages are
+ * visible to the device. Allocate storage for the device mappings.
+ * If a mapping has already been performed, indicated by the storage
+ * pointer being non NULL, the function returns success.
+ */
+static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt)
+{
+       struct vmw_private *dev_priv = vmw_tt->dev_priv;
+       struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
+       struct vmw_sg_table *vsgt = &vmw_tt->vsgt;
+       struct vmw_piter iter;
+       dma_addr_t old;
+       int ret = 0;
+       static size_t sgl_size;
+       static size_t sgt_size;
+
+       if (vmw_tt->mapped)
+               return 0;
+
+       vsgt->mode = dev_priv->map_mode;
+       vsgt->pages = vmw_tt->dma_ttm.ttm.pages;
+       vsgt->num_pages = vmw_tt->dma_ttm.ttm.num_pages;
+       vsgt->addrs = vmw_tt->dma_ttm.dma_address;
+       vsgt->sgt = &vmw_tt->sgt;
+
+       switch (dev_priv->map_mode) {
+       case vmw_dma_map_bind:
+       case vmw_dma_map_populate:
+               if (unlikely(!sgl_size)) {
+                       sgl_size = ttm_round_pot(sizeof(struct scatterlist));
+                       sgt_size = ttm_round_pot(sizeof(struct sg_table));
+               }
+               vmw_tt->sg_alloc_size = sgt_size + sgl_size * vsgt->num_pages;
+               ret = ttm_mem_global_alloc(glob, vmw_tt->sg_alloc_size, false,
+                                          true);
+               if (unlikely(ret != 0))
+                       return ret;
+
+               ret = sg_alloc_table_from_pages(&vmw_tt->sgt, vsgt->pages,
+                                               vsgt->num_pages, 0,
+                                               (unsigned long)
+                                               vsgt->num_pages << PAGE_SHIFT,
+                                               GFP_KERNEL);
+               if (unlikely(ret != 0))
+                       goto out_sg_alloc_fail;
+
+               if (vsgt->num_pages > vmw_tt->sgt.nents) {
+                       uint64_t over_alloc =
+                               sgl_size * (vsgt->num_pages -
+                                           vmw_tt->sgt.nents);
+
+                       ttm_mem_global_free(glob, over_alloc);
+                       vmw_tt->sg_alloc_size -= over_alloc;
+               }
+
+               ret = vmw_ttm_map_for_dma(vmw_tt);
+               if (unlikely(ret != 0))
+                       goto out_map_fail;
+
+               break;
+       default:
+               break;
+       }
+
+       old = ~((dma_addr_t) 0);
+       vmw_tt->vsgt.num_regions = 0;
+       for (vmw_piter_start(&iter, vsgt, 0); vmw_piter_next(&iter);) {
+               dma_addr_t cur = vmw_piter_dma_addr(&iter);
+
+               if (cur != old + PAGE_SIZE)
+                       vmw_tt->vsgt.num_regions++;
+               old = cur;
+       }
+
+       vmw_tt->mapped = true;
+       return 0;
+
+out_map_fail:
+       sg_free_table(vmw_tt->vsgt.sgt);
+       vmw_tt->vsgt.sgt = NULL;
+out_sg_alloc_fail:
+       ttm_mem_global_free(glob, vmw_tt->sg_alloc_size);
+       return ret;
+}
+
+/**
+ * vmw_ttm_unmap_dma - Tear down any TTM page device mappings
+ *
+ * @vmw_tt: Pointer to a struct vmw_ttm_tt
+ *
+ * Tear down any previously set up device DMA mappings and free
+ * any storage space allocated for them. If there are no mappings set up,
+ * this function is a NOP.
+ */
+static void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt)
+{
+       struct vmw_private *dev_priv = vmw_tt->dev_priv;
+
+       if (!vmw_tt->vsgt.sgt)
+               return;
+
+       switch (dev_priv->map_mode) {
+       case vmw_dma_map_bind:
+       case vmw_dma_map_populate:
+               vmw_ttm_unmap_from_dma(vmw_tt);
+               sg_free_table(vmw_tt->vsgt.sgt);
+               vmw_tt->vsgt.sgt = NULL;
+               ttm_mem_global_free(vmw_mem_glob(dev_priv),
+                                   vmw_tt->sg_alloc_size);
+               break;
+       default:
+               break;
+       }
+       vmw_tt->mapped = false;
+}
+
 static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
 {
-       struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, ttm);
+       struct vmw_ttm_tt *vmw_be =
+               container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
+       int ret;
+
+       ret = vmw_ttm_map_dma(vmw_be);
+       if (unlikely(ret != 0))
+               return ret;
 
        vmw_be->gmr_id = bo_mem->start;
 
-       return vmw_gmr_bind(vmw_be->dev_priv, ttm->pages,
+       return vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt,
                            ttm->num_pages, vmw_be->gmr_id);
 }
 
 static int vmw_ttm_unbind(struct ttm_tt *ttm)
 {
-       struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, ttm);
+       struct vmw_ttm_tt *vmw_be =
+               container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
 
        vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
+
+       if (vmw_be->dev_priv->map_mode == vmw_dma_map_bind)
+               vmw_ttm_unmap_dma(vmw_be);
+
        return 0;
 }
 
 static void vmw_ttm_destroy(struct ttm_tt *ttm)
 {
-       struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, ttm);
-
-       ttm_tt_fini(ttm);
+       struct vmw_ttm_tt *vmw_be =
+               container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
+
+       vmw_ttm_unmap_dma(vmw_be);
+       if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent)
+               ttm_dma_tt_fini(&vmw_be->dma_ttm);
+       else
+               ttm_tt_fini(ttm);
        kfree(vmw_be);
 }
 
+static int vmw_ttm_populate(struct ttm_tt *ttm)
+{
+       struct vmw_ttm_tt *vmw_tt =
+               container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
+       struct vmw_private *dev_priv = vmw_tt->dev_priv;
+       struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
+       int ret;
+
+       if (ttm->state != tt_unpopulated)
+               return 0;
+
+       if (dev_priv->map_mode == vmw_dma_alloc_coherent) {
+               size_t size =
+                       ttm_round_pot(ttm->num_pages * sizeof(dma_addr_t));
+               ret = ttm_mem_global_alloc(glob, size, false, true);
+               if (unlikely(ret != 0))
+                       return ret;
+
+               ret = ttm_dma_populate(&vmw_tt->dma_ttm, dev_priv->dev->dev);
+               if (unlikely(ret != 0))
+                       ttm_mem_global_free(glob, size);
+       } else
+               ret = ttm_pool_populate(ttm);
+
+       return ret;
+}
+
+static void vmw_ttm_unpopulate(struct ttm_tt *ttm)
+{
+       struct vmw_ttm_tt *vmw_tt = container_of(ttm, struct vmw_ttm_tt,
+                                                dma_ttm.ttm);
+       struct vmw_private *dev_priv = vmw_tt->dev_priv;
+       struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
+
+       vmw_ttm_unmap_dma(vmw_tt);
+       if (dev_priv->map_mode == vmw_dma_alloc_coherent) {
+               size_t size =
+                       ttm_round_pot(ttm->num_pages * sizeof(dma_addr_t));
+
+               ttm_dma_unpopulate(&vmw_tt->dma_ttm, dev_priv->dev->dev);
+               ttm_mem_global_free(glob, size);
+       } else
+               ttm_pool_unpopulate(ttm);
+}
+
 static struct ttm_backend_func vmw_ttm_func = {
        .bind = vmw_ttm_bind,
        .unbind = vmw_ttm_unbind,
@@ -183,20 +520,28 @@ struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev,
                                 struct page *dummy_read_page)
 {
        struct vmw_ttm_tt *vmw_be;
+       int ret;
 
-       vmw_be = kmalloc(sizeof(*vmw_be), GFP_KERNEL);
+       vmw_be = kzalloc(sizeof(*vmw_be), GFP_KERNEL);
        if (!vmw_be)
                return NULL;
 
-       vmw_be->ttm.func = &vmw_ttm_func;
+       vmw_be->dma_ttm.ttm.func = &vmw_ttm_func;
        vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev);
 
-       if (ttm_tt_init(&vmw_be->ttm, bdev, size, page_flags, dummy_read_page)) {
-               kfree(vmw_be);
-               return NULL;
-       }
-
-       return &vmw_be->ttm;
+       if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent)
+               ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bdev, size, page_flags,
+                                     dummy_read_page);
+       else
+               ret = ttm_tt_init(&vmw_be->dma_ttm.ttm, bdev, size, page_flags,
+                                 dummy_read_page);
+       if (unlikely(ret != 0))
+               goto out_no_init;
+
+       return &vmw_be->dma_ttm.ttm;
+out_no_init:
+       kfree(vmw_be);
+       return NULL;
 }
 
 int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
@@ -332,8 +677,8 @@ static int vmw_sync_obj_wait(void *sync_obj, bool lazy, bool interruptible)
 
 struct ttm_bo_driver vmw_bo_driver = {
        .ttm_tt_create = &vmw_ttm_tt_create,
-       .ttm_tt_populate = &ttm_pool_populate,
-       .ttm_tt_unpopulate = &ttm_pool_unpopulate,
+       .ttm_tt_populate = &vmw_ttm_populate,
+       .ttm_tt_unpopulate = &vmw_ttm_unpopulate,
        .invalidate_caches = vmw_invalidate_caches,
        .init_mem_type = vmw_init_mem_type,
        .evict_flags = vmw_evict_flags,
index 1a90f0a..20d5485 100644 (file)
@@ -32,6 +32,7 @@
 #include <drm/ttm/ttm_bo_driver.h>
 #include <drm/ttm/ttm_object.h>
 #include <drm/ttm/ttm_module.h>
+#include <linux/dma_remapping.h>
 
 #define VMWGFX_DRIVER_NAME "vmwgfx"
 #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices"
@@ -185,6 +186,9 @@ static struct pci_device_id vmw_pci_id_list[] = {
 MODULE_DEVICE_TABLE(pci, vmw_pci_id_list);
 
 static int enable_fbdev = IS_ENABLED(CONFIG_DRM_VMWGFX_FBCON);
+static int vmw_force_iommu;
+static int vmw_restrict_iommu;
+static int vmw_force_coherent;
 
 static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
 static void vmw_master_init(struct vmw_master *);
@@ -193,6 +197,13 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
 
 MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev");
 module_param_named(enable_fbdev, enable_fbdev, int, 0600);
+MODULE_PARM_DESC(force_dma_api, "Force using the DMA API for TTM pages");
+module_param_named(force_dma_api, vmw_force_iommu, int, 0600);
+MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages");
+module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600);
+MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages");
+module_param_named(force_coherent, vmw_force_coherent, int, 0600);
+
 
 static void vmw_print_capabilities(uint32_t capabilities)
 {
@@ -427,12 +438,85 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv)
        dev_priv->initial_height = height;
 }
 
+/**
+ * vmw_dma_select_mode - Determine how DMA mappings should be set up for this
+ * system.
+ *
+ * @dev_priv: Pointer to a struct vmw_private
+ *
+ * This functions tries to determine the IOMMU setup and what actions
+ * need to be taken by the driver to make system pages visible to the
+ * device.
+ * If this function decides that DMA is not possible, it returns -EINVAL.
+ * The driver may then try to disable features of the device that require
+ * DMA.
+ */
+static int vmw_dma_select_mode(struct vmw_private *dev_priv)
+{
+       static const char *names[vmw_dma_map_max] = {
+               [vmw_dma_phys] = "Using physical TTM page addresses.",
+               [vmw_dma_alloc_coherent] = "Using coherent TTM pages.",
+               [vmw_dma_map_populate] = "Keeping DMA mappings.",
+               [vmw_dma_map_bind] = "Giving up DMA mappings early."};
+#ifdef CONFIG_X86
+       const struct dma_map_ops *dma_ops = get_dma_ops(dev_priv->dev->dev);
+
+#ifdef CONFIG_INTEL_IOMMU
+       if (intel_iommu_enabled) {
+               dev_priv->map_mode = vmw_dma_map_populate;
+               goto out_fixup;
+       }
+#endif
+
+       if (!(vmw_force_iommu || vmw_force_coherent)) {
+               dev_priv->map_mode = vmw_dma_phys;
+               DRM_INFO("DMA map mode: %s\n", names[dev_priv->map_mode]);
+               return 0;
+       }
+
+       dev_priv->map_mode = vmw_dma_map_populate;
+
+       if (dma_ops->sync_single_for_cpu)
+               dev_priv->map_mode = vmw_dma_alloc_coherent;
+#ifdef CONFIG_SWIOTLB
+       if (swiotlb_nr_tbl() == 0)
+               dev_priv->map_mode = vmw_dma_map_populate;
+#endif
+
+#ifdef CONFIG_INTEL_IOMMU
+out_fixup:
+#endif
+       if (dev_priv->map_mode == vmw_dma_map_populate &&
+           vmw_restrict_iommu)
+               dev_priv->map_mode = vmw_dma_map_bind;
+
+       if (vmw_force_coherent)
+               dev_priv->map_mode = vmw_dma_alloc_coherent;
+
+#if !defined(CONFIG_SWIOTLB) && !defined(CONFIG_INTEL_IOMMU)
+       /*
+        * No coherent page pool
+        */
+       if (dev_priv->map_mode == vmw_dma_alloc_coherent)
+               return -EINVAL;
+#endif
+
+#else /* CONFIG_X86 */
+       dev_priv->map_mode = vmw_dma_map_populate;
+#endif /* CONFIG_X86 */
+
+       DRM_INFO("DMA map mode: %s\n", names[dev_priv->map_mode]);
+
+       return 0;
+}
+
 static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 {
        struct vmw_private *dev_priv;
        int ret;
        uint32_t svga_id;
        enum vmw_res_type i;
+       bool refuse_dma = false;
 
        dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
        if (unlikely(dev_priv == NULL)) {
@@ -481,6 +565,11 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        }
 
        dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES);
+       ret = vmw_dma_select_mode(dev_priv);
+       if (unlikely(ret != 0)) {
+               DRM_INFO("Restricting capabilities due to IOMMU setup.\n");
+               refuse_dma = true;
+       }
 
        dev_priv->vram_size = vmw_read(dev_priv, SVGA_REG_VRAM_SIZE);
        dev_priv->mmio_size = vmw_read(dev_priv, SVGA_REG_MEM_SIZE);
@@ -558,8 +647,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        }
 
        dev_priv->has_gmr = true;
-       if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
-                          dev_priv->max_gmr_ids) != 0) {
+       if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) ||
+           refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
+                                        dev_priv->max_gmr_ids) != 0) {
                DRM_INFO("No GMR memory available. "
                         "Graphics memory resources are very limited.\n");
                dev_priv->has_gmr = false;
@@ -740,9 +830,17 @@ static void vmw_postclose(struct drm_device *dev,
        struct vmw_fpriv *vmw_fp;
 
        vmw_fp = vmw_fpriv(file_priv);
-       ttm_object_file_release(&vmw_fp->tfile);
-       if (vmw_fp->locked_master)
+
+       if (vmw_fp->locked_master) {
+               struct vmw_master *vmaster =
+                       vmw_master(vmw_fp->locked_master);
+
+               ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
+               ttm_vt_unlock(&vmaster->lock);
                drm_master_put(&vmw_fp->locked_master);
+       }
+
+       ttm_object_file_release(&vmw_fp->tfile);
        kfree(vmw_fp);
 }
 
@@ -925,14 +1023,13 @@ static void vmw_master_drop(struct drm_device *dev,
 
        vmw_fp->locked_master = drm_master_get(file_priv->master);
        ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
-       vmw_execbuf_release_pinned_bo(dev_priv);
-
        if (unlikely((ret != 0))) {
                DRM_ERROR("Unable to lock TTM at VT switch.\n");
                drm_master_put(&vmw_fp->locked_master);
        }
 
-       ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
+       ttm_lock_set_kill(&vmaster->lock, false, SIGTERM);
+       vmw_execbuf_release_pinned_bo(dev_priv);
 
        if (!dev_priv->enable_fb) {
                ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM);
index 150ec64..e401d5d 100644 (file)
@@ -177,6 +177,58 @@ struct vmw_res_cache_entry {
        struct vmw_resource_val_node *node;
 };
 
+/**
+ * enum vmw_dma_map_mode - indicate how to perform TTM page dma mappings.
+ */
+enum vmw_dma_map_mode {
+       vmw_dma_phys,           /* Use physical page addresses */
+       vmw_dma_alloc_coherent, /* Use TTM coherent pages */
+       vmw_dma_map_populate,   /* Unmap from DMA just after unpopulate */
+       vmw_dma_map_bind,       /* Unmap from DMA just before unbind */
+       vmw_dma_map_max
+};
+
+/**
+ * struct vmw_sg_table - Scatter/gather table for binding, with additional
+ * device-specific information.
+ *
+ * @sgt: Pointer to a struct sg_table with binding information
+ * @num_regions: Number of regions with device-address contigous pages
+ */
+struct vmw_sg_table {
+       enum vmw_dma_map_mode mode;
+       struct page **pages;
+       const dma_addr_t *addrs;
+       struct sg_table *sgt;
+       unsigned long num_regions;
+       unsigned long num_pages;
+};
+
+/**
+ * struct vmw_piter - Page iterator that iterates over a list of pages
+ * and DMA addresses that could be either a scatter-gather list or
+ * arrays
+ *
+ * @pages: Array of page pointers to the pages.
+ * @addrs: DMA addresses to the pages if coherent pages are used.
+ * @iter: Scatter-gather page iterator. Current position in SG list.
+ * @i: Current position in arrays.
+ * @num_pages: Number of pages total.
+ * @next: Function to advance the iterator. Returns false if past the list
+ * of pages, true otherwise.
+ * @dma_address: Function to return the DMA address of the current page.
+ */
+struct vmw_piter {
+       struct page **pages;
+       const dma_addr_t *addrs;
+       struct sg_page_iter iter;
+       unsigned long i;
+       unsigned long num_pages;
+       bool (*next)(struct vmw_piter *);
+       dma_addr_t (*dma_address)(struct vmw_piter *);
+       struct page *(*page)(struct vmw_piter *);
+};
+
 struct vmw_sw_context{
        struct drm_open_hash res_ht;
        bool res_ht_initialized;
@@ -358,6 +410,11 @@ struct vmw_private {
 
        struct list_head res_lru[vmw_res_max];
        uint32_t used_memory_size;
+
+       /*
+        * DMA mapping stuff.
+        */
+       enum vmw_dma_map_mode map_mode;
 };
 
 static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res)
@@ -405,7 +462,7 @@ void vmw_3d_resource_dec(struct vmw_private *dev_priv, bool hide_svga);
  */
 
 extern int vmw_gmr_bind(struct vmw_private *dev_priv,
-                       struct page *pages[],
+                       const struct vmw_sg_table *vsgt,
                        unsigned long num_pages,
                        int gmr_id);
 extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);
@@ -568,6 +625,45 @@ extern struct ttm_placement vmw_evictable_placement;
 extern struct ttm_placement vmw_srf_placement;
 extern struct ttm_bo_driver vmw_bo_driver;
 extern int vmw_dma_quiescent(struct drm_device *dev);
+extern void vmw_piter_start(struct vmw_piter *viter,
+                           const struct vmw_sg_table *vsgt,
+                           unsigned long p_offs);
+
+/**
+ * vmw_piter_next - Advance the iterator one page.
+ *
+ * @viter: Pointer to the iterator to advance.
+ *
+ * Returns false if past the list of pages, true otherwise.
+ */
+static inline bool vmw_piter_next(struct vmw_piter *viter)
+{
+       return viter->next(viter);
+}
+
+/**
+ * vmw_piter_dma_addr - Return the DMA address of the current page.
+ *
+ * @viter: Pointer to the iterator
+ *
+ * Returns the DMA address of the page pointed to by @viter.
+ */
+static inline dma_addr_t vmw_piter_dma_addr(struct vmw_piter *viter)
+{
+       return viter->dma_address(viter);
+}
+
+/**
+ * vmw_piter_page - Return a pointer to the current page.
+ *
+ * @viter: Pointer to the iterator
+ *
+ * Returns the DMA address of the page pointed to by @viter.
+ */
+static inline struct page *vmw_piter_page(struct vmw_piter *viter)
+{
+       return viter->page(viter);
+}
 
 /**
  * Command submission - vmwgfx_execbuf.c
index 1a0bf07..6ef0b03 100644 (file)
 #define VMW_PPN_SIZE (sizeof(unsigned long))
 /* A future safe maximum remap size. */
 #define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE)
+#define DMA_ADDR_INVALID ((dma_addr_t) 0)
+#define DMA_PAGE_INVALID 0UL
 
 static int vmw_gmr2_bind(struct vmw_private *dev_priv,
-                        struct page *pages[],
+                        struct vmw_piter *iter,
                         unsigned long num_pages,
                         int gmr_id)
 {
@@ -81,11 +83,13 @@ static int vmw_gmr2_bind(struct vmw_private *dev_priv,
 
                for (i = 0; i < nr; ++i) {
                        if (VMW_PPN_SIZE <= 4)
-                               *cmd = page_to_pfn(*pages++);
+                               *cmd = vmw_piter_dma_addr(iter) >> PAGE_SHIFT;
                        else
-                               *((uint64_t *)cmd) = page_to_pfn(*pages++);
+                               *((uint64_t *)cmd) = vmw_piter_dma_addr(iter) >>
+                                       PAGE_SHIFT;
 
                        cmd += VMW_PPN_SIZE / sizeof(*cmd);
+                       vmw_piter_next(iter);
                }
 
                num_pages -= nr;
@@ -120,22 +124,56 @@ static void vmw_gmr2_unbind(struct vmw_private *dev_priv,
        vmw_fifo_commit(dev_priv, define_size);
 }
 
+
+static void vmw_gmr_free_descriptors(struct device *dev, dma_addr_t desc_dma,
+                                    struct list_head *desc_pages)
+{
+       struct page *page, *next;
+       struct svga_guest_mem_descriptor *page_virtual;
+       unsigned int desc_per_page = PAGE_SIZE /
+               sizeof(struct svga_guest_mem_descriptor) - 1;
+
+       if (list_empty(desc_pages))
+               return;
+
+       list_for_each_entry_safe(page, next, desc_pages, lru) {
+               list_del_init(&page->lru);
+
+               if (likely(desc_dma != DMA_ADDR_INVALID)) {
+                       dma_unmap_page(dev, desc_dma, PAGE_SIZE,
+                                      DMA_TO_DEVICE);
+               }
+
+               page_virtual = kmap_atomic(page);
+               desc_dma = (dma_addr_t)
+                       le32_to_cpu(page_virtual[desc_per_page].ppn) <<
+                       PAGE_SHIFT;
+               kunmap_atomic(page_virtual);
+
+               __free_page(page);
+       }
+}
+
 /**
  * FIXME: Adjust to the ttm lowmem / highmem storage to minimize
  * the number of used descriptors.
+ *
  */
 
-static int vmw_gmr_build_descriptors(struct list_head *desc_pages,
-                                    struct page *pages[],
-                                    unsigned long num_pages)
+static int vmw_gmr_build_descriptors(struct device *dev,
+                                    struct list_head *desc_pages,
+                                    struct vmw_piter *iter,
+                                    unsigned long num_pages,
+                                    dma_addr_t *first_dma)
 {
-       struct page *page, *next;
+       struct page *page;
        struct svga_guest_mem_descriptor *page_virtual = NULL;
        struct svga_guest_mem_descriptor *desc_virtual = NULL;
        unsigned int desc_per_page;
        unsigned long prev_pfn;
        unsigned long pfn;
        int ret;
+       dma_addr_t desc_dma;
 
        desc_per_page = PAGE_SIZE /
            sizeof(struct svga_guest_mem_descriptor) - 1;
@@ -148,23 +186,12 @@ static int vmw_gmr_build_descriptors(struct list_head *desc_pages,
                }
 
                list_add_tail(&page->lru, desc_pages);
-
-               /*
-                * Point previous page terminating descriptor to this
-                * page before unmapping it.
-                */
-
-               if (likely(page_virtual != NULL)) {
-                       desc_virtual->ppn = page_to_pfn(page);
-                       kunmap_atomic(page_virtual);
-               }
-
                page_virtual = kmap_atomic(page);
                desc_virtual = page_virtual - 1;
                prev_pfn = ~(0UL);
 
                while (likely(num_pages != 0)) {
-                       pfn = page_to_pfn(*pages);
+                       pfn = vmw_piter_dma_addr(iter) >> PAGE_SHIFT;
 
                        if (pfn != prev_pfn + 1) {
 
@@ -181,104 +208,82 @@ static int vmw_gmr_build_descriptors(struct list_head *desc_pages,
                        }
                        prev_pfn = pfn;
                        --num_pages;
-                       ++pages;
+                       vmw_piter_next(iter);
                }
 
-               (++desc_virtual)->ppn = cpu_to_le32(0);
+               (++desc_virtual)->ppn = DMA_PAGE_INVALID;
                desc_virtual->num_pages = cpu_to_le32(0);
+               kunmap_atomic(page_virtual);
        }
 
-       if (likely(page_virtual != NULL))
+       desc_dma = 0;
+       list_for_each_entry_reverse(page, desc_pages, lru) {
+               page_virtual = kmap_atomic(page);
+               page_virtual[desc_per_page].ppn = cpu_to_le32
+                       (desc_dma >> PAGE_SHIFT);
                kunmap_atomic(page_virtual);
+               desc_dma = dma_map_page(dev, page, 0, PAGE_SIZE,
+                                       DMA_TO_DEVICE);
+
+               if (unlikely(dma_mapping_error(dev, desc_dma)))
+                       goto out_err;
+       }
+       *first_dma = desc_dma;
 
        return 0;
 out_err:
-       list_for_each_entry_safe(page, next, desc_pages, lru) {
-               list_del_init(&page->lru);
-               __free_page(page);
-       }
+       vmw_gmr_free_descriptors(dev, DMA_ADDR_INVALID, desc_pages);
        return ret;
 }
 
-static inline void vmw_gmr_free_descriptors(struct list_head *desc_pages)
-{
-       struct page *page, *next;
-
-       list_for_each_entry_safe(page, next, desc_pages, lru) {
-               list_del_init(&page->lru);
-               __free_page(page);
-       }
-}
-
 static void vmw_gmr_fire_descriptors(struct vmw_private *dev_priv,
-                                    int gmr_id, struct list_head *desc_pages)
+                                    int gmr_id, dma_addr_t desc_dma)
 {
-       struct page *page;
-
-       if (unlikely(list_empty(desc_pages)))
-               return;
-
-       page = list_entry(desc_pages->next, struct page, lru);
-
        mutex_lock(&dev_priv->hw_mutex);
 
        vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id);
        wmb();
-       vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, page_to_pfn(page));
+       vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, desc_dma >> PAGE_SHIFT);
        mb();
 
        mutex_unlock(&dev_priv->hw_mutex);
 
 }
 
-/**
- * FIXME: Adjust to the ttm lowmem / highmem storage to minimize
- * the number of used descriptors.
- */
-
-static unsigned long vmw_gmr_count_descriptors(struct page *pages[],
-                                       unsigned long num_pages)
-{
-       unsigned long prev_pfn = ~(0UL);
-       unsigned long pfn;
-       unsigned long descriptors = 0;
-
-       while (num_pages--) {
-               pfn = page_to_pfn(*pages++);
-               if (prev_pfn + 1 != pfn)
-                       ++descriptors;
-               prev_pfn = pfn;
-       }
-
-       return descriptors;
-}
-
 int vmw_gmr_bind(struct vmw_private *dev_priv,
-                struct page *pages[],
+                const struct vmw_sg_table *vsgt,
                 unsigned long num_pages,
                 int gmr_id)
 {
        struct list_head desc_pages;
+       dma_addr_t desc_dma = 0;
+       struct device *dev = dev_priv->dev->dev;
+       struct vmw_piter data_iter;
        int ret;
 
+       vmw_piter_start(&data_iter, vsgt, 0);
+
+       if (unlikely(!vmw_piter_next(&data_iter)))
+               return 0;
+
        if (likely(dev_priv->capabilities & SVGA_CAP_GMR2))
-               return vmw_gmr2_bind(dev_priv, pages, num_pages, gmr_id);
+               return vmw_gmr2_bind(dev_priv, &data_iter, num_pages, gmr_id);
 
        if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR)))
                return -EINVAL;
 
-       if (vmw_gmr_count_descriptors(pages, num_pages) >
-           dev_priv->max_gmr_descriptors)
+       if (vsgt->num_regions > dev_priv->max_gmr_descriptors)
                return -EINVAL;
 
        INIT_LIST_HEAD(&desc_pages);
 
-       ret = vmw_gmr_build_descriptors(&desc_pages, pages, num_pages);
+       ret = vmw_gmr_build_descriptors(dev, &desc_pages, &data_iter,
+                                       num_pages, &desc_dma);
        if (unlikely(ret != 0))
                return ret;
 
-       vmw_gmr_fire_descriptors(dev_priv, gmr_id, &desc_pages);
-       vmw_gmr_free_descriptors(&desc_pages);
+       vmw_gmr_fire_descriptors(dev_priv, gmr_id, desc_dma);
+       vmw_gmr_free_descriptors(dev, desc_dma, &desc_pages);
 
        return 0;
 }
index 0e67cf4..252501a 100644 (file)
@@ -32,6 +32,8 @@
 #include <drm/drmP.h>
 #include "vmwgfx_resource_priv.h"
 
+#define VMW_RES_EVICT_ERR_COUNT 10
+
 struct vmw_user_dma_buffer {
        struct ttm_base_object base;
        struct vmw_dma_buffer dma;
@@ -970,7 +972,7 @@ void vmw_resource_unreserve(struct vmw_resource *res,
        if (new_backup)
                res->backup_offset = new_backup_offset;
 
-       if (!res->func->may_evict)
+       if (!res->func->may_evict || res->id == -1)
                return;
 
        write_lock(&dev_priv->resource_lock);
@@ -1091,8 +1093,9 @@ vmw_resource_backoff_reservation(struct ww_acquire_ctx *ticket,
  *                         to a backup buffer.
  *
  * @res:            The resource to evict.
+ * @interruptible:  Whether to wait interruptible.
  */
-int vmw_resource_do_evict(struct vmw_resource *res)
+int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible)
 {
        struct ttm_validate_buffer val_buf;
        const struct vmw_res_func *func = res->func;
@@ -1102,7 +1105,8 @@ int vmw_resource_do_evict(struct vmw_resource *res)
        BUG_ON(!func->may_evict);
 
        val_buf.bo = NULL;
-       ret = vmw_resource_check_buffer(res, &ticket, true, &val_buf);
+       ret = vmw_resource_check_buffer(res, &ticket, interruptible,
+                                       &val_buf);
        if (unlikely(ret != 0))
                return ret;
 
@@ -1141,6 +1145,7 @@ int vmw_resource_validate(struct vmw_resource *res)
        struct vmw_private *dev_priv = res->dev_priv;
        struct list_head *lru_list = &dev_priv->res_lru[res->func->res_type];
        struct ttm_validate_buffer val_buf;
+       unsigned err_count = 0;
 
        if (likely(!res->func->may_evict))
                return 0;
@@ -1155,7 +1160,7 @@ int vmw_resource_validate(struct vmw_resource *res)
 
                write_lock(&dev_priv->resource_lock);
                if (list_empty(lru_list) || !res->func->may_evict) {
-                       DRM_ERROR("Out of device device id entries "
+                       DRM_ERROR("Out of device device resources "
                                  "for %s.\n", res->func->type_name);
                        ret = -EBUSY;
                        write_unlock(&dev_priv->resource_lock);
@@ -1168,7 +1173,19 @@ int vmw_resource_validate(struct vmw_resource *res)
                list_del_init(&evict_res->lru_head);
 
                write_unlock(&dev_priv->resource_lock);
-               vmw_resource_do_evict(evict_res);
+
+               ret = vmw_resource_do_evict(evict_res, true);
+               if (unlikely(ret != 0)) {
+                       write_lock(&dev_priv->resource_lock);
+                       list_add_tail(&evict_res->lru_head, lru_list);
+                       write_unlock(&dev_priv->resource_lock);
+                       if (ret == -ERESTARTSYS ||
+                           ++err_count > VMW_RES_EVICT_ERR_COUNT) {
+                               vmw_resource_unreference(&evict_res);
+                               goto out_no_validate;
+                       }
+               }
+
                vmw_resource_unreference(&evict_res);
        } while (1);
 
@@ -1253,13 +1270,15 @@ bool vmw_resource_needs_backup(const struct vmw_resource *res)
  * @type:           The resource type to evict
  *
  * To avoid thrashing starvation or as part of the hibernation sequence,
- * evict all evictable resources of a specific type.
+ * try to evict all evictable resources of a specific type.
  */
 static void vmw_resource_evict_type(struct vmw_private *dev_priv,
                                    enum vmw_res_type type)
 {
        struct list_head *lru_list = &dev_priv->res_lru[type];
        struct vmw_resource *evict_res;
+       unsigned err_count = 0;
+       int ret;
 
        do {
                write_lock(&dev_priv->resource_lock);
@@ -1272,7 +1291,18 @@ static void vmw_resource_evict_type(struct vmw_private *dev_priv,
                                         lru_head));
                list_del_init(&evict_res->lru_head);
                write_unlock(&dev_priv->resource_lock);
-               vmw_resource_do_evict(evict_res);
+
+               ret = vmw_resource_do_evict(evict_res, false);
+               if (unlikely(ret != 0)) {
+                       write_lock(&dev_priv->resource_lock);
+                       list_add_tail(&evict_res->lru_head, lru_list);
+                       write_unlock(&dev_priv->resource_lock);
+                       if (++err_count > VMW_RES_EVICT_ERR_COUNT) {
+                               vmw_resource_unreference(&evict_res);
+                               return;
+                       }
+               }
+
                vmw_resource_unreference(&evict_res);
        } while (1);
 
index 71b70e3..c91d547 100644 (file)
@@ -241,6 +241,7 @@ config HID_HOLTEK
          - Sharkoon Drakonia / Perixx MX-2000 gaming mice
          - Tracer Sniper TRM-503 / NOVA Gaming Slider X200 /
            Zalman ZM-GM1
+         - SHARKOON DarkGlider Gaming mouse
 
 config HOLTEK_FF
        bool "Holtek On Line Grip force feedback support"
index b8470b1..e80da62 100644 (file)
@@ -319,7 +319,7 @@ static s32 item_sdata(struct hid_item *item)
 
 static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 {
-       __u32 raw_value;
+       __s32 raw_value;
        switch (item->tag) {
        case HID_GLOBAL_ITEM_TAG_PUSH:
 
@@ -370,10 +370,11 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
                return 0;
 
        case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-               /* Units exponent negative numbers are given through a
-                * two's complement.
-                * See "6.2.2.7 Global Items" for more information. */
-               raw_value = item_udata(item);
+               /* Many devices provide unit exponent as a two's complement
+                * nibble due to the common misunderstanding of HID
+                * specification 1.11, 6.2.2.7 Global Items. Attempt to handle
+                * both this and the standard encoding. */
+               raw_value = item_sdata(item);
                if (!(raw_value & 0xfffffff0))
                        parser->global.unit_exponent = hid_snto32(raw_value, 4);
                else
@@ -1715,6 +1716,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
        { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
@@ -1869,6 +1871,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO2, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
        { }
 };
index 7e6db3c..e696566 100644 (file)
@@ -27,6 +27,7 @@
  * - USB ID 04d9:a067, sold as Sharkoon Drakonia and Perixx MX-2000
  * - USB ID 04d9:a04a, sold as Tracer Sniper TRM-503, NOVA Gaming Slider X200
  *   and Zalman ZM-GM1
+ * - USB ID 04d9:a081, sold as SHARKOON DarkGlider Gaming mouse
  */
 
 static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
@@ -46,6 +47,7 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                        }
                        break;
                case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A:
+               case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081:
                        if (*rsize >= 113 && rdesc[106] == 0xff && rdesc[107] == 0x7f
                                        && rdesc[111] == 0xff && rdesc[112] == 0x7f) {
                                hid_info(hdev, "Fixing up report descriptor\n");
@@ -63,6 +65,8 @@ static const struct hid_device_id holtek_mouse_devices[] = {
                        USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
                        USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
+                       USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, holtek_mouse_devices);
index e60e8d5..f0296a5 100644 (file)
 #define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD      0xa055
 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067    0xa067
 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A    0xa04a
+#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081    0xa081
 
 #define USB_VENDOR_ID_IMATION          0x0718
 #define USB_DEVICE_ID_DISC_STAKKA      0xd000
 #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN   0x0003
 
 #define USB_VENDOR_ID_NINTENDO         0x057e
+#define USB_VENDOR_ID_NINTENDO2                0x054c
 #define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306
 #define USB_DEVICE_ID_NINTENDO_WIIMOTE2        0x0330
 
 #define USB_DEVICE_ID_SYNAPTICS_COMP_TP        0x0009
 #define USB_DEVICE_ID_SYNAPTICS_WTP    0x0010
 #define USB_DEVICE_ID_SYNAPTICS_DPAD   0x0013
+#define USB_DEVICE_ID_SYNAPTICS_LTS1   0x0af8
+#define USB_DEVICE_ID_SYNAPTICS_LTS2   0x1d10
 
 #define USB_VENDOR_ID_THINGM           0x27b8
 #define USB_DEVICE_ID_BLINK1           0x01ed
 #define USB_VENDOR_ID_PRIMAX   0x0461
 #define USB_DEVICE_ID_PRIMAX_KEYBOARD  0x4e05
 
+#define USB_VENDOR_ID_SIS      0x0457
+#define USB_DEVICE_ID_SIS_TS   0x1013
+
 #endif
index 8741d95..d97f232 100644 (file)
@@ -192,6 +192,7 @@ static int hidinput_setkeycode(struct input_dev *dev,
        return -EINVAL;
 }
 
+
 /**
  * hidinput_calc_abs_res - calculate an absolute axis resolution
  * @field: the HID report field to calculate resolution for
@@ -234,23 +235,17 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
        case ABS_MT_TOOL_Y:
        case ABS_MT_TOUCH_MAJOR:
        case ABS_MT_TOUCH_MINOR:
-               if (field->unit & 0xffffff00)           /* Not a length */
-                       return 0;
-               unit_exponent += hid_snto32(field->unit >> 4, 4) - 1;
-               switch (field->unit & 0xf) {
-               case 0x1:                               /* If centimeters */
+               if (field->unit == 0x11) {              /* If centimeters */
                        /* Convert to millimeters */
                        unit_exponent += 1;
-                       break;
-               case 0x3:                               /* If inches */
+               } else if (field->unit == 0x13) {       /* If inches */
                        /* Convert to millimeters */
                        prev = physical_extents;
                        physical_extents *= 254;
                        if (physical_extents < prev)
                                return 0;
                        unit_exponent -= 1;
-                       break;
-               default:
+               } else {
                        return 0;
                }
                break;
index 602c188..6101816 100644 (file)
@@ -382,7 +382,7 @@ static ssize_t kone_sysfs_write_profilex(struct file *fp,
 }
 #define PROFILE_ATTR(number)                                   \
 static struct bin_attribute bin_attr_profile##number = {       \
-       .attr = { .name = "profile##number", .mode = 0660 },    \
+       .attr = { .name = "profile" #number, .mode = 0660 },    \
        .size = sizeof(struct kone_profile),                    \
        .read = kone_sysfs_read_profilex,                       \
        .write = kone_sysfs_write_profilex,                     \
index 5ddf605..5e99fcd 100644 (file)
@@ -229,13 +229,13 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
 
 #define PROFILE_ATTR(number)                                           \
 static struct bin_attribute bin_attr_profile##number##_settings = {    \
-       .attr = { .name = "profile##number##_settings", .mode = 0440 }, \
+       .attr = { .name = "profile" #number "_settings", .mode = 0440 },        \
        .size = KONEPLUS_SIZE_PROFILE_SETTINGS,                         \
        .read = koneplus_sysfs_read_profilex_settings,                  \
        .private = &profile_numbers[number-1],                          \
 };                                                                     \
 static struct bin_attribute bin_attr_profile##number##_buttons = {     \
-       .attr = { .name = "profile##number##_buttons", .mode = 0440 },  \
+       .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
        .size = KONEPLUS_SIZE_PROFILE_BUTTONS,                          \
        .read = koneplus_sysfs_read_profilex_buttons,                   \
        .private = &profile_numbers[number-1],                          \
index 515bc03..0c8e1ef 100644 (file)
@@ -257,13 +257,13 @@ static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
 
 #define PROFILE_ATTR(number)                                           \
 static struct bin_attribute bin_attr_profile##number##_settings = {    \
-       .attr = { .name = "profile##number##_settings", .mode = 0440 }, \
+       .attr = { .name = "profile" #number "_settings", .mode = 0440 },        \
        .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,                         \
        .read = kovaplus_sysfs_read_profilex_settings,                  \
        .private = &profile_numbers[number-1],                          \
 };                                                                     \
 static struct bin_attribute bin_attr_profile##number##_buttons = {     \
-       .attr = { .name = "profile##number##_buttons", .mode = 0440 },  \
+       .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
        .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,                          \
        .read = kovaplus_sysfs_read_profilex_buttons,                   \
        .private = &profile_numbers[number-1],                          \
index 5a6dbbe..1a07e07 100644 (file)
@@ -225,13 +225,13 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
 
 #define PROFILE_ATTR(number)                                           \
 static struct bin_attribute bin_attr_profile##number##_settings = {    \
-       .attr = { .name = "profile##number##_settings", .mode = 0440 }, \
+       .attr = { .name = "profile" #number "_settings", .mode = 0440 },        \
        .size = PYRA_SIZE_PROFILE_SETTINGS,                             \
        .read = pyra_sysfs_read_profilex_settings,                      \
        .private = &profile_numbers[number-1],                          \
 };                                                                     \
 static struct bin_attribute bin_attr_profile##number##_buttons = {     \
-       .attr = { .name = "profile##number##_buttons", .mode = 0440 },  \
+       .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
        .size = PYRA_SIZE_PROFILE_BUTTONS,                              \
        .read = pyra_sysfs_read_profilex_buttons,                       \
        .private = &profile_numbers[number-1],                          \
index abb20db..1446f52 100644 (file)
@@ -834,7 +834,8 @@ static void wiimote_init_set_type(struct wiimote_data *wdata,
                goto done;
        }
 
-       if (vendor == USB_VENDOR_ID_NINTENDO) {
+       if (vendor == USB_VENDOR_ID_NINTENDO ||
+           vendor == USB_VENDOR_ID_NINTENDO2) {
                if (product == USB_DEVICE_ID_NINTENDO_WIIMOTE) {
                        devtype = WIIMOTE_DEV_GEN10;
                        goto done;
@@ -1855,6 +1856,8 @@ static void wiimote_hid_remove(struct hid_device *hdev)
 static const struct hid_device_id wiimote_hid_devices[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
                                USB_DEVICE_ID_NINTENDO_WIIMOTE) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO2,
+                               USB_DEVICE_ID_NINTENDO_WIIMOTE) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
                                USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
        { }
index 2e7d644..71adf9e 100644 (file)
@@ -119,12 +119,22 @@ static const struct wiimod_ops wiimod_keys = {
  * the rumble motor, this flag shouldn't be set.
  */
 
+/* used by wiimod_rumble and wiipro_rumble */
+static void wiimod_rumble_worker(struct work_struct *work)
+{
+       struct wiimote_data *wdata = container_of(work, struct wiimote_data,
+                                                 rumble_worker);
+
+       spin_lock_irq(&wdata->state.lock);
+       wiiproto_req_rumble(wdata, wdata->state.cache_rumble);
+       spin_unlock_irq(&wdata->state.lock);
+}
+
 static int wiimod_rumble_play(struct input_dev *dev, void *data,
                              struct ff_effect *eff)
 {
        struct wiimote_data *wdata = input_get_drvdata(dev);
        __u8 value;
-       unsigned long flags;
 
        /*
         * The wiimote supports only a single rumble motor so if any magnitude
@@ -137,9 +147,10 @@ static int wiimod_rumble_play(struct input_dev *dev, void *data,
        else
                value = 0;
 
-       spin_lock_irqsave(&wdata->state.lock, flags);
-       wiiproto_req_rumble(wdata, value);
-       spin_unlock_irqrestore(&wdata->state.lock, flags);
+       /* Locking state.lock here might deadlock with input_event() calls.
+        * schedule_work acts as barrier. Merging multiple changes is fine. */
+       wdata->state.cache_rumble = value;
+       schedule_work(&wdata->rumble_worker);
 
        return 0;
 }
@@ -147,6 +158,8 @@ static int wiimod_rumble_play(struct input_dev *dev, void *data,
 static int wiimod_rumble_probe(const struct wiimod_ops *ops,
                               struct wiimote_data *wdata)
 {
+       INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker);
+
        set_bit(FF_RUMBLE, wdata->input->ffbit);
        if (input_ff_create_memless(wdata->input, NULL, wiimod_rumble_play))
                return -ENOMEM;
@@ -159,6 +172,8 @@ static void wiimod_rumble_remove(const struct wiimod_ops *ops,
 {
        unsigned long flags;
 
+       cancel_work_sync(&wdata->rumble_worker);
+
        spin_lock_irqsave(&wdata->state.lock, flags);
        wiiproto_req_rumble(wdata, 0);
        spin_unlock_irqrestore(&wdata->state.lock, flags);
@@ -1731,7 +1746,6 @@ static int wiimod_pro_play(struct input_dev *dev, void *data,
 {
        struct wiimote_data *wdata = input_get_drvdata(dev);
        __u8 value;
-       unsigned long flags;
 
        /*
         * The wiimote supports only a single rumble motor so if any magnitude
@@ -1744,9 +1758,10 @@ static int wiimod_pro_play(struct input_dev *dev, void *data,
        else
                value = 0;
 
-       spin_lock_irqsave(&wdata->state.lock, flags);
-       wiiproto_req_rumble(wdata, value);
-       spin_unlock_irqrestore(&wdata->state.lock, flags);
+       /* Locking state.lock here might deadlock with input_event() calls.
+        * schedule_work acts as barrier. Merging multiple changes is fine. */
+       wdata->state.cache_rumble = value;
+       schedule_work(&wdata->rumble_worker);
 
        return 0;
 }
@@ -1756,6 +1771,8 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
 {
        int ret, i;
 
+       INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker);
+
        wdata->extension.input = input_allocate_device();
        if (!wdata->extension.input)
                return -ENOMEM;
@@ -1817,12 +1834,13 @@ static void wiimod_pro_remove(const struct wiimod_ops *ops,
        if (!wdata->extension.input)
                return;
 
+       input_unregister_device(wdata->extension.input);
+       wdata->extension.input = NULL;
+       cancel_work_sync(&wdata->rumble_worker);
+
        spin_lock_irqsave(&wdata->state.lock, flags);
        wiiproto_req_rumble(wdata, 0);
        spin_unlock_irqrestore(&wdata->state.lock, flags);
-
-       input_unregister_device(wdata->extension.input);
-       wdata->extension.input = NULL;
 }
 
 static const struct wiimod_ops wiimod_pro = {
index f1474f3..75db0c4 100644 (file)
@@ -133,13 +133,15 @@ struct wiimote_state {
        __u8 *cmd_read_buf;
        __u8 cmd_read_size;
 
-       /* calibration data */
+       /* calibration/cache data */
        __u16 calib_bboard[4][3];
+       __u8 cache_rumble;
 };
 
 struct wiimote_data {
        struct hid_device *hdev;
        struct input_dev *input;
+       struct work_struct rumble_worker;
        struct led_classdev *leds[4];
        struct input_dev *accel;
        struct input_dev *ir;
index 8918dd1..6a6dd5c 100644 (file)
@@ -308,18 +308,25 @@ static int hidraw_fasync(int fd, struct file *file, int on)
 static void drop_ref(struct hidraw *hidraw, int exists_bit)
 {
        if (exists_bit) {
-               hid_hw_close(hidraw->hid);
                hidraw->exist = 0;
-               if (hidraw->open)
+               if (hidraw->open) {
+                       hid_hw_close(hidraw->hid);
                        wake_up_interruptible(&hidraw->wait);
+               }
        } else {
                --hidraw->open;
        }
-
-       if (!hidraw->open && !hidraw->exist) {
-               device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
-               hidraw_table[hidraw->minor] = NULL;
-               kfree(hidraw);
+       if (!hidraw->open) {
+               if (!hidraw->exist) {
+                       device_destroy(hidraw_class,
+                                       MKDEV(hidraw_major, hidraw->minor));
+                       hidraw_table[hidraw->minor] = NULL;
+                       kfree(hidraw);
+               } else {
+                       /* close device for last reader */
+                       hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
+                       hid_hw_close(hidraw->hid);
+               }
        }
 }
 
index 5bf2fb7..93b00d7 100644 (file)
@@ -615,7 +615,7 @@ static const struct file_operations uhid_fops = {
 
 static struct miscdevice uhid_misc = {
        .fops           = &uhid_fops,
-       .minor          = MISC_DYNAMIC_MINOR,
+       .minor          = UHID_MINOR,
        .name           = UHID_NAME,
 };
 
@@ -634,4 +634,5 @@ module_exit(uhid_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
 MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
+MODULE_ALIAS_MISCDEV(UHID_MINOR);
 MODULE_ALIAS("devname:" UHID_NAME);
index 0734552..3fca3be 100644 (file)
@@ -110,6 +110,9 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_SIS, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
 
        { 0, 0 }
 };
index 98814d1..3288f13 100644 (file)
@@ -230,6 +230,7 @@ static int send_argument(const char *key)
 
 static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
 {
+       u8 status, data = 0;
        int i;
 
        if (send_command(cmd) || send_argument(key)) {
@@ -237,6 +238,7 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
                return -EIO;
        }
 
+       /* This has no effect on newer (2012) SMCs */
        if (send_byte(len, APPLESMC_DATA_PORT)) {
                pr_warn("%.4s: read len fail\n", key);
                return -EIO;
@@ -250,6 +252,17 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
                buffer[i] = inb(APPLESMC_DATA_PORT);
        }
 
+       /* Read the data port until bit0 is cleared */
+       for (i = 0; i < 16; i++) {
+               udelay(APPLESMC_MIN_WAIT);
+               status = inb(APPLESMC_CMD_PORT);
+               if (!(status & 0x01))
+                       break;
+               data = inb(APPLESMC_DATA_PORT);
+       }
+       if (i)
+               pr_warn("flushed %d bytes, last value is: %d\n", i, data);
+
        return 0;
 }
 
index 4c1b605..0aa0113 100644 (file)
@@ -270,7 +270,8 @@ static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume);
 MODULE_ALIAS("platform:i2c_designware");
 
 static struct platform_driver dw_i2c_driver = {
-       .remove         = dw_i2c_remove,
+       .probe = dw_i2c_probe,
+       .remove = dw_i2c_remove,
        .driver         = {
                .name   = "i2c_designware",
                .owner  = THIS_MODULE,
@@ -282,7 +283,7 @@ static struct platform_driver dw_i2c_driver = {
 
 static int __init dw_i2c_init_driver(void)
 {
-       return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
+       return platform_driver_register(&dw_i2c_driver);
 }
 subsys_initcall(dw_i2c_init_driver);
 
index ccf4665..1d7efa3 100644 (file)
@@ -365,7 +365,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
        clk_disable_unprepare(i2c_imx->clk);
 }
 
-static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
+static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
                                                        unsigned int rate)
 {
        struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div;
@@ -589,7 +589,7 @@ static struct i2c_algorithm i2c_imx_algo = {
        .functionality  = i2c_imx_func,
 };
 
-static int __init i2c_imx_probe(struct platform_device *pdev)
+static int i2c_imx_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id = of_match_device(i2c_imx_dt_ids,
                                                           &pdev->dev);
@@ -697,7 +697,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
        return 0;   /* Return OK */
 }
 
-static int __exit i2c_imx_remove(struct platform_device *pdev)
+static int i2c_imx_remove(struct platform_device *pdev)
 {
        struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
 
@@ -715,7 +715,8 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver i2c_imx_driver = {
-       .remove         = __exit_p(i2c_imx_remove),
+       .probe = i2c_imx_probe,
+       .remove = i2c_imx_remove,
        .driver = {
                .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,
@@ -726,7 +727,7 @@ static struct platform_driver i2c_imx_driver = {
 
 static int __init i2c_adap_imx_init(void)
 {
-       return platform_driver_probe(&i2c_imx_driver, i2c_imx_probe);
+       return platform_driver_register(&i2c_imx_driver);
 }
 subsys_initcall(i2c_adap_imx_init);
 
index f4a0167..b7c8577 100644 (file)
@@ -780,12 +780,13 @@ static struct platform_driver mxs_i2c_driver = {
                   .owner = THIS_MODULE,
                   .of_match_table = mxs_i2c_dt_ids,
                   },
+       .probe = mxs_i2c_probe,
        .remove = mxs_i2c_remove,
 };
 
 static int __init mxs_i2c_init(void)
 {
-       return platform_driver_probe(&mxs_i2c_driver, mxs_i2c_probe);
+       return platform_driver_register(&mxs_i2c_driver);
 }
 subsys_initcall(mxs_i2c_init);
 
index 6d8308d..9967a6f 100644 (file)
@@ -939,6 +939,9 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
                /*
                 * ProDB0017052: Clear ARDY bit twice
                 */
+               if (stat & OMAP_I2C_STAT_ARDY)
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ARDY);
+
                if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
                                        OMAP_I2C_STAT_AL)) {
                        omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY |
index f8f6f2e..04a17b9 100644 (file)
@@ -859,8 +859,7 @@ static const struct i2c_algorithm stu300_algo = {
        .functionality  = stu300_func,
 };
 
-static int __init
-stu300_probe(struct platform_device *pdev)
+static int stu300_probe(struct platform_device *pdev)
 {
        struct stu300_dev *dev;
        struct i2c_adapter *adap;
@@ -966,8 +965,7 @@ static SIMPLE_DEV_PM_OPS(stu300_pm, stu300_suspend, stu300_resume);
 #define STU300_I2C_PM  NULL
 #endif
 
-static int __exit
-stu300_remove(struct platform_device *pdev)
+static int stu300_remove(struct platform_device *pdev)
 {
        struct stu300_dev *dev = platform_get_drvdata(pdev);
 
@@ -989,13 +987,14 @@ static struct platform_driver stu300_i2c_driver = {
                .pm     = STU300_I2C_PM,
                .of_match_table = stu300_dt_match,
        },
-       .remove         = __exit_p(stu300_remove),
+       .probe = stu300_probe,
+       .remove = stu300_remove,
 
 };
 
 static int __init stu300_init(void)
 {
-       return platform_driver_probe(&stu300_i2c_driver, stu300_probe);
+       return platform_driver_register(&stu300_i2c_driver);
 }
 
 static void __exit stu300_exit(void)
index 29d3f04..3be58f8 100644 (file)
@@ -1134,6 +1134,9 @@ static void acpi_i2c_register_devices(struct i2c_adapter *adap)
        acpi_handle handle;
        acpi_status status;
 
+       if (!adap->dev.parent)
+               return;
+
        handle = ACPI_HANDLE(adap->dev.parent);
        if (!handle)
                return;
index 74b41ae..928656e 100644 (file)
@@ -200,7 +200,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
        arb->parent = of_find_i2c_adapter_by_node(parent_np);
        if (!arb->parent) {
                dev_err(dev, "Cannot find parent bus\n");
-               return -EINVAL;
+               return -EPROBE_DEFER;
        }
 
        /* Actually add the mux adapter */
index 5d4a99b..a764da7 100644 (file)
@@ -66,7 +66,7 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
        struct device_node *adapter_np, *child;
        struct i2c_adapter *adapter;
        unsigned *values, *gpios;
-       int i = 0;
+       int i = 0, ret;
 
        if (!np)
                return -ENODEV;
@@ -79,7 +79,7 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
        adapter = of_find_i2c_adapter_by_node(adapter_np);
        if (!adapter) {
                dev_err(&pdev->dev, "Cannot find parent bus\n");
-               return -ENODEV;
+               return -EPROBE_DEFER;
        }
        mux->data.parent = i2c_adapter_id(adapter);
        put_device(&adapter->dev);
@@ -116,8 +116,12 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
                return -ENOMEM;
        }
 
-       for (i = 0; i < mux->data.n_gpios; i++)
-               gpios[i] = of_get_named_gpio(np, "mux-gpios", i);
+       for (i = 0; i < mux->data.n_gpios; i++) {
+               ret = of_get_named_gpio(np, "mux-gpios", i);
+               if (ret < 0)
+                       return ret;
+               gpios[i] = ret;
+       }
 
        mux->data.gpios = gpios;
 
@@ -177,7 +181,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
        if (!parent) {
                dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
                        mux->data.parent);
-               return -ENODEV;
+               return -EPROBE_DEFER;
        }
 
        mux->parent = parent;
index 69a9173..68a3715 100644 (file)
@@ -113,7 +113,7 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
        adapter = of_find_i2c_adapter_by_node(adapter_np);
        if (!adapter) {
                dev_err(mux->dev, "Cannot find parent bus\n");
-               return -ENODEV;
+               return -EPROBE_DEFER;
        }
        mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
        put_device(&adapter->dev);
@@ -211,7 +211,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
        if (!mux->parent) {
                dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
                        mux->pdata->parent_bus_num);
-               ret = -ENODEV;
+               ret = -EPROBE_DEFER;
                goto err;
        }
 
index d0a79a4..ba6f6a9 100644 (file)
@@ -185,10 +185,8 @@ static int ad8366_remove(struct spi_device *spi)
 
        iio_device_unregister(indio_dev);
 
-       if (!IS_ERR(reg)) {
+       if (!IS_ERR(reg))
                regulator_disable(reg);
-               regulator_put(reg);
-       }
 
        return 0;
 }
index a7b30be..52605c0 100644 (file)
@@ -525,8 +525,10 @@ static int adf4350_probe(struct spi_device *spi)
        }
 
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
-       if (indio_dev == NULL)
-               return -ENOMEM;
+       if (indio_dev == NULL) {
+               ret =  -ENOMEM;
+               goto error_disable_clk;
+       }
 
        st = iio_priv(indio_dev);
 
index 2710f72..2db7dcd 100644 (file)
@@ -477,6 +477,9 @@ void iio_disable_all_buffers(struct iio_dev *indio_dev)
        indio_dev->currentmode = INDIO_DIRECT_MODE;
        if (indio_dev->setup_ops->postdisable)
                indio_dev->setup_ops->postdisable(indio_dev);
+
+       if (indio_dev->available_scan_masks == NULL)
+               kfree(indio_dev->active_scan_mask);
 }
 
 int iio_update_buffers(struct iio_dev *indio_dev,
index 8e84cd5..f95c697 100644 (file)
@@ -852,7 +852,6 @@ static void iio_dev_release(struct device *device)
                iio_device_unregister_trigger_consumer(indio_dev);
        iio_device_unregister_eventset(indio_dev);
        iio_device_unregister_sysfs(indio_dev);
-       iio_device_unregister_debugfs(indio_dev);
 
        ida_simple_remove(&iio_ida, indio_dev->id);
        kfree(indio_dev);
@@ -1087,6 +1086,7 @@ void iio_device_unregister(struct iio_dev *indio_dev)
 
        if (indio_dev->chrdev.dev)
                cdev_del(&indio_dev->chrdev);
+       iio_device_unregister_debugfs(indio_dev);
 
        iio_disable_all_buffers(indio_dev);
 
index e8d2849..cab3bc7 100644 (file)
@@ -29,9 +29,9 @@
 #define ST_MAGN_NUMBER_DATA_CHANNELS           3
 
 /* DEFAULT VALUE FOR SENSORS */
-#define ST_MAGN_DEFAULT_OUT_X_L_ADDR           0X04
-#define ST_MAGN_DEFAULT_OUT_Y_L_ADDR           0X08
-#define ST_MAGN_DEFAULT_OUT_Z_L_ADDR           0X06
+#define ST_MAGN_DEFAULT_OUT_X_H_ADDR           0X03
+#define ST_MAGN_DEFAULT_OUT_Y_H_ADDR           0X07
+#define ST_MAGN_DEFAULT_OUT_Z_H_ADDR           0X05
 
 /* FULLSCALE */
 #define ST_MAGN_FS_AVL_1300MG                  1300
 static const struct iio_chan_spec st_magn_16bit_channels[] = {
        ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
                        BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
-                       ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
-                       ST_MAGN_DEFAULT_OUT_X_L_ADDR),
+                       ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_BE, 16, 16,
+                       ST_MAGN_DEFAULT_OUT_X_H_ADDR),
        ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
                        BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
-                       ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
-                       ST_MAGN_DEFAULT_OUT_Y_L_ADDR),
+                       ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_BE, 16, 16,
+                       ST_MAGN_DEFAULT_OUT_Y_H_ADDR),
        ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
                        BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
-                       ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
-                       ST_MAGN_DEFAULT_OUT_Z_L_ADDR),
+                       ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_BE, 16, 16,
+                       ST_MAGN_DEFAULT_OUT_Z_H_ADDR),
        IIO_CHAN_SOFT_TIMESTAMP(3)
 };
 
index 5ceda71..b84791f 100644 (file)
@@ -31,6 +31,17 @@ config INFINIBAND_USER_ACCESS
          libibverbs, libibcm and a hardware driver library from
          <http://www.openfabrics.org/git/>.
 
+config INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
+       bool "Experimental and unstable ABI for userspace access to flow steering verbs"
+       depends on INFINIBAND_USER_ACCESS
+       depends on STAGING
+       ---help---
+         The final ABI for userspace access to flow steering verbs
+         has not been defined.  To use the current ABI, *WHICH WILL
+         CHANGE IN THE FUTURE*, say Y here.
+
+         If unsure, say N.
+
 config INFINIBAND_USER_MEM
        bool
        depends on INFINIBAND_USER_ACCESS != n
index d040b87..d8f9c6c 100644 (file)
@@ -217,7 +217,9 @@ IB_UVERBS_DECLARE_CMD(destroy_srq);
 IB_UVERBS_DECLARE_CMD(create_xsrq);
 IB_UVERBS_DECLARE_CMD(open_xrcd);
 IB_UVERBS_DECLARE_CMD(close_xrcd);
+#ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
 IB_UVERBS_DECLARE_CMD(create_flow);
 IB_UVERBS_DECLARE_CMD(destroy_flow);
+#endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */
 
 #endif /* UVERBS_H */
index f2b81b9..2f0f01b 100644 (file)
@@ -54,7 +54,9 @@ static struct uverbs_lock_class qp_lock_class = { .name = "QP-uobj" };
 static struct uverbs_lock_class ah_lock_class  = { .name = "AH-uobj" };
 static struct uverbs_lock_class srq_lock_class = { .name = "SRQ-uobj" };
 static struct uverbs_lock_class xrcd_lock_class = { .name = "XRCD-uobj" };
+#ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
 static struct uverbs_lock_class rule_lock_class = { .name = "RULE-uobj" };
+#endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */
 
 #define INIT_UDATA(udata, ibuf, obuf, ilen, olen)                      \
        do {                                                            \
@@ -2599,6 +2601,7 @@ out_put:
        return ret ? ret : in_len;
 }
 
+#ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
 static int kern_spec_to_ib_spec(struct ib_kern_spec *kern_spec,
                                union ib_flow_spec *ib_spec)
 {
@@ -2824,6 +2827,7 @@ ssize_t ib_uverbs_destroy_flow(struct ib_uverbs_file *file,
 
        return ret ? ret : in_len;
 }
+#endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */
 
 static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
                                struct ib_uverbs_create_xsrq *cmd,
index 75ad86c..2df31f6 100644 (file)
@@ -115,8 +115,10 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
        [IB_USER_VERBS_CMD_CLOSE_XRCD]          = ib_uverbs_close_xrcd,
        [IB_USER_VERBS_CMD_CREATE_XSRQ]         = ib_uverbs_create_xsrq,
        [IB_USER_VERBS_CMD_OPEN_QP]             = ib_uverbs_open_qp,
+#ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
        [IB_USER_VERBS_CMD_CREATE_FLOW]         = ib_uverbs_create_flow,
        [IB_USER_VERBS_CMD_DESTROY_FLOW]        = ib_uverbs_destroy_flow
+#endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */
 };
 
 static void ib_uverbs_add_one(struct ib_device *device);
@@ -605,6 +607,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
        if (!(file->device->ib_dev->uverbs_cmd_mask & (1ull << hdr.command)))
                return -ENOSYS;
 
+#ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
        if (hdr.command >= IB_USER_VERBS_CMD_THRESHOLD) {
                struct ib_uverbs_cmd_hdr_ex hdr_ex;
 
@@ -621,6 +624,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
                                                     (hdr_ex.out_words +
                                                      hdr_ex.provider_out_words) * 4);
        } else {
+#endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */
                if (hdr.in_words * 4 != count)
                        return -EINVAL;
 
@@ -628,7 +632,9 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
                                                     buf + sizeof(hdr),
                                                     hdr.in_words * 4,
                                                     hdr.out_words * 4);
+#ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
        }
+#endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */
 }
 
 static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
index d5d1929..cedda25 100644 (file)
@@ -141,7 +141,7 @@ static const char *to_qp_state_str(int state)
                return "C2_QP_STATE_ERROR";
        default:
                return "<invalid QP state>";
-       };
+       }
 }
 
 void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
index d6c5a73..f061264 100644 (file)
@@ -1691,9 +1691,11 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
                ibdev->ib_dev.create_flow       = mlx4_ib_create_flow;
                ibdev->ib_dev.destroy_flow      = mlx4_ib_destroy_flow;
 
+#ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
                ibdev->ib_dev.uverbs_cmd_mask   |=
                        (1ull << IB_USER_VERBS_CMD_CREATE_FLOW) |
                        (1ull << IB_USER_VERBS_CMD_DESTROY_FLOW);
+#endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */
        }
 
        mlx4_ib_alloc_eqs(dev, ibdev);
index 3f831de..b1a6cb3 100644 (file)
@@ -164,6 +164,7 @@ int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn)
 static int alloc_comp_eqs(struct mlx5_ib_dev *dev)
 {
        struct mlx5_eq_table *table = &dev->mdev.priv.eq_table;
+       char name[MLX5_MAX_EQ_NAME];
        struct mlx5_eq *eq, *n;
        int ncomp_vec;
        int nent;
@@ -180,11 +181,10 @@ static int alloc_comp_eqs(struct mlx5_ib_dev *dev)
                        goto clean;
                }
 
-               snprintf(eq->name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i);
+               snprintf(name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i);
                err = mlx5_create_map_eq(&dev->mdev, eq,
                                         i + MLX5_EQ_VEC_COMP_BASE, nent, 0,
-                                        eq->name,
-                                        &dev->mdev.priv.uuari.uars[0]);
+                                        name, &dev->mdev.priv.uuari.uars[0]);
                if (err) {
                        kfree(eq);
                        goto clean;
@@ -301,9 +301,8 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
        props->max_srq_sge         = max_rq_sg - 1;
        props->max_fast_reg_page_list_len = (unsigned int)-1;
        props->local_ca_ack_delay  = dev->mdev.caps.local_ca_ack_delay;
-       props->atomic_cap          = dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_ATOMIC ?
-               IB_ATOMIC_HCA : IB_ATOMIC_NONE;
-       props->masked_atomic_cap   = IB_ATOMIC_HCA;
+       props->atomic_cap          = IB_ATOMIC_NONE;
+       props->masked_atomic_cap   = IB_ATOMIC_NONE;
        props->max_pkeys           = be16_to_cpup((__be16 *)(out_mad->data + 28));
        props->max_mcast_grp       = 1 << dev->mdev.caps.log_max_mcg;
        props->max_mcast_qp_attach = dev->mdev.caps.max_qp_mcg;
@@ -1006,6 +1005,11 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
        ibev.device           = &ibdev->ib_dev;
        ibev.element.port_num = port;
 
+       if (port < 1 || port > ibdev->num_ports) {
+               mlx5_ib_warn(ibdev, "warning: event on port %d\n", port);
+               return;
+       }
+
        if (ibdev->ib_active)
                ib_dispatch_event(&ibev);
 }
index bd41df9..3453580 100644 (file)
@@ -42,6 +42,10 @@ enum {
        DEF_CACHE_SIZE  = 10,
 };
 
+enum {
+       MLX5_UMR_ALIGN  = 2048
+};
+
 static __be64 *mr_align(__be64 *ptr, int align)
 {
        unsigned long mask = align - 1;
@@ -61,13 +65,11 @@ static int order2idx(struct mlx5_ib_dev *dev, int order)
 
 static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
 {
-       struct device *ddev = dev->ib_dev.dma_device;
        struct mlx5_mr_cache *cache = &dev->cache;
        struct mlx5_cache_ent *ent = &cache->ent[c];
        struct mlx5_create_mkey_mbox_in *in;
        struct mlx5_ib_mr *mr;
        int npages = 1 << ent->order;
-       int size = sizeof(u64) * npages;
        int err = 0;
        int i;
 
@@ -83,21 +85,6 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
                }
                mr->order = ent->order;
                mr->umred = 1;
-               mr->pas = kmalloc(size + 0x3f, GFP_KERNEL);
-               if (!mr->pas) {
-                       kfree(mr);
-                       err = -ENOMEM;
-                       goto out;
-               }
-               mr->dma = dma_map_single(ddev, mr_align(mr->pas, 0x40), size,
-                                        DMA_TO_DEVICE);
-               if (dma_mapping_error(ddev, mr->dma)) {
-                       kfree(mr->pas);
-                       kfree(mr);
-                       err = -ENOMEM;
-                       goto out;
-               }
-
                in->seg.status = 1 << 6;
                in->seg.xlt_oct_size = cpu_to_be32((npages + 1) / 2);
                in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
@@ -108,8 +95,6 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
                                            sizeof(*in));
                if (err) {
                        mlx5_ib_warn(dev, "create mkey failed %d\n", err);
-                       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
-                       kfree(mr->pas);
                        kfree(mr);
                        goto out;
                }
@@ -129,11 +114,9 @@ out:
 
 static void remove_keys(struct mlx5_ib_dev *dev, int c, int num)
 {
-       struct device *ddev = dev->ib_dev.dma_device;
        struct mlx5_mr_cache *cache = &dev->cache;
        struct mlx5_cache_ent *ent = &cache->ent[c];
        struct mlx5_ib_mr *mr;
-       int size;
        int err;
        int i;
 
@@ -149,14 +132,10 @@ static void remove_keys(struct mlx5_ib_dev *dev, int c, int num)
                ent->size--;
                spin_unlock(&ent->lock);
                err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
-               if (err) {
+               if (err)
                        mlx5_ib_warn(dev, "failed destroy mkey\n");
-               } else {
-                       size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40);
-                       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
-                       kfree(mr->pas);
+               else
                        kfree(mr);
-               }
        }
 }
 
@@ -408,13 +387,12 @@ static void free_cached_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
 
 static void clean_keys(struct mlx5_ib_dev *dev, int c)
 {
-       struct device *ddev = dev->ib_dev.dma_device;
        struct mlx5_mr_cache *cache = &dev->cache;
        struct mlx5_cache_ent *ent = &cache->ent[c];
        struct mlx5_ib_mr *mr;
-       int size;
        int err;
 
+       cancel_delayed_work(&ent->dwork);
        while (1) {
                spin_lock(&ent->lock);
                if (list_empty(&ent->head)) {
@@ -427,14 +405,10 @@ static void clean_keys(struct mlx5_ib_dev *dev, int c)
                ent->size--;
                spin_unlock(&ent->lock);
                err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
-               if (err) {
+               if (err)
                        mlx5_ib_warn(dev, "failed destroy mkey\n");
-               } else {
-                       size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40);
-                       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
-                       kfree(mr->pas);
+               else
                        kfree(mr);
-               }
        }
 }
 
@@ -540,13 +514,15 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)
        int i;
 
        dev->cache.stopped = 1;
-       destroy_workqueue(dev->cache.wq);
+       flush_workqueue(dev->cache.wq);
 
        mlx5_mr_cache_debugfs_cleanup(dev);
 
        for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++)
                clean_keys(dev, i);
 
+       destroy_workqueue(dev->cache.wq);
+
        return 0;
 }
 
@@ -675,10 +651,12 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
                                  int page_shift, int order, int access_flags)
 {
        struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct device *ddev = dev->ib_dev.dma_device;
        struct umr_common *umrc = &dev->umrc;
        struct ib_send_wr wr, *bad;
        struct mlx5_ib_mr *mr;
        struct ib_sge sg;
+       int size = sizeof(u64) * npages;
        int err;
        int i;
 
@@ -697,7 +675,22 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
        if (!mr)
                return ERR_PTR(-EAGAIN);
 
-       mlx5_ib_populate_pas(dev, umem, page_shift, mr_align(mr->pas, 0x40), 1);
+       mr->pas = kmalloc(size + MLX5_UMR_ALIGN - 1, GFP_KERNEL);
+       if (!mr->pas) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       mlx5_ib_populate_pas(dev, umem, page_shift,
+                            mr_align(mr->pas, MLX5_UMR_ALIGN), 1);
+
+       mr->dma = dma_map_single(ddev, mr_align(mr->pas, MLX5_UMR_ALIGN), size,
+                                DMA_TO_DEVICE);
+       if (dma_mapping_error(ddev, mr->dma)) {
+               kfree(mr->pas);
+               err = -ENOMEM;
+               goto error;
+       }
 
        memset(&wr, 0, sizeof(wr));
        wr.wr_id = (u64)(unsigned long)mr;
@@ -718,6 +711,9 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
        wait_for_completion(&mr->done);
        up(&umrc->sem);
 
+       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
+       kfree(mr->pas);
+
        if (mr->status != IB_WC_SUCCESS) {
                mlx5_ib_warn(dev, "reg umr failed\n");
                err = -EFAULT;
index 045f8cd..5659ea8 100644 (file)
@@ -203,7 +203,7 @@ static int sq_overhead(enum ib_qp_type qp_type)
 
        switch (qp_type) {
        case IB_QPT_XRC_INI:
-               size = sizeof(struct mlx5_wqe_xrc_seg);
+               size += sizeof(struct mlx5_wqe_xrc_seg);
                /* fall through */
        case IB_QPT_RC:
                size += sizeof(struct mlx5_wqe_ctrl_seg) +
@@ -211,20 +211,23 @@ static int sq_overhead(enum ib_qp_type qp_type)
                        sizeof(struct mlx5_wqe_raddr_seg);
                break;
 
+       case IB_QPT_XRC_TGT:
+               return 0;
+
        case IB_QPT_UC:
-               size = sizeof(struct mlx5_wqe_ctrl_seg) +
+               size += sizeof(struct mlx5_wqe_ctrl_seg) +
                        sizeof(struct mlx5_wqe_raddr_seg);
                break;
 
        case IB_QPT_UD:
        case IB_QPT_SMI:
        case IB_QPT_GSI:
-               size = sizeof(struct mlx5_wqe_ctrl_seg) +
+               size += sizeof(struct mlx5_wqe_ctrl_seg) +
                        sizeof(struct mlx5_wqe_datagram_seg);
                break;
 
        case MLX5_IB_QPT_REG_UMR:
-               size = sizeof(struct mlx5_wqe_ctrl_seg) +
+               size += sizeof(struct mlx5_wqe_ctrl_seg) +
                        sizeof(struct mlx5_wqe_umr_ctrl_seg) +
                        sizeof(struct mlx5_mkey_seg);
                break;
@@ -270,7 +273,8 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
                return wqe_size;
 
        if (wqe_size > dev->mdev.caps.max_sq_desc_sz) {
-               mlx5_ib_dbg(dev, "\n");
+               mlx5_ib_dbg(dev, "wqe_size(%d) > max_sq_desc_sz(%d)\n",
+                           wqe_size, dev->mdev.caps.max_sq_desc_sz);
                return -EINVAL;
        }
 
@@ -280,9 +284,15 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
 
        wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size);
        qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB;
+       if (qp->sq.wqe_cnt > dev->mdev.caps.max_wqes) {
+               mlx5_ib_dbg(dev, "wqe count(%d) exceeds limits(%d)\n",
+                           qp->sq.wqe_cnt, dev->mdev.caps.max_wqes);
+               return -ENOMEM;
+       }
        qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB);
        qp->sq.max_gs = attr->cap.max_send_sge;
-       qp->sq.max_post = 1 << ilog2(wq_size / wqe_size);
+       qp->sq.max_post = wq_size / wqe_size;
+       attr->cap.max_send_wr = qp->sq.max_post;
 
        return wq_size;
 }
@@ -1280,6 +1290,11 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q
                                          MLX5_QP_OPTPAR_Q_KEY,
                        [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_PKEY_INDEX    |
                                           MLX5_QP_OPTPAR_Q_KEY,
+                       [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH |
+                                         MLX5_QP_OPTPAR_RRE            |
+                                         MLX5_QP_OPTPAR_RAE            |
+                                         MLX5_QP_OPTPAR_RWE            |
+                                         MLX5_QP_OPTPAR_PKEY_INDEX,
                },
        },
        [MLX5_QP_STATE_RTR] = {
@@ -1314,6 +1329,11 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q
                [MLX5_QP_STATE_RTS] = {
                        [MLX5_QP_ST_UD]  = MLX5_QP_OPTPAR_Q_KEY,
                        [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_Q_KEY,
+                       [MLX5_QP_ST_UC]  = MLX5_QP_OPTPAR_RWE,
+                       [MLX5_QP_ST_RC]  = MLX5_QP_OPTPAR_RNR_TIMEOUT   |
+                                          MLX5_QP_OPTPAR_RWE           |
+                                          MLX5_QP_OPTPAR_RAE           |
+                                          MLX5_QP_OPTPAR_RRE,
                },
        },
 };
@@ -1651,29 +1671,6 @@ static __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg,
        rseg->reserved = 0;
 }
 
-static void set_atomic_seg(struct mlx5_wqe_atomic_seg *aseg, struct ib_send_wr *wr)
-{
-       if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
-               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
-       } else if (wr->opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
-               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add_mask);
-       } else {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
-               aseg->compare  = 0;
-       }
-}
-
-static void set_masked_atomic_seg(struct mlx5_wqe_masked_atomic_seg *aseg,
-                                 struct ib_send_wr *wr)
-{
-       aseg->swap_add          = cpu_to_be64(wr->wr.atomic.swap);
-       aseg->swap_add_mask     = cpu_to_be64(wr->wr.atomic.swap_mask);
-       aseg->compare           = cpu_to_be64(wr->wr.atomic.compare_add);
-       aseg->compare_mask      = cpu_to_be64(wr->wr.atomic.compare_add_mask);
-}
-
 static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg,
                             struct ib_send_wr *wr)
 {
@@ -2063,28 +2060,11 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               set_raddr_seg(seg, wr->wr.atomic.remote_addr,
-                                             wr->wr.atomic.rkey);
-                               seg  += sizeof(struct mlx5_wqe_raddr_seg);
-
-                               set_atomic_seg(seg, wr);
-                               seg  += sizeof(struct mlx5_wqe_atomic_seg);
-
-                               size += (sizeof(struct mlx5_wqe_raddr_seg) +
-                                        sizeof(struct mlx5_wqe_atomic_seg)) / 16;
-                               break;
-
                        case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
-                               set_raddr_seg(seg, wr->wr.atomic.remote_addr,
-                                             wr->wr.atomic.rkey);
-                               seg  += sizeof(struct mlx5_wqe_raddr_seg);
-
-                               set_masked_atomic_seg(seg, wr);
-                               seg  += sizeof(struct mlx5_wqe_masked_atomic_seg);
-
-                               size += (sizeof(struct mlx5_wqe_raddr_seg) +
-                                        sizeof(struct mlx5_wqe_masked_atomic_seg)) / 16;
-                               break;
+                               mlx5_ib_warn(dev, "Atomic operations are not supported yet\n");
+                               err = -ENOSYS;
+                               *bad_wr = wr;
+                               goto out;
 
                        case IB_WR_LOCAL_INV:
                                next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
index 84d297a..0aa478b 100644 (file)
@@ -295,7 +295,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
        mlx5_vfree(in);
        if (err) {
                mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err);
-               goto err_srq;
+               goto err_usr_kern_srq;
        }
 
        mlx5_ib_dbg(dev, "create SRQ with srqn 0x%x\n", srq->msrq.srqn);
@@ -316,6 +316,8 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
 
 err_core:
        mlx5_core_destroy_srq(&dev->mdev, &srq->msrq);
+
+err_usr_kern_srq:
        if (pd->uobject)
                destroy_srq_user(pd, srq);
        else
index 7c9d35f..6902017 100644 (file)
@@ -357,7 +357,7 @@ static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
                        mthca_warn(dev, "Unhandled event %02x(%02x) on EQ %d\n",
                                   eqe->type, eqe->subtype, eq->eqn);
                        break;
-               };
+               }
 
                set_eqe_hw(eqe);
                ++eq->cons_index;
index 4ed8235..50219ab 100644 (file)
@@ -150,7 +150,7 @@ enum ib_qp_state get_ibqp_state(enum ocrdma_qp_state qps)
                return IB_QPS_SQE;
        case OCRDMA_QPS_ERR:
                return IB_QPS_ERR;
-       };
+       }
        return IB_QPS_ERR;
 }
 
@@ -171,7 +171,7 @@ static enum ocrdma_qp_state get_ocrdma_qp_state(enum ib_qp_state qps)
                return OCRDMA_QPS_SQE;
        case IB_QPS_ERR:
                return OCRDMA_QPS_ERR;
-       };
+       }
        return OCRDMA_QPS_ERR;
 }
 
@@ -1982,7 +1982,7 @@ int ocrdma_mbx_create_qp(struct ocrdma_qp *qp, struct ib_qp_init_attr *attrs,
                break;
        default:
                return -EINVAL;
-       };
+       }
 
        cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_QP, sizeof(*cmd));
        if (!cmd)
index 56e0049..0ce7674 100644 (file)
@@ -531,7 +531,7 @@ static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event)
        case BE_DEV_DOWN:
                ocrdma_close(dev);
                break;
-       };
+       }
 }
 
 static struct ocrdma_driver ocrdma_drv = {
index 6e982bb..69f1d12 100644 (file)
@@ -141,7 +141,7 @@ static inline void get_link_speed_and_width(struct ocrdma_dev *dev,
                /* Unsupported */
                *ib_speed = IB_SPEED_SDR;
                *ib_width = IB_WIDTH_1X;
-       };
+       }
 }
 
 
@@ -2331,7 +2331,7 @@ static enum ib_wc_status ocrdma_to_ibwc_err(u16 status)
        default:
                ibwc_status = IB_WC_GENERAL_ERR;
                break;
-       };
+       }
        return ibwc_status;
 }
 
@@ -2370,7 +2370,7 @@ static void ocrdma_update_wc(struct ocrdma_qp *qp, struct ib_wc *ibwc,
                pr_err("%s() invalid opcode received = 0x%x\n",
                       __func__, hdr->cw & OCRDMA_WQE_OPCODE_MASK);
                break;
-       };
+       }
 }
 
 static void ocrdma_set_cqe_status_flushed(struct ocrdma_qp *qp,
index 3591855..6df2350 100644 (file)
@@ -594,7 +594,7 @@ isert_connect_release(struct isert_conn *isert_conn)
 
        pr_debug("Entering isert_connect_release(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
 
-       if (device->use_frwr)
+       if (device && device->use_frwr)
                isert_conn_free_frwr_pool(isert_conn);
 
        if (isert_conn->conn_qp) {
index 653ac6b..6c923c7 100644 (file)
@@ -1588,7 +1588,7 @@ static int srpt_build_tskmgmt_rsp(struct srpt_rdma_ch *ch,
        int resp_data_len;
        int resp_len;
 
-       resp_data_len = (rsp_code == SRP_TSK_MGMT_SUCCESS) ? 0 : 4;
+       resp_data_len = 4;
        resp_len = sizeof(*srp_rsp) + resp_data_len;
 
        srp_rsp = ioctx->ioctx.buf;
@@ -1600,11 +1600,9 @@ static int srpt_build_tskmgmt_rsp(struct srpt_rdma_ch *ch,
                                    + atomic_xchg(&ch->req_lim_delta, 0));
        srp_rsp->tag = tag;
 
-       if (rsp_code != SRP_TSK_MGMT_SUCCESS) {
-               srp_rsp->flags |= SRP_RSP_FLAG_RSPVALID;
-               srp_rsp->resp_data_len = cpu_to_be32(resp_data_len);
-               srp_rsp->data[3] = rsp_code;
-       }
+       srp_rsp->flags |= SRP_RSP_FLAG_RSPVALID;
+       srp_rsp->resp_data_len = cpu_to_be32(resp_data_len);
+       srp_rsp->data[3] = rsp_code;
 
        return resp_len;
 }
@@ -2358,6 +2356,8 @@ static void srpt_release_channel_work(struct work_struct *w)
        transport_deregister_session(se_sess);
        ch->sess = NULL;
 
+       ib_destroy_cm_id(ch->cm_id);
+
        srpt_destroy_ch_ib(ch);
 
        srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring,
@@ -2368,8 +2368,6 @@ static void srpt_release_channel_work(struct work_struct *w)
        list_del(&ch->list);
        spin_unlock_irq(&sdev->spinlock);
 
-       ib_destroy_cm_id(ch->cm_id);
-
        if (ch->release_done)
                complete(ch->release_done);
 
index c044699..e75d015 100644 (file)
@@ -1734,6 +1734,7 @@ EXPORT_SYMBOL_GPL(input_class);
  */
 struct input_dev *input_allocate_device(void)
 {
+       static atomic_t input_no = ATOMIC_INIT(0);
        struct input_dev *dev;
 
        dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
@@ -1743,9 +1744,13 @@ struct input_dev *input_allocate_device(void)
                device_initialize(&dev->dev);
                mutex_init(&dev->mutex);
                spin_lock_init(&dev->event_lock);
+               init_timer(&dev->timer);
                INIT_LIST_HEAD(&dev->h_list);
                INIT_LIST_HEAD(&dev->node);
 
+               dev_set_name(&dev->dev, "input%ld",
+                            (unsigned long) atomic_inc_return(&input_no) - 1);
+
                __module_get(THIS_MODULE);
        }
 
@@ -2019,7 +2024,6 @@ static void devm_input_device_unregister(struct device *dev, void *res)
  */
 int input_register_device(struct input_dev *dev)
 {
-       static atomic_t input_no = ATOMIC_INIT(0);
        struct input_devres *devres = NULL;
        struct input_handler *handler;
        unsigned int packet_size;
@@ -2059,7 +2063,6 @@ int input_register_device(struct input_dev *dev)
         * If delay and period are pre-set by the driver, then autorepeating
         * is handled by the driver itself and we don't do it in input.c.
         */
-       init_timer(&dev->timer);
        if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
                dev->timer.data = (long) dev;
                dev->timer.function = input_repeat_key;
@@ -2073,9 +2076,6 @@ int input_register_device(struct input_dev *dev)
        if (!dev->setkeycode)
                dev->setkeycode = input_default_setkeycode;
 
-       dev_set_name(&dev->dev, "input%ld",
-                    (unsigned long) atomic_inc_return(&input_no) - 1);
-
        error = device_add(&dev->dev);
        if (error)
                goto err_free_vals;
index 134c3b4..a2e758d 100644 (file)
@@ -786,10 +786,17 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
        input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 
-       if (pdata)
+       if (pdata) {
                error = pxa27x_keypad_build_keycode(keypad);
-       else
+       } else {
                error = pxa27x_keypad_build_keycode_from_dt(keypad);
+               /*
+                * Data that we get from DT resides in dynamically
+                * allocated memory so we need to update our pdata
+                * pointer.
+                */
+               pdata = keypad->pdata;
+       }
        if (error) {
                dev_err(&pdev->dev, "failed to build keycode\n");
                goto failed_put_clk;
index 082684e..9365535 100644 (file)
@@ -351,7 +351,9 @@ static void cm109_urb_irq_callback(struct urb *urb)
        if (status) {
                if (status == -ESHUTDOWN)
                        return;
-               dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status);
+               dev_err_ratelimited(&dev->intf->dev, "%s: urb status %d\n",
+                                   __func__, status);
+               goto out;
        }
 
        /* Special keys */
@@ -418,8 +420,12 @@ static void cm109_urb_ctl_callback(struct urb *urb)
             dev->ctl_data->byte[2],
             dev->ctl_data->byte[3]);
 
-       if (status)
-               dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status);
+       if (status) {
+               if (status == -ESHUTDOWN)
+                       return;
+               dev_err_ratelimited(&dev->intf->dev, "%s: urb status %d\n",
+                                   __func__, status);
+       }
 
        spin_lock(&dev->ctl_submit_lock);
 
@@ -427,7 +433,7 @@ static void cm109_urb_ctl_callback(struct urb *urb)
 
        if (likely(!dev->shutdown)) {
 
-               if (dev->buzzer_pending) {
+               if (dev->buzzer_pending || status) {
                        dev->buzzer_pending = 0;
                        dev->ctl_urb_pending = 1;
                        cm109_submit_buzz_toggle(dev);
index 7c5d72a..8365847 100644 (file)
@@ -103,6 +103,7 @@ static const struct alps_model_info alps_model_data[] = {
        /* Dell Latitude E5500, E6400, E6500, Precision M4400 */
        { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,
                ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
+       { { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_DUALPOINT },              /* Dell XT2 */
        { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS },           /* Dell Vostro 1400 */
        { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
                ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },                            /* Toshiba Tecra A11-11L */
index 78e4de4..52c9ebf 100644 (file)
@@ -223,21 +223,26 @@ static int i8042_flush(void)
 {
        unsigned long flags;
        unsigned char data, str;
-       int i = 0;
+       int count = 0;
+       int retval = 0;
 
        spin_lock_irqsave(&i8042_lock, flags);
 
-       while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) {
-               udelay(50);
-               data = i8042_read_data();
-               i++;
-               dbg("%02x <- i8042 (flush, %s)\n",
-                   data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
+       while ((str = i8042_read_status()) & I8042_STR_OBF) {
+               if (count++ < I8042_BUFFER_SIZE) {
+                       udelay(50);
+                       data = i8042_read_data();
+                       dbg("%02x <- i8042 (flush, %s)\n",
+                           data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
+               } else {
+                       retval = -EIO;
+                       break;
+               }
        }
 
        spin_unlock_irqrestore(&i8042_lock, flags);
 
-       return i;
+       return retval;
 }
 
 /*
@@ -849,7 +854,7 @@ static int __init i8042_check_aux(void)
 
 static int i8042_controller_check(void)
 {
-       if (i8042_flush() == I8042_BUFFER_SIZE) {
+       if (i8042_flush()) {
                pr_err("No controller found\n");
                return -ENODEV;
        }
index 79b69ea..e53416a 100644 (file)
@@ -1031,6 +1031,7 @@ static void wacom_destroy_leds(struct wacom *wacom)
 }
 
 static enum power_supply_property wacom_battery_props[] = {
+       POWER_SUPPLY_PROP_SCOPE,
        POWER_SUPPLY_PROP_CAPACITY
 };
 
@@ -1042,6 +1043,9 @@ static int wacom_battery_get_property(struct power_supply *psy,
        int ret = 0;
 
        switch (psp) {
+               case POWER_SUPPLY_PROP_SCOPE:
+                       val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+                       break;
                case POWER_SUPPLY_PROP_CAPACITY:
                        val->intval =
                                wacom->wacom_wac.battery_capacity * 100 / 31;
index b2aa503..c59b797 100644 (file)
@@ -2054,6 +2054,12 @@ static const struct wacom_features wacom_features_0x101 =
 static const struct wacom_features wacom_features_0x10D =
        { "Wacom ISDv4 10D",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,
          0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x10E =
+       { "Wacom ISDv4 10E",      WACOM_PKGLEN_MTTPC,     27760, 15694,  255,
+         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x10F =
+       { "Wacom ISDv4 10F",      WACOM_PKGLEN_MTTPC,     27760, 15694,  255,
+         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x4001 =
        { "Wacom ISDv4 4001",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,
          0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2248,6 +2254,8 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x100) },
        { USB_DEVICE_WACOM(0x101) },
        { USB_DEVICE_WACOM(0x10D) },
+       { USB_DEVICE_WACOM(0x10E) },
+       { USB_DEVICE_WACOM(0x10F) },
        { USB_DEVICE_WACOM(0x300) },
        { USB_DEVICE_WACOM(0x301) },
        { USB_DEVICE_WACOM(0x304) },
index fe302e3..c880eba 100644 (file)
@@ -52,7 +52,7 @@ config AMD_IOMMU
        select PCI_PRI
        select PCI_PASID
        select IOMMU_API
-       depends on X86_64 && PCI && ACPI && X86_IO_APIC
+       depends on X86_64 && PCI && ACPI
        ---help---
          With this option you can enable support for AMD IOMMU hardware in
          your system. An IOMMU is a hardware component which provides
index f417e89..181c9ba 100644 (file)
@@ -377,6 +377,7 @@ struct arm_smmu_cfg {
        u32                             cbar;
        pgd_t                           *pgd;
 };
+#define INVALID_IRPTNDX                        0xff
 
 #define ARM_SMMU_CB_ASID(cfg)          ((cfg)->cbndx)
 #define ARM_SMMU_CB_VMID(cfg)          ((cfg)->cbndx + 1)
@@ -840,7 +841,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
        if (IS_ERR_VALUE(ret)) {
                dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n",
                        root_cfg->irptndx, irq);
-               root_cfg->irptndx = -1;
+               root_cfg->irptndx = INVALID_IRPTNDX;
                goto out_free_context;
        }
 
@@ -869,7 +870,7 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
        writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR);
        arm_smmu_tlb_inv_context(root_cfg);
 
-       if (root_cfg->irptndx != -1) {
+       if (root_cfg->irptndx != INVALID_IRPTNDX) {
                irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
                free_irq(irq, domain);
        }
@@ -1857,8 +1858,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
                goto out_put_parent;
        }
 
-       arm_smmu_device_reset(smmu);
-
        for (i = 0; i < smmu->num_global_irqs; ++i) {
                err = request_irq(smmu->irqs[i],
                                  arm_smmu_global_fault,
@@ -1876,6 +1875,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
        spin_lock(&arm_smmu_devices_lock);
        list_add(&smmu->list, &arm_smmu_devices);
        spin_unlock(&arm_smmu_devices_lock);
+
+       arm_smmu_device_reset(smmu);
        return 0;
 
 out_free_irqs:
@@ -1966,10 +1967,10 @@ static int __init arm_smmu_init(void)
                return ret;
 
        /* Oh, for a proper bus abstraction */
-       if (!iommu_present(&platform_bus_type));
+       if (!iommu_present(&platform_bus_type))
                bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
 
-       if (!iommu_present(&amba_bustype));
+       if (!iommu_present(&amba_bustype))
                bus_set_iommu(&amba_bustype, &arm_smmu_ops);
 
        return 0;
index 71eb233..2a7f0dd 100644 (file)
@@ -996,10 +996,11 @@ static void request_write(struct cached_dev *dc, struct search *s)
                closure_bio_submit(bio, cl, s->d);
        } else {
                bch_writeback_add(dc);
+               s->op.cache_bio = bio;
 
                if (bio->bi_rw & REQ_FLUSH) {
                        /* Also need to send a flush to the backing device */
-                       struct bio *flush = bio_alloc_bioset(0, GFP_NOIO,
+                       struct bio *flush = bio_alloc_bioset(GFP_NOIO, 0,
                                                             dc->disk.bio_split);
 
                        flush->bi_rw    = WRITE_FLUSH;
@@ -1008,8 +1009,6 @@ static void request_write(struct cached_dev *dc, struct search *s)
                        flush->bi_private = cl;
 
                        closure_bio_submit(flush, cl, s->d);
-               } else {
-                       s->op.cache_bio = bio;
                }
        }
 out:
index 4caa8e6..2d2b1b7 100644 (file)
@@ -269,6 +269,14 @@ static chunk_t area_location(struct pstore *ps, chunk_t area)
        return NUM_SNAPSHOT_HDR_CHUNKS + ((ps->exceptions_per_area + 1) * area);
 }
 
+static void skip_metadata(struct pstore *ps)
+{
+       uint32_t stride = ps->exceptions_per_area + 1;
+       chunk_t next_free = ps->next_free;
+       if (sector_div(next_free, stride) == NUM_SNAPSHOT_HDR_CHUNKS)
+               ps->next_free++;
+}
+
 /*
  * Read or write a metadata area.  Remembering to skip the first
  * chunk which holds the header.
@@ -502,6 +510,8 @@ static int read_exceptions(struct pstore *ps,
 
        ps->current_area--;
 
+       skip_metadata(ps);
+
        return 0;
 }
 
@@ -616,8 +626,6 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
                                        struct dm_exception *e)
 {
        struct pstore *ps = get_info(store);
-       uint32_t stride;
-       chunk_t next_free;
        sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev);
 
        /* Is there enough room ? */
@@ -630,10 +638,8 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
         * Move onto the next free pending, making sure to take
         * into account the location of the metadata chunks.
         */
-       stride = (ps->exceptions_per_area + 1);
-       next_free = ++ps->next_free;
-       if (sector_div(next_free, stride) == 1)
-               ps->next_free++;
+       ps->next_free++;
+       skip_metadata(ps);
 
        atomic_inc(&ps->pending_count);
        return 0;
index adf4d7e..561a65f 100644 (file)
@@ -8111,6 +8111,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
        u64 *p;
        int lo, hi;
        int rv = 1;
+       unsigned long flags;
 
        if (bb->shift < 0)
                /* badblocks are disabled */
@@ -8125,7 +8126,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
                sectors = next - s;
        }
 
-       write_seqlock_irq(&bb->lock);
+       write_seqlock_irqsave(&bb->lock, flags);
 
        p = bb->page;
        lo = 0;
@@ -8241,7 +8242,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
        bb->changed = 1;
        if (!acknowledged)
                bb->unacked_exist = 1;
-       write_sequnlock_irq(&bb->lock);
+       write_sequnlock_irqrestore(&bb->lock, flags);
 
        return rv;
 }
index d60412c..aacf6bf 100644 (file)
@@ -1479,6 +1479,7 @@ static int raid1_spare_active(struct mddev *mddev)
                        }
                }
                if (rdev
+                   && rdev->recovery_offset == MaxSector
                    && !test_bit(Faulty, &rdev->flags)
                    && !test_and_set_bit(In_sync, &rdev->flags)) {
                        count++;
index df7b0a0..73dc8a3 100644 (file)
@@ -1782,6 +1782,7 @@ static int raid10_spare_active(struct mddev *mddev)
                        }
                        sysfs_notify_dirent_safe(tmp->replacement->sysfs_state);
                } else if (tmp->rdev
+                          && tmp->rdev->recovery_offset == MaxSector
                           && !test_bit(Faulty, &tmp->rdev->flags)
                           && !test_and_set_bit(In_sync, &tmp->rdev->flags)) {
                        count++;
index 7ff4f25..f8b9068 100644 (file)
@@ -778,6 +778,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                        bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
                        bi->bi_io_vec[0].bv_offset = 0;
                        bi->bi_size = STRIPE_SIZE;
+                       /*
+                        * If this is discard request, set bi_vcnt 0. We don't
+                        * want to confuse SCSI because SCSI will replace payload
+                        */
+                       if (rw & REQ_DISCARD)
+                               bi->bi_vcnt = 0;
                        if (rrdev)
                                set_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags);
 
@@ -816,6 +822,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                        rbi->bi_io_vec[0].bv_len = STRIPE_SIZE;
                        rbi->bi_io_vec[0].bv_offset = 0;
                        rbi->bi_size = STRIPE_SIZE;
+                       /*
+                        * If this is discard request, set bi_vcnt 0. We don't
+                        * want to confuse SCSI because SCSI will replace payload
+                        */
+                       if (rw & REQ_DISCARD)
+                               rbi->bi_vcnt = 0;
                        if (conf->mddev->gendisk)
                                trace_block_bio_remap(bdev_get_queue(rbi->bi_bdev),
                                                      rbi, disk_devt(conf->mddev->gendisk),
@@ -2910,6 +2922,14 @@ static void handle_stripe_clean_event(struct r5conf *conf,
                }
                /* now that discard is done we can proceed with any sync */
                clear_bit(STRIPE_DISCARD, &sh->state);
+               /*
+                * SCSI discard will change some bio fields and the stripe has
+                * no updated data, so remove it from hash list and the stripe
+                * will be reinitialized
+                */
+               spin_lock_irq(&conf->device_lock);
+               remove_hash(sh);
+               spin_unlock_irq(&conf->device_lock);
                if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state))
                        set_bit(STRIPE_HANDLE, &sh->state);
 
index 2521f7e..e79749c 100644 (file)
@@ -912,14 +912,8 @@ static int tda10071_init(struct dvb_frontend *fe)
                { 0xd5, 0x03, 0x03 },
        };
 
-       /* firmware status */
-       ret = tda10071_rd_reg(priv, 0x51, &tmp);
-       if (ret)
-               goto error;
-
-       if (!tmp) {
+       if (priv->warm) {
                /* warm state - wake up device from sleep */
-               priv->warm = 1;
 
                for (i = 0; i < ARRAY_SIZE(tab); i++) {
                        ret = tda10071_wr_reg_mask(priv, tab[i].reg,
@@ -937,7 +931,6 @@ static int tda10071_init(struct dvb_frontend *fe)
                        goto error;
        } else {
                /* cold state - try to download firmware */
-               priv->warm = 0;
 
                /* request the firmware, this will block and timeout */
                ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent);
index bb0c99d..b06a7e5 100644 (file)
@@ -628,16 +628,13 @@ static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable)
 
 static const struct v4l2_dv_timings_cap ad9389b_timings_cap = {
        .type = V4L2_DV_BT_656_1120,
-       .bt = {
-               .max_width = 1920,
-               .max_height = 1200,
-               .min_pixelclock = 25000000,
-               .max_pixelclock = 170000000,
-               .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+       /* keep this initialization for compatibility with GCC < 4.4.6 */
+       .reserved = { 0 },
+       V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
+               V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
-               .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
-                       V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM,
-       },
+               V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
+               V4L2_DV_BT_CAP_CUSTOM)
 };
 
 static int ad9389b_s_dv_timings(struct v4l2_subdev *sd,
index 7a57609..7c8d971 100644 (file)
@@ -119,16 +119,14 @@ static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
 
 static const struct v4l2_dv_timings_cap adv7511_timings_cap = {
        .type = V4L2_DV_BT_656_1120,
-       .bt = {
-               .max_width = ADV7511_MAX_WIDTH,
-               .max_height = ADV7511_MAX_HEIGHT,
-               .min_pixelclock = ADV7511_MIN_PIXELCLOCK,
-               .max_pixelclock = ADV7511_MAX_PIXELCLOCK,
-               .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+       /* keep this initialization for compatibility with GCC < 4.4.6 */
+       .reserved = { 0 },
+       V4L2_INIT_BT_TIMINGS(0, ADV7511_MAX_WIDTH, 0, ADV7511_MAX_HEIGHT,
+               ADV7511_MIN_PIXELCLOCK, ADV7511_MAX_PIXELCLOCK,
+               V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
-               .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
-                       V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM,
-       },
+               V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
+                       V4L2_DV_BT_CAP_CUSTOM)
 };
 
 static inline struct adv7511_state *get_adv7511_state(struct v4l2_subdev *sd)
@@ -1126,6 +1124,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
        state->i2c_edid = i2c_new_dummy(client->adapter, state->i2c_edid_addr >> 1);
        if (state->i2c_edid == NULL) {
                v4l2_err(sd, "failed to register edid i2c client\n");
+               err = -ENOMEM;
                goto err_entity;
        }
 
@@ -1133,6 +1132,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
        state->work_queue = create_singlethread_workqueue(sd->name);
        if (state->work_queue == NULL) {
                v4l2_err(sd, "could not create workqueue\n");
+               err = -ENOMEM;
                goto err_unreg_cec;
        }
 
index d174890..22f729d 100644 (file)
@@ -546,30 +546,24 @@ static inline bool is_digital_input(struct v4l2_subdev *sd)
 
 static const struct v4l2_dv_timings_cap adv7842_timings_cap_analog = {
        .type = V4L2_DV_BT_656_1120,
-       .bt = {
-               .max_width = 1920,
-               .max_height = 1200,
-               .min_pixelclock = 25000000,
-               .max_pixelclock = 170000000,
-               .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+       /* keep this initialization for compatibility with GCC < 4.4.6 */
+       .reserved = { 0 },
+       V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
+               V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
-               .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
-                       V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM,
-       },
+               V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
+                       V4L2_DV_BT_CAP_CUSTOM)
 };
 
 static const struct v4l2_dv_timings_cap adv7842_timings_cap_digital = {
        .type = V4L2_DV_BT_656_1120,
-       .bt = {
-               .max_width = 1920,
-               .max_height = 1200,
-               .min_pixelclock = 25000000,
-               .max_pixelclock = 225000000,
-               .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+       /* keep this initialization for compatibility with GCC < 4.4.6 */
+       .reserved = { 0 },
+       V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 225000000,
+               V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
-               .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
-                       V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM,
-       },
+               V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
+                       V4L2_DV_BT_CAP_CUSTOM)
 };
 
 static inline const struct v4l2_dv_timings_cap *
index a58a8f6..d9f65d7 100644 (file)
@@ -46,14 +46,10 @@ struct ths8200_state {
 
 static const struct v4l2_dv_timings_cap ths8200_timings_cap = {
        .type = V4L2_DV_BT_656_1120,
-       .bt = {
-               .max_width = 1920,
-               .max_height = 1080,
-               .min_pixelclock = 25000000,
-               .max_pixelclock = 148500000,
-               .standards = V4L2_DV_BT_STD_CEA861,
-               .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE,
-       },
+       /* keep this initialization for compatibility with GCC < 4.4.6 */
+       .reserved = { 0 },
+       V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1080, 25000000, 148500000,
+               V4L2_DV_BT_STD_CEA861, V4L2_DV_BT_CAP_PROGRESSIVE)
 };
 
 static inline struct ths8200_state *to_state(struct v4l2_subdev *sd)
index e12bbd8..fb60da8 100644 (file)
@@ -1455,6 +1455,7 @@ static int video_release(struct file *file)
 
        /* stop video capture */
        if (res_check(fh, RESOURCE_VIDEO)) {
+               pm_qos_remove_request(&dev->qos_request);
                videobuf_streamoff(&fh->cap);
                res_free(dev,fh,RESOURCE_VIDEO);
        }
index 15d2396..9b88a46 100644 (file)
@@ -1423,6 +1423,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
        jpeg->vfd_decoder->release      = video_device_release;
        jpeg->vfd_decoder->lock         = &jpeg->lock;
        jpeg->vfd_decoder->v4l2_dev     = &jpeg->v4l2_dev;
+       jpeg->vfd_decoder->vfl_dir      = VFL_DIR_M2M;
 
        ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
        if (ret) {
index 7a9c5e9..4f30341 100644 (file)
@@ -776,7 +776,7 @@ static int sh_vou_try_fmt_vid_out(struct file *file, void *priv,
        v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
                              &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
 
-       for (i = 0; ARRAY_SIZE(vou_fmt); i++)
+       for (i = 0; i < ARRAY_SIZE(vou_fmt); i++)
                if (vou_fmt[i].pfmt == pix->pixelformat)
                        return 0;
 
index 8f9f621..f975b70 100644 (file)
@@ -266,7 +266,6 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
        struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
        struct idmac_video_param *video = &ichan->params.video;
        const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt;
-       unsigned long flags;
        dma_cookie_t cookie;
        size_t new_size;
 
@@ -328,7 +327,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
                memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
 #endif
 
-       spin_lock_irqsave(&mx3_cam->lock, flags);
+       spin_lock_irq(&mx3_cam->lock);
        list_add_tail(&buf->queue, &mx3_cam->capture);
 
        if (!mx3_cam->active)
@@ -351,7 +350,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
        if (mx3_cam->active == buf)
                mx3_cam->active = NULL;
 
-       spin_unlock_irqrestore(&mx3_cam->lock, flags);
+       spin_unlock_irq(&mx3_cam->lock);
 error:
        vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
 }
index ad9309d..6c96e48 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include "e4000_priv.h"
+#include <linux/math64.h>
 
 /* write multiple registers */
 static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
@@ -233,7 +234,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
         * or more.
         */
        f_vco = c->frequency * e4000_pll_lut[i].mul;
-       sigma_delta = 0x10000UL * (f_vco % priv->cfg->clock) / priv->cfg->clock;
+       sigma_delta = div_u64(0x10000ULL * (f_vco % priv->cfg->clock), priv->cfg->clock);
        buf[0] = f_vco / priv->cfg->clock;
        buf[1] = (sigma_delta >> 0) & 0xff;
        buf[2] = (sigma_delta >> 8) & 0xff;
index c43c8d3..be77482 100644 (file)
@@ -111,6 +111,13 @@ static const struct dmi_system_id stk_upside_down_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "F3JC")
                }
        },
+       {
+               .ident = "T12Rg-H",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "HCL Infosystems Limited"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T12Rg-H")
+               }
+       },
        {}
 };
 
index 81695d4..c3bb250 100644 (file)
@@ -2090,6 +2090,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX },
+       /* Microsoft Lifecam NX-3000 */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x045e,
+         .idProduct            = 0x0721,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_DEF },
        /* Microsoft Lifecam VX-7000 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2174,6 +2183,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_DEF },
+       /* Dell SP2008WFP Monitor */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x05a9,
+         .idProduct            = 0x2641,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_DEF },
        /* Dell Alienware X51 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
index 594c75e..de0e87f 100644 (file)
@@ -353,7 +353,9 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 
                        if (b->m.planes[plane].bytesused > length)
                                return -EINVAL;
-                       if (b->m.planes[plane].data_offset >=
+
+                       if (b->m.planes[plane].data_offset > 0 &&
+                           b->m.planes[plane].data_offset >=
                            b->m.planes[plane].bytesused)
                                return -EINVAL;
                }
index fd56f25..646f08f 100644 (file)
@@ -423,6 +423,39 @@ static inline int vma_is_io(struct vm_area_struct *vma)
        return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
 }
 
+static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
+       struct vm_area_struct *vma, unsigned long *res)
+{
+       unsigned long pfn, start_pfn, prev_pfn;
+       unsigned int i;
+       int ret;
+
+       if (!vma_is_io(vma))
+               return -EFAULT;
+
+       ret = follow_pfn(vma, start, &pfn);
+       if (ret)
+               return ret;
+
+       start_pfn = pfn;
+       start += PAGE_SIZE;
+
+       for (i = 1; i < n_pages; ++i, start += PAGE_SIZE) {
+               prev_pfn = pfn;
+               ret = follow_pfn(vma, start, &pfn);
+
+               if (ret) {
+                       pr_err("no page for address %lu\n", start);
+                       return ret;
+               }
+               if (pfn != prev_pfn + 1)
+                       return -EINVAL;
+       }
+
+       *res = start_pfn;
+       return 0;
+}
+
 static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
        int n_pages, struct vm_area_struct *vma, int write)
 {
@@ -433,6 +466,9 @@ static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
                        unsigned long pfn;
                        int ret = follow_pfn(vma, start, &pfn);
 
+                       if (!pfn_valid(pfn))
+                               return -EINVAL;
+
                        if (ret) {
                                pr_err("no page for address %lu\n", start);
                                return ret;
@@ -468,16 +504,49 @@ static void vb2_dc_put_userptr(void *buf_priv)
        struct vb2_dc_buf *buf = buf_priv;
        struct sg_table *sgt = buf->dma_sgt;
 
-       dma_unmap_sg(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
-       if (!vma_is_io(buf->vma))
-               vb2_dc_sgt_foreach_page(sgt, vb2_dc_put_dirty_page);
+       if (sgt) {
+               dma_unmap_sg(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
+               if (!vma_is_io(buf->vma))
+                       vb2_dc_sgt_foreach_page(sgt, vb2_dc_put_dirty_page);
 
-       sg_free_table(sgt);
-       kfree(sgt);
+               sg_free_table(sgt);
+               kfree(sgt);
+       }
        vb2_put_vma(buf->vma);
        kfree(buf);
 }
 
+/*
+ * For some kind of reserved memory there might be no struct page available,
+ * so all that can be done to support such 'pages' is to try to convert
+ * pfn to dma address or at the last resort just assume that
+ * dma address == physical address (like it has been assumed in earlier version
+ * of videobuf2-dma-contig
+ */
+
+#ifdef __arch_pfn_to_dma
+static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn)
+{
+       return (dma_addr_t)__arch_pfn_to_dma(dev, pfn);
+}
+#elif defined(__pfn_to_bus)
+static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn)
+{
+       return (dma_addr_t)__pfn_to_bus(pfn);
+}
+#elif defined(__pfn_to_phys)
+static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn)
+{
+       return (dma_addr_t)__pfn_to_phys(pfn);
+}
+#else
+static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn)
+{
+       /* really, we cannot do anything better at this point */
+       return (dma_addr_t)(pfn) << PAGE_SHIFT;
+}
+#endif
+
 static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
        unsigned long size, int write)
 {
@@ -548,6 +617,14 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
        /* extract page list from userspace mapping */
        ret = vb2_dc_get_user_pages(start, pages, n_pages, vma, write);
        if (ret) {
+               unsigned long pfn;
+               if (vb2_dc_get_user_pfn(start, n_pages, vma, &pfn) == 0) {
+                       buf->dma_addr = vb2_dc_pfn_to_dma(buf->dev, pfn);
+                       buf->size = size;
+                       kfree(pages);
+                       return buf;
+               }
+
                pr_err("failed to get user pages\n");
                goto fail_vma;
        }
index 87ed3fb..f344659 100644 (file)
@@ -113,14 +113,14 @@ static const struct sh_mobile_sdhi_ops sdhi_ops = {
 };
 
 static const struct of_device_id sh_mobile_sdhi_of_match[] = {
-       { .compatible = "renesas,shmobile-sdhi" },
-       { .compatible = "renesas,sh7372-sdhi" },
-       { .compatible = "renesas,sh73a0-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,r8a73a4-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,r8a7740-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,r8a7778-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,r8a7779-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,r8a7790-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-shmobile" },
+       { .compatible = "renesas,sdhi-sh7372" },
+       { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7778", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7779", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7790", .data = &sh_mobile_sdhi_of_cfg[0], },
        {},
 };
 MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
index 26b14f9..6bc9618 100644 (file)
@@ -168,12 +168,25 @@ static inline int write_disable(struct m25p *flash)
  */
 static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
 {
+       int status;
+       bool need_wren = false;
+
        switch (JEDEC_MFR(jedec_id)) {
-       case CFI_MFR_MACRONIX:
        case CFI_MFR_ST: /* Micron, actually */
+               /* Some Micron need WREN command; all will accept it */
+               need_wren = true;
+       case CFI_MFR_MACRONIX:
        case 0xEF /* winbond */:
+               if (need_wren)
+                       write_enable(flash);
+
                flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
-               return spi_write(flash->spi, flash->command, 1);
+               status = spi_write(flash->spi, flash->command, 1);
+
+               if (need_wren)
+                       write_disable(flash);
+
+               return status;
        default:
                /* Spansion style */
                flash->command[0] = OPCODE_BRWR;
index 59ab069..a9830ff 100644 (file)
@@ -349,7 +349,7 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
 
 int common_nfc_set_geometry(struct gpmi_nand_data *this)
 {
-       return set_geometry_by_ecc_info(this) ? 0 : legacy_set_geometry(this);
+       return legacy_set_geometry(this);
 }
 
 struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
index 7ed4841..d340b2f 100644 (file)
@@ -2869,10 +2869,8 @@ static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
 
        len = le16_to_cpu(p->ext_param_page_length) * 16;
        ep = kmalloc(len, GFP_KERNEL);
-       if (!ep) {
-               ret = -ENOMEM;
-               goto ext_out;
-       }
+       if (!ep)
+               return -ENOMEM;
 
        /* Send our own NAND_CMD_PARAM. */
        chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
@@ -2920,7 +2918,7 @@ static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
        }
 
        pr_info("ONFI extended param page detected.\n");
-       return 0;
+       ret = 0;
 
 ext_out:
        kfree(ep);
index dd03dfd..c28d4e2 100644 (file)
@@ -1320,7 +1320,12 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
        for (cs = 0; cs < pdata->num_cs; cs++) {
                struct mtd_info *mtd = info->host[cs]->mtd;
 
-               mtd->name = pdev->name;
+               /*
+                * The mtd name matches the one used in 'mtdparts' kernel
+                * parameter. This name cannot be changed or otherwise
+                * user's mtd partitions configuration would get broken.
+                */
+               mtd->name = "pxa3xx_nand-0";
                info->cs = cs;
                ret = pxa3xx_nand_scan(mtd);
                if (ret) {
index 55bbb8b..e883bfe 100644 (file)
@@ -1724,6 +1724,7 @@ static int __bond_release_one(struct net_device *bond_dev,
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave, *oldcurrent;
        struct sockaddr addr;
+       int old_flags = bond_dev->flags;
        netdev_features_t old_features = bond_dev->features;
 
        /* slave is not a slave or master is not master of this slave */
@@ -1855,12 +1856,18 @@ static int __bond_release_one(struct net_device *bond_dev,
         * bond_change_active_slave(..., NULL)
         */
        if (!USES_PRIMARY(bond->params.mode)) {
-               /* unset promiscuity level from slave */
-               if (bond_dev->flags & IFF_PROMISC)
+               /* unset promiscuity level from slave
+                * NOTE: The NETDEV_CHANGEADDR call above may change the value
+                * of the IFF_PROMISC flag in the bond_dev, but we need the
+                * value of that flag before that change, as that was the value
+                * when this slave was attached, so we cache at the start of the
+                * function and use it here. Same goes for ALLMULTI below
+                */
+               if (old_flags & IFF_PROMISC)
                        dev_set_promiscuity(slave_dev, -1);
 
                /* unset allmulti level from slave */
-               if (bond_dev->flags & IFF_ALLMULTI)
+               if (old_flags & IFF_ALLMULTI)
                        dev_set_allmulti(slave_dev, -1);
 
                bond_hw_addr_flush(bond_dev, slave_dev);
index 3b1ff61..693d8ff 100644 (file)
@@ -1405,10 +1405,10 @@ static int at91_can_remove(struct platform_device *pdev)
 
 static const struct platform_device_id at91_can_id_table[] = {
        {
-               .name = "at91_can",
+               .name = "at91sam9x5_can",
                .driver_data = (kernel_ulong_t)&at91_at91sam9x5_data,
        }, {
-               .name = "at91sam9x5_can",
+               .name = "at91_can",
                .driver_data = (kernel_ulong_t)&at91_at91sam9263_data,
        }, {
                /* sentinel */
index f9cba41..1870c47 100644 (file)
@@ -705,14 +705,14 @@ static size_t can_get_size(const struct net_device *dev)
        size_t size;
 
        size = nla_total_size(sizeof(u32));   /* IFLA_CAN_STATE */
-       size += sizeof(struct can_ctrlmode);  /* IFLA_CAN_CTRLMODE */
+       size += nla_total_size(sizeof(struct can_ctrlmode));  /* IFLA_CAN_CTRLMODE */
        size += nla_total_size(sizeof(u32));  /* IFLA_CAN_RESTART_MS */
-       size += sizeof(struct can_bittiming); /* IFLA_CAN_BITTIMING */
-       size += sizeof(struct can_clock);     /* IFLA_CAN_CLOCK */
+       size += nla_total_size(sizeof(struct can_bittiming)); /* IFLA_CAN_BITTIMING */
+       size += nla_total_size(sizeof(struct can_clock));     /* IFLA_CAN_CLOCK */
        if (priv->do_get_berr_counter)        /* IFLA_CAN_BERR_COUNTER */
-               size += sizeof(struct can_berr_counter);
+               size += nla_total_size(sizeof(struct can_berr_counter));
        if (priv->bittiming_const)            /* IFLA_CAN_BITTIMING_CONST */
-               size += sizeof(struct can_bittiming_const);
+               size += nla_total_size(sizeof(struct can_bittiming_const));
 
        return size;
 }
index 71c677e..8f5ce74 100644 (file)
@@ -62,7 +62,7 @@
 #define FLEXCAN_MCR_BCC                        BIT(16)
 #define FLEXCAN_MCR_LPRIO_EN           BIT(13)
 #define FLEXCAN_MCR_AEN                        BIT(12)
-#define FLEXCAN_MCR_MAXMB(x)           ((x) & 0xf)
+#define FLEXCAN_MCR_MAXMB(x)           ((x) & 0x1f)
 #define FLEXCAN_MCR_IDAM_A             (0 << 8)
 #define FLEXCAN_MCR_IDAM_B             (1 << 8)
 #define FLEXCAN_MCR_IDAM_C             (2 << 8)
@@ -702,7 +702,6 @@ static int flexcan_chip_start(struct net_device *dev)
 {
        struct flexcan_priv *priv = netdev_priv(dev);
        struct flexcan_regs __iomem *regs = priv->base;
-       unsigned int i;
        int err;
        u32 reg_mcr, reg_ctrl;
 
@@ -736,9 +735,11 @@ static int flexcan_chip_start(struct net_device *dev)
         *
         */
        reg_mcr = flexcan_read(&regs->mcr);
+       reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
        reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
                FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
-               FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS;
+               FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
+               FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
        netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
        flexcan_write(reg_mcr, &regs->mcr);
 
@@ -772,16 +773,9 @@ static int flexcan_chip_start(struct net_device *dev)
        netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
        flexcan_write(reg_ctrl, &regs->ctrl);
 
-       for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) {
-               flexcan_write(0, &regs->cantxfg[i].can_ctrl);
-               flexcan_write(0, &regs->cantxfg[i].can_id);
-               flexcan_write(0, &regs->cantxfg[i].data[0]);
-               flexcan_write(0, &regs->cantxfg[i].data[1]);
-
-               /* put MB into rx queue */
-               flexcan_write(FLEXCAN_MB_CNT_CODE(0x4),
-                       &regs->cantxfg[i].can_ctrl);
-       }
+       /* Abort any pending TX, mark Mailbox as INACTIVE */
+       flexcan_write(FLEXCAN_MB_CNT_CODE(0x4),
+                     &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
 
        /* acceptance mask/acceptance code (accept everything) */
        flexcan_write(0x0, &regs->rxgmask);
@@ -991,9 +985,9 @@ static void unregister_flexcandev(struct net_device *dev)
 }
 
 static const struct of_device_id flexcan_of_match[] = {
-       { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
-       { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
        { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
+       { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
+       { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, flexcan_of_match);
index 874188b..25377e5 100644 (file)
@@ -76,6 +76,10 @@ MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces");
 /* maximum rx buffer len: extended CAN frame with timestamp */
 #define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1)
 
+#define SLC_CMD_LEN 1
+#define SLC_SFF_ID_LEN 3
+#define SLC_EFF_ID_LEN 8
+
 struct slcan {
        int                     magic;
 
@@ -142,47 +146,63 @@ static void slc_bump(struct slcan *sl)
 {
        struct sk_buff *skb;
        struct can_frame cf;
-       int i, dlc_pos, tmp;
-       unsigned long ultmp;
-       char cmd = sl->rbuff[0];
-
-       if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R'))
+       int i, tmp;
+       u32 tmpid;
+       char *cmd = sl->rbuff;
+
+       cf.can_id = 0;
+
+       switch (*cmd) {
+       case 'r':
+               cf.can_id = CAN_RTR_FLAG;
+               /* fallthrough */
+       case 't':
+               /* store dlc ASCII value and terminate SFF CAN ID string */
+               cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN];
+               sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN] = 0;
+               /* point to payload data behind the dlc */
+               cmd += SLC_CMD_LEN + SLC_SFF_ID_LEN + 1;
+               break;
+       case 'R':
+               cf.can_id = CAN_RTR_FLAG;
+               /* fallthrough */
+       case 'T':
+               cf.can_id |= CAN_EFF_FLAG;
+               /* store dlc ASCII value and terminate EFF CAN ID string */
+               cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN];
+               sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN] = 0;
+               /* point to payload data behind the dlc */
+               cmd += SLC_CMD_LEN + SLC_EFF_ID_LEN + 1;
+               break;
+       default:
                return;
+       }
 
-       if (cmd & 0x20) /* tiny chars 'r' 't' => standard frame format */
-               dlc_pos = 4; /* dlc position tiiid */
-       else
-               dlc_pos = 9; /* dlc position Tiiiiiiiid */
-
-       if (!((sl->rbuff[dlc_pos] >= '0') && (sl->rbuff[dlc_pos] < '9')))
+       if (kstrtou32(sl->rbuff + SLC_CMD_LEN, 16, &tmpid))
                return;
 
-       cf.can_dlc = sl->rbuff[dlc_pos] - '0'; /* get can_dlc from ASCII val */
+       cf.can_id |= tmpid;
 
-       sl->rbuff[dlc_pos] = 0; /* terminate can_id string */
-
-       if (kstrtoul(sl->rbuff+1, 16, &ultmp))
+       /* get can_dlc from sanitized ASCII value */
+       if (cf.can_dlc >= '0' && cf.can_dlc < '9')
+               cf.can_dlc -= '0';
+       else
                return;
 
-       cf.can_id = ultmp;
-
-       if (!(cmd & 0x20)) /* NO tiny chars => extended frame format */
-               cf.can_id |= CAN_EFF_FLAG;
-
-       if ((cmd | 0x20) == 'r') /* RTR frame */
-               cf.can_id |= CAN_RTR_FLAG;
-
        *(u64 *) (&cf.data) = 0; /* clear payload */
 
-       for (i = 0, dlc_pos++; i < cf.can_dlc; i++) {
-               tmp = hex_to_bin(sl->rbuff[dlc_pos++]);
-               if (tmp < 0)
-                       return;
-               cf.data[i] = (tmp << 4);
-               tmp = hex_to_bin(sl->rbuff[dlc_pos++]);
-               if (tmp < 0)
-                       return;
-               cf.data[i] |= tmp;
+       /* RTR frames may have a dlc > 0 but they never have any data bytes */
+       if (!(cf.can_id & CAN_RTR_FLAG)) {
+               for (i = 0; i < cf.can_dlc; i++) {
+                       tmp = hex_to_bin(*cmd++);
+                       if (tmp < 0)
+                               return;
+                       cf.data[i] = (tmp << 4);
+                       tmp = hex_to_bin(*cmd++);
+                       if (tmp < 0)
+                               return;
+                       cf.data[i] |= tmp;
+               }
        }
 
        skb = dev_alloc_skb(sizeof(struct can_frame) +
@@ -209,7 +229,6 @@ static void slc_bump(struct slcan *sl)
 /* parse tty input stream */
 static void slcan_unesc(struct slcan *sl, unsigned char s)
 {
-
        if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */
                if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
                    (sl->rcount > 4))  {
@@ -236,27 +255,46 @@ static void slcan_unesc(struct slcan *sl, unsigned char s)
 /* Encapsulate one can_frame and stuff into a TTY queue. */
 static void slc_encaps(struct slcan *sl, struct can_frame *cf)
 {
-       int actual, idx, i;
-       char cmd;
+       int actual, i;
+       unsigned char *pos;
+       unsigned char *endpos;
+       canid_t id = cf->can_id;
+
+       pos = sl->xbuff;
 
        if (cf->can_id & CAN_RTR_FLAG)
-               cmd = 'R'; /* becomes 'r' in standard frame format */
+               *pos = 'R'; /* becomes 'r' in standard frame format (SFF) */
        else
-               cmd = 'T'; /* becomes 't' in standard frame format */
+               *pos = 'T'; /* becomes 't' in standard frame format (SSF) */
 
-       if (cf->can_id & CAN_EFF_FLAG)
-               sprintf(sl->xbuff, "%c%08X%d", cmd,
-                       cf->can_id & CAN_EFF_MASK, cf->can_dlc);
-       else
-               sprintf(sl->xbuff, "%c%03X%d", cmd | 0x20,
-                       cf->can_id & CAN_SFF_MASK, cf->can_dlc);
+       /* determine number of chars for the CAN-identifier */
+       if (cf->can_id & CAN_EFF_FLAG) {
+               id &= CAN_EFF_MASK;
+               endpos = pos + SLC_EFF_ID_LEN;
+       } else {
+               *pos |= 0x20; /* convert R/T to lower case for SFF */
+               id &= CAN_SFF_MASK;
+               endpos = pos + SLC_SFF_ID_LEN;
+       }
 
-       idx = strlen(sl->xbuff);
+       /* build 3 (SFF) or 8 (EFF) digit CAN identifier */
+       pos++;
+       while (endpos >= pos) {
+               *endpos-- = hex_asc_upper[id & 0xf];
+               id >>= 4;
+       }
+
+       pos += (cf->can_id & CAN_EFF_FLAG) ? SLC_EFF_ID_LEN : SLC_SFF_ID_LEN;
 
-       for (i = 0; i < cf->can_dlc; i++)
-               sprintf(&sl->xbuff[idx + 2*i], "%02X", cf->data[i]);
+       *pos++ = cf->can_dlc + '0';
+
+       /* RTR frames may have a dlc > 0 but they never have any data bytes */
+       if (!(cf->can_id & CAN_RTR_FLAG)) {
+               for (i = 0; i < cf->can_dlc; i++)
+                       pos = hex_byte_pack_upper(pos, cf->data[i]);
+       }
 
-       strcat(sl->xbuff, "\r"); /* add terminating character */
+       *pos++ = '\r';
 
        /* Order of next two lines is *very* important.
         * When we are sending a little amount of data,
@@ -267,8 +305,8 @@ static void slc_encaps(struct slcan *sl, struct can_frame *cf)
         *       14 Oct 1994  Dmitry Gorodchanin.
         */
        set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
-       actual = sl->tty->ops->write(sl->tty, sl->xbuff, strlen(sl->xbuff));
-       sl->xleft = strlen(sl->xbuff) - actual;
+       actual = sl->tty->ops->write(sl->tty, sl->xbuff, pos - sl->xbuff);
+       sl->xleft = (pos - sl->xbuff) - actual;
        sl->xhead = sl->xbuff + actual;
        sl->dev->stats.tx_bytes += cf->can_dlc;
 }
@@ -286,11 +324,13 @@ static void slcan_write_wakeup(struct tty_struct *tty)
        if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
                return;
 
+       spin_lock(&sl->lock);
        if (sl->xleft <= 0)  {
                /* Now serial buffer is almost free & we can start
                 * transmission of another packet */
                sl->dev->stats.tx_packets++;
                clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+               spin_unlock(&sl->lock);
                netif_wake_queue(sl->dev);
                return;
        }
@@ -298,6 +338,7 @@ static void slcan_write_wakeup(struct tty_struct *tty)
        actual = tty->ops->write(tty, sl->xhead, sl->xleft);
        sl->xleft -= actual;
        sl->xhead += actual;
+       spin_unlock(&sl->lock);
 }
 
 /* Send a can_frame to a TTY queue. */
index a0f647f..0b7a4c3 100644 (file)
@@ -463,7 +463,7 @@ static int peak_usb_start(struct peak_usb_device *dev)
        if (i < PCAN_USB_MAX_TX_URBS) {
                if (i == 0) {
                        netdev_err(netdev, "couldn't setup any tx URB\n");
-                       return err;
+                       goto err_tx;
                }
 
                netdev_warn(netdev, "tx performance may be slow\n");
@@ -472,7 +472,7 @@ static int peak_usb_start(struct peak_usb_device *dev)
        if (dev->adapter->dev_start) {
                err = dev->adapter->dev_start(dev);
                if (err)
-                       goto failed;
+                       goto err_adapter;
        }
 
        dev->state |= PCAN_USB_STATE_STARTED;
@@ -481,19 +481,26 @@ static int peak_usb_start(struct peak_usb_device *dev)
        if (dev->adapter->dev_set_bus) {
                err = dev->adapter->dev_set_bus(dev, 1);
                if (err)
-                       goto failed;
+                       goto err_adapter;
        }
 
        dev->can.state = CAN_STATE_ERROR_ACTIVE;
 
        return 0;
 
-failed:
+err_adapter:
        if (err == -ENODEV)
                netif_device_detach(dev->netdev);
 
        netdev_warn(netdev, "couldn't submit control: %d\n", err);
 
+       for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) {
+               usb_free_urb(dev->tx_contexts[i].urb);
+               dev->tx_contexts[i].urb = NULL;
+       }
+err_tx:
+       usb_kill_anchored_urbs(&dev->rx_submitted);
+
        return err;
 }
 
index 97b3d32..c5e375d 100644 (file)
@@ -1197,8 +1197,9 @@ union cdu_context {
 /* TM (timers) host DB constants */
 #define TM_ILT_PAGE_SZ_HW      0
 #define TM_ILT_PAGE_SZ         (4096 << TM_ILT_PAGE_SZ_HW) /* 4K */
-/* #define TM_CONN_NUM         (CNIC_STARTING_CID+CNIC_ISCSI_CXT_MAX) */
-#define TM_CONN_NUM            1024
+#define TM_CONN_NUM            (BNX2X_FIRST_VF_CID + \
+                                BNX2X_VF_CIDS + \
+                                CNIC_ISCSI_CID_MAX)
 #define TM_ILT_SZ              (8 * TM_CONN_NUM)
 #define TM_ILT_LINES           DIV_ROUND_UP(TM_ILT_SZ, TM_ILT_PAGE_SZ)
 
@@ -1527,7 +1528,6 @@ struct bnx2x {
 #define PCI_32BIT_FLAG                 (1 << 1)
 #define ONE_PORT_FLAG                  (1 << 2)
 #define NO_WOL_FLAG                    (1 << 3)
-#define USING_DAC_FLAG                 (1 << 4)
 #define USING_MSIX_FLAG                        (1 << 5)
 #define USING_MSI_FLAG                 (1 << 6)
 #define DISABLE_MSI_FLAG               (1 << 7)
@@ -1621,7 +1621,7 @@ struct bnx2x {
        u16                     rx_ticks_int;
        u16                     rx_ticks;
 /* Maximal coalescing timeout in us */
-#define BNX2X_MAX_COALESCE_TOUT                (0xf0*12)
+#define BNX2X_MAX_COALESCE_TOUT                (0xff*BNX2X_BTR)
 
        u32                     lin_cnt;
 
@@ -2072,7 +2072,8 @@ u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
 
 void bnx2x_prep_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
                               u8 src_type, u8 dst_type);
-int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae);
+int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
+                              u32 *comp);
 
 /* FLR related routines */
 u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp);
@@ -2498,4 +2499,8 @@ enum bnx2x_pci_bus_speed {
 };
 
 void bnx2x_set_local_cmng(struct bnx2x *bp);
+
+#define MCPR_SCRATCH_BASE(bp) \
+       (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH)
+
 #endif /* bnx2x.h */
index 61726af..4ab4c89 100644 (file)
@@ -681,6 +681,7 @@ static void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                }
        }
 #endif
+       skb_record_rx_queue(skb, fp->rx_queue);
        napi_gro_receive(&fp->napi, skb);
 }
 
@@ -2481,8 +2482,7 @@ load_error_cnic2:
 load_error_cnic1:
        bnx2x_napi_disable_cnic(bp);
        /* Update the number of queues without the cnic queues */
-       rc = bnx2x_set_real_num_queues(bp, 0);
-       if (rc)
+       if (bnx2x_set_real_num_queues(bp, 0))
                BNX2X_ERR("Unable to set real_num_queues not including cnic\n");
 load_error_cnic0:
        BNX2X_ERR("CNIC-related load failed\n");
index 324de5f..e8efa1c 100644 (file)
@@ -891,17 +891,8 @@ static void bnx2x_get_regs(struct net_device *dev,
         * will re-enable parity attentions right after the dump.
         */
 
-       /* Disable parity on path 0 */
-       bnx2x_pretend_func(bp, 0);
        bnx2x_disable_blocks_parity(bp);
 
-       /* Disable parity on path 1 */
-       bnx2x_pretend_func(bp, 1);
-       bnx2x_disable_blocks_parity(bp);
-
-       /* Return to current function */
-       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
-
        dump_hdr.header_size = (sizeof(struct dump_header) / 4) - 1;
        dump_hdr.preset = DUMP_ALL_PRESETS;
        dump_hdr.version = BNX2X_DUMP_VERSION;
@@ -928,18 +919,9 @@ static void bnx2x_get_regs(struct net_device *dev,
        /* Actually read the registers */
        __bnx2x_get_regs(bp, p);
 
-       /* Re-enable parity attentions on path 0 */
-       bnx2x_pretend_func(bp, 0);
+       /* Re-enable parity attentions */
        bnx2x_clear_blocks_parity(bp);
        bnx2x_enable_blocks_parity(bp);
-
-       /* Re-enable parity attentions on path 1 */
-       bnx2x_pretend_func(bp, 1);
-       bnx2x_clear_blocks_parity(bp);
-       bnx2x_enable_blocks_parity(bp);
-
-       /* Return to current function */
-       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
 }
 
 static int bnx2x_get_preset_regs_len(struct net_device *dev, u32 preset)
@@ -993,17 +975,8 @@ static int bnx2x_get_dump_data(struct net_device *dev,
         * will re-enable parity attentions right after the dump.
         */
 
-       /* Disable parity on path 0 */
-       bnx2x_pretend_func(bp, 0);
        bnx2x_disable_blocks_parity(bp);
 
-       /* Disable parity on path 1 */
-       bnx2x_pretend_func(bp, 1);
-       bnx2x_disable_blocks_parity(bp);
-
-       /* Return to current function */
-       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
-
        dump_hdr.header_size = (sizeof(struct dump_header) / 4) - 1;
        dump_hdr.preset = bp->dump_preset_idx;
        dump_hdr.version = BNX2X_DUMP_VERSION;
@@ -1032,19 +1005,10 @@ static int bnx2x_get_dump_data(struct net_device *dev,
        /* Actually read the registers */
        __bnx2x_get_preset_regs(bp, p, dump_hdr.preset);
 
-       /* Re-enable parity attentions on path 0 */
-       bnx2x_pretend_func(bp, 0);
+       /* Re-enable parity attentions */
        bnx2x_clear_blocks_parity(bp);
        bnx2x_enable_blocks_parity(bp);
 
-       /* Re-enable parity attentions on path 1 */
-       bnx2x_pretend_func(bp, 1);
-       bnx2x_clear_blocks_parity(bp);
-       bnx2x_enable_blocks_parity(bp);
-
-       /* Return to current function */
-       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
-
        return 0;
 }
 
index 76df015..c2dfea7 100644 (file)
@@ -640,23 +640,35 @@ static const struct {
  * [30] MCP Latched ump_tx_parity
  * [31] MCP Latched scpad_parity
  */
-#define MISC_AEU_ENABLE_MCP_PRTY_BITS  \
+#define MISC_AEU_ENABLE_MCP_PRTY_SUB_BITS      \
        (AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY | \
         AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY | \
-        AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY | \
+        AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY)
+
+#define MISC_AEU_ENABLE_MCP_PRTY_BITS  \
+       (MISC_AEU_ENABLE_MCP_PRTY_SUB_BITS | \
         AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY)
 
 /* Below registers control the MCP parity attention output. When
  * MISC_AEU_ENABLE_MCP_PRTY_BITS are set - attentions are
  * enabled, when cleared - disabled.
  */
-static const u32 mcp_attn_ctl_regs[] = {
-       MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0,
-       MISC_REG_AEU_ENABLE4_NIG_0,
-       MISC_REG_AEU_ENABLE4_PXP_0,
-       MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0,
-       MISC_REG_AEU_ENABLE4_NIG_1,
-       MISC_REG_AEU_ENABLE4_PXP_1
+static const struct {
+       u32 addr;
+       u32 bits;
+} mcp_attn_ctl_regs[] = {
+       { MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0,
+               MISC_AEU_ENABLE_MCP_PRTY_BITS },
+       { MISC_REG_AEU_ENABLE4_NIG_0,
+               MISC_AEU_ENABLE_MCP_PRTY_SUB_BITS },
+       { MISC_REG_AEU_ENABLE4_PXP_0,
+               MISC_AEU_ENABLE_MCP_PRTY_SUB_BITS },
+       { MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0,
+               MISC_AEU_ENABLE_MCP_PRTY_BITS },
+       { MISC_REG_AEU_ENABLE4_NIG_1,
+               MISC_AEU_ENABLE_MCP_PRTY_SUB_BITS },
+       { MISC_REG_AEU_ENABLE4_PXP_1,
+               MISC_AEU_ENABLE_MCP_PRTY_SUB_BITS }
 };
 
 static inline void bnx2x_set_mcp_parity(struct bnx2x *bp, u8 enable)
@@ -665,14 +677,14 @@ static inline void bnx2x_set_mcp_parity(struct bnx2x *bp, u8 enable)
        u32 reg_val;
 
        for (i = 0; i < ARRAY_SIZE(mcp_attn_ctl_regs); i++) {
-               reg_val = REG_RD(bp, mcp_attn_ctl_regs[i]);
+               reg_val = REG_RD(bp, mcp_attn_ctl_regs[i].addr);
 
                if (enable)
-                       reg_val |= MISC_AEU_ENABLE_MCP_PRTY_BITS;
+                       reg_val |= mcp_attn_ctl_regs[i].bits;
                else
-                       reg_val &= ~MISC_AEU_ENABLE_MCP_PRTY_BITS;
+                       reg_val &= ~mcp_attn_ctl_regs[i].bits;
 
-               REG_WR(bp, mcp_attn_ctl_regs[i], reg_val);
+               REG_WR(bp, mcp_attn_ctl_regs[i].addr, reg_val);
        }
 }
 
index d60a2ea..5146822 100644 (file)
@@ -175,6 +175,7 @@ typedef int (*read_sfp_module_eeprom_func_p)(struct bnx2x_phy *phy,
 #define EDC_MODE_LINEAR                                0x0022
 #define EDC_MODE_LIMITING                              0x0044
 #define EDC_MODE_PASSIVE_DAC                   0x0055
+#define EDC_MODE_ACTIVE_DAC                    0x0066
 
 /* ETS defines*/
 #define DCBX_INVALID_COS                                       (0xFF)
@@ -3684,6 +3685,41 @@ static void bnx2x_warpcore_enable_AN_KR2(struct bnx2x_phy *phy,
        bnx2x_update_link_attr(params, vars->link_attr_sync);
 }
 
+static void bnx2x_disable_kr2(struct link_params *params,
+                             struct link_vars *vars,
+                             struct bnx2x_phy *phy)
+{
+       struct bnx2x *bp = params->bp;
+       int i;
+       static struct bnx2x_reg_set reg_set[] = {
+               /* Step 1 - Program the TX/RX alignment markers */
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL5, 0x7690},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL7, 0xe647},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL6, 0xc4f0},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL9, 0x7690},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL11, 0xe647},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL10, 0xc4f0},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_USERB0_CTRL, 0x000c},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL1, 0x6000},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL3, 0x0000},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CODE_FIELD, 0x0002},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI1, 0x0000},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI2, 0x0af7},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI3, 0x0af7},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_BAM_CODE, 0x0002},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_UD_CODE, 0x0000}
+       };
+       DP(NETIF_MSG_LINK, "Disabling 20G-KR2\n");
+
+       for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+               bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
+                                reg_set[i].val);
+       vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
+       bnx2x_update_link_attr(params, vars->link_attr_sync);
+
+       vars->check_kr2_recovery_cnt = CHECK_KR2_RECOVERY_CNT;
+}
+
 static void bnx2x_warpcore_set_lpi_passthrough(struct bnx2x_phy *phy,
                                               struct link_params *params)
 {
@@ -3715,7 +3751,6 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
                                        struct link_params *params,
                                        struct link_vars *vars) {
        u16 lane, i, cl72_ctrl, an_adv = 0;
-       u16 ucode_ver;
        struct bnx2x *bp = params->bp;
        static struct bnx2x_reg_set reg_set[] = {
                {MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7},
@@ -3806,15 +3841,7 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
 
        /* Advertise pause */
        bnx2x_ext_phy_set_pause(params, phy, vars);
-       /* Set KR Autoneg Work-Around flag for Warpcore version older than D108
-        */
-       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-                       MDIO_WC_REG_UC_INFO_B1_VERSION, &ucode_ver);
-       if (ucode_ver < 0xd108) {
-               DP(NETIF_MSG_LINK, "Enable AN KR work-around. WC ver:0x%x\n",
-                              ucode_ver);
-               vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
-       }
+       vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
        bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
                                 MDIO_WC_REG_DIGITAL5_MISC7, 0x100);
 
@@ -3838,6 +3865,8 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
                bnx2x_set_aer_mmd(params, phy);
 
                bnx2x_warpcore_enable_AN_KR2(phy, params, vars);
+       } else {
+               bnx2x_disable_kr2(params, vars, phy);
        }
 
        /* Enable Autoneg: only on the main lane */
@@ -4347,20 +4376,14 @@ static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
        struct bnx2x *bp = params->bp;
        u32 serdes_net_if;
        u16 gp_status1 = 0, lnkup = 0, lnkup_kr = 0;
-       u16 lane = bnx2x_get_warpcore_lane(phy, params);
 
        vars->turn_to_run_wc_rt = vars->turn_to_run_wc_rt ? 0 : 1;
 
        if (!vars->turn_to_run_wc_rt)
                return;
 
-       /* Return if there is no link partner */
-       if (!(bnx2x_warpcore_get_sigdet(phy, params))) {
-               DP(NETIF_MSG_LINK, "bnx2x_warpcore_get_sigdet false\n");
-               return;
-       }
-
        if (vars->rx_tx_asic_rst) {
+               u16 lane = bnx2x_get_warpcore_lane(phy, params);
                serdes_net_if = (REG_RD(bp, params->shmem_base +
                                offsetof(struct shmem_region, dev_info.
                                port_hw_config[params->port].default_cfg)) &
@@ -4375,14 +4398,8 @@ static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
                                /*10G KR*/
                        lnkup_kr = (gp_status1 >> (12+lane)) & 0x1;
 
-                       DP(NETIF_MSG_LINK,
-                               "gp_status1 0x%x\n", gp_status1);
-
                        if (lnkup_kr || lnkup) {
-                                       vars->rx_tx_asic_rst = 0;
-                                       DP(NETIF_MSG_LINK,
-                                       "link up, rx_tx_asic_rst 0x%x\n",
-                                       vars->rx_tx_asic_rst);
+                               vars->rx_tx_asic_rst = 0;
                        } else {
                                /* Reset the lane to see if link comes up.*/
                                bnx2x_warpcore_reset_lane(bp, phy, 1);
@@ -4507,10 +4524,14 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
                         * enabled transmitter to avoid current leakage in case
                         * no module is connected
                         */
-                       if (bnx2x_is_sfp_module_plugged(phy, params))
-                               bnx2x_sfp_module_detection(phy, params);
-                       else
-                               bnx2x_sfp_e3_set_transmitter(params, phy, 1);
+                       if ((params->loopback_mode == LOOPBACK_NONE) ||
+                           (params->loopback_mode == LOOPBACK_EXT)) {
+                               if (bnx2x_is_sfp_module_plugged(phy, params))
+                                       bnx2x_sfp_module_detection(phy, params);
+                               else
+                                       bnx2x_sfp_e3_set_transmitter(params,
+                                                                    phy, 1);
+                       }
 
                        bnx2x_warpcore_config_sfi(phy, params);
                        break;
@@ -5757,6 +5778,11 @@ static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
        rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, gp_speed,
                                         duplex);
 
+       /* In case of KR link down, start up the recovering procedure */
+       if ((!link_up) && (phy->media_type == ETH_PHY_KR) &&
+           (!(phy->flags & FLAGS_WC_DUAL_MODE)))
+               vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
+
        DP(NETIF_MSG_LINK, "duplex %x  flow_ctrl 0x%x link_status 0x%x\n",
                   vars->duplex, vars->flow_ctrl, vars->link_status);
        return rc;
@@ -6507,6 +6533,11 @@ static int bnx2x_link_initialize(struct link_params *params,
                        params->phy[INT_PHY].config_init(phy, params, vars);
        }
 
+       /* Re-read this value in case it was changed inside config_init due to
+        * limitations of optic module
+        */
+       vars->line_speed = params->phy[INT_PHY].req_line_speed;
+
        /* Init external phy*/
        if (non_ext_phy) {
                if (params->phy[INT_PHY].supported &
@@ -8080,7 +8111,10 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
                if (copper_module_type &
                    SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
                        DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
-                       check_limiting_mode = 1;
+                       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
+                               *edc_mode = EDC_MODE_ACTIVE_DAC;
+                       else
+                               check_limiting_mode = 1;
                } else if (copper_module_type &
                        SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
                                DP(NETIF_MSG_LINK,
@@ -8555,6 +8589,7 @@ static void bnx2x_warpcore_set_limiting_mode(struct link_params *params,
                mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
                break;
        case EDC_MODE_PASSIVE_DAC:
+       case EDC_MODE_ACTIVE_DAC:
                mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_DAC;
                break;
        default:
@@ -9730,32 +9765,41 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
                         MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
                         an_1000_val);
 
-       /* set 100 speed advertisement */
-       if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
-            (phy->speed_cap_mask &
-             (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
-              PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF))) {
-               an_10_100_val |= (1<<7);
-               /* Enable autoneg and restart autoneg for legacy speeds */
-               autoneg_val |= (1<<9 | 1<<12);
-
-               if (phy->req_duplex == DUPLEX_FULL)
+       /* Set 10/100 speed advertisement */
+       if (phy->req_line_speed == SPEED_AUTO_NEG) {
+               if (phy->speed_cap_mask &
+                   PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL) {
+                       /* Enable autoneg and restart autoneg for legacy speeds
+                        */
+                       autoneg_val |= (1<<9 | 1<<12);
                        an_10_100_val |= (1<<8);
-               DP(NETIF_MSG_LINK, "Advertising 100M\n");
-       }
-       /* set 10 speed advertisement */
-       if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
-            (phy->speed_cap_mask &
-             (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
-              PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) &&
-            (phy->supported &
-             (SUPPORTED_10baseT_Half |
-              SUPPORTED_10baseT_Full)))) {
-               an_10_100_val |= (1<<5);
-               autoneg_val |= (1<<9 | 1<<12);
-               if (phy->req_duplex == DUPLEX_FULL)
+                       DP(NETIF_MSG_LINK, "Advertising 100M-FD\n");
+               }
+
+               if (phy->speed_cap_mask &
+                   PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF) {
+                       /* Enable autoneg and restart autoneg for legacy speeds
+                        */
+                       autoneg_val |= (1<<9 | 1<<12);
+                       an_10_100_val |= (1<<7);
+                       DP(NETIF_MSG_LINK, "Advertising 100M-HD\n");
+               }
+
+               if ((phy->speed_cap_mask &
+                    PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
+                   (phy->supported & SUPPORTED_10baseT_Full)) {
                        an_10_100_val |= (1<<6);
-               DP(NETIF_MSG_LINK, "Advertising 10M\n");
+                       autoneg_val |= (1<<9 | 1<<12);
+                       DP(NETIF_MSG_LINK, "Advertising 10M-FD\n");
+               }
+
+               if ((phy->speed_cap_mask &
+                    PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF) &&
+                   (phy->supported & SUPPORTED_10baseT_Half)) {
+                       an_10_100_val |= (1<<5);
+                       autoneg_val |= (1<<9 | 1<<12);
+                       DP(NETIF_MSG_LINK, "Advertising 10M-HD\n");
+               }
        }
 
        /* Only 10/100 are allowed to work in FORCE mode */
@@ -13432,43 +13476,6 @@ static void bnx2x_sfp_tx_fault_detection(struct bnx2x_phy *phy,
                }
        }
 }
-static void bnx2x_disable_kr2(struct link_params *params,
-                             struct link_vars *vars,
-                             struct bnx2x_phy *phy)
-{
-       struct bnx2x *bp = params->bp;
-       int i;
-       static struct bnx2x_reg_set reg_set[] = {
-               /* Step 1 - Program the TX/RX alignment markers */
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL5, 0x7690},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL7, 0xe647},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL6, 0xc4f0},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL9, 0x7690},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL11, 0xe647},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL10, 0xc4f0},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_USERB0_CTRL, 0x000c},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL1, 0x6000},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL3, 0x0000},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CODE_FIELD, 0x0002},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI1, 0x0000},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI2, 0x0af7},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI3, 0x0af7},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_BAM_CODE, 0x0002},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_UD_CODE, 0x0000}
-       };
-       DP(NETIF_MSG_LINK, "Disabling 20G-KR2\n");
-
-       for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-               bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
-                                reg_set[i].val);
-       vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
-       bnx2x_update_link_attr(params, vars->link_attr_sync);
-
-       vars->check_kr2_recovery_cnt = CHECK_KR2_RECOVERY_CNT;
-       /* Restart AN on leading lane */
-       bnx2x_warpcore_restart_AN_KR(phy, params);
-}
-
 static void bnx2x_kr2_recovery(struct link_params *params,
                               struct link_vars *vars,
                               struct bnx2x_phy *phy)
@@ -13546,6 +13553,8 @@ static void bnx2x_check_kr2_wa(struct link_params *params,
                /* Disable KR2 on both lanes */
                DP(NETIF_MSG_LINK, "BP=0x%x, NP=0x%x\n", base_page, next_page);
                bnx2x_disable_kr2(params, vars, phy);
+               /* Restart AN on leading lane */
+               bnx2x_warpcore_restart_AN_KR(phy, params);
                return;
        }
 }
index a6704b5..b42f89c 100644 (file)
@@ -503,9 +503,9 @@ void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
 }
 
 /* issue a dmae command over the init-channel and wait for completion */
-int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae)
+int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
+                              u32 *comp)
 {
-       u32 *wb_comp = bnx2x_sp(bp, wb_comp);
        int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 4000;
        int rc = 0;
 
@@ -518,14 +518,14 @@ int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae)
        spin_lock_bh(&bp->dmae_lock);
 
        /* reset completion */
-       *wb_comp = 0;
+       *comp = 0;
 
        /* post the command on the channel used for initializations */
        bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
 
        /* wait for completion */
        udelay(5);
-       while ((*wb_comp & ~DMAE_PCI_ERR_FLAG) != DMAE_COMP_VAL) {
+       while ((*comp & ~DMAE_PCI_ERR_FLAG) != DMAE_COMP_VAL) {
 
                if (!cnt ||
                    (bp->recovery_state != BNX2X_RECOVERY_DONE &&
@@ -537,7 +537,7 @@ int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae)
                cnt--;
                udelay(50);
        }
-       if (*wb_comp & DMAE_PCI_ERR_FLAG) {
+       if (*comp & DMAE_PCI_ERR_FLAG) {
                BNX2X_ERR("DMAE PCI error!\n");
                rc = DMAE_PCI_ERROR;
        }
@@ -574,7 +574,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
        dmae.len = len32;
 
        /* issue the command and wait for completion */
-       rc = bnx2x_issue_dmae_with_comp(bp, &dmae);
+       rc = bnx2x_issue_dmae_with_comp(bp, &dmae, bnx2x_sp(bp, wb_comp));
        if (rc) {
                BNX2X_ERR("DMAE returned failure %d\n", rc);
                bnx2x_panic();
@@ -611,7 +611,7 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
        dmae.len = len32;
 
        /* issue the command and wait for completion */
-       rc = bnx2x_issue_dmae_with_comp(bp, &dmae);
+       rc = bnx2x_issue_dmae_with_comp(bp, &dmae, bnx2x_sp(bp, wb_comp));
        if (rc) {
                BNX2X_ERR("DMAE returned failure %d\n", rc);
                bnx2x_panic();
@@ -751,6 +751,10 @@ static int bnx2x_mc_assert(struct bnx2x *bp)
        return rc;
 }
 
+#define MCPR_TRACE_BUFFER_SIZE (0x800)
+#define SCRATCH_BUFFER_SIZE(bp)        \
+       (CHIP_IS_E1(bp) ? 0x10000 : (CHIP_IS_E1H(bp) ? 0x20000 : 0x28000))
+
 void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
 {
        u32 addr, val;
@@ -775,7 +779,17 @@ void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
                trace_shmem_base = bp->common.shmem_base;
        else
                trace_shmem_base = SHMEM2_RD(bp, other_shmem_base_addr);
-       addr = trace_shmem_base - 0x800;
+
+       /* sanity */
+       if (trace_shmem_base < MCPR_SCRATCH_BASE(bp) + MCPR_TRACE_BUFFER_SIZE ||
+           trace_shmem_base >= MCPR_SCRATCH_BASE(bp) +
+                               SCRATCH_BUFFER_SIZE(bp)) {
+               BNX2X_ERR("Unable to dump trace buffer (mark %x)\n",
+                         trace_shmem_base);
+               return;
+       }
+
+       addr = trace_shmem_base - MCPR_TRACE_BUFFER_SIZE;
 
        /* validate TRCB signature */
        mark = REG_RD(bp, addr);
@@ -787,14 +801,17 @@ void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
        /* read cyclic buffer pointer */
        addr += 4;
        mark = REG_RD(bp, addr);
-       mark = (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH)
-                       + ((mark + 0x3) & ~0x3) - 0x08000000;
+       mark = MCPR_SCRATCH_BASE(bp) + ((mark + 0x3) & ~0x3) - 0x08000000;
+       if (mark >= trace_shmem_base || mark < addr + 4) {
+               BNX2X_ERR("Mark doesn't fall inside Trace Buffer\n");
+               return;
+       }
        printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark);
 
        printk("%s", lvl);
 
        /* dump buffer after the mark */
-       for (offset = mark; offset <= trace_shmem_base; offset += 0x8*4) {
+       for (offset = mark; offset < trace_shmem_base; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
                        data[word] = htonl(REG_RD(bp, offset + 4*word));
                data[8] = 0x0;
@@ -4280,65 +4297,60 @@ static void _print_next_block(int idx, const char *blk)
        pr_cont("%s%s", idx ? ", " : "", blk);
 }
 
-static int bnx2x_check_blocks_with_parity0(struct bnx2x *bp, u32 sig,
-                                           int par_num, bool print)
+static bool bnx2x_check_blocks_with_parity0(struct bnx2x *bp, u32 sig,
+                                           int *par_num, bool print)
 {
-       int i = 0;
-       u32 cur_bit = 0;
+       u32 cur_bit;
+       bool res;
+       int i;
+
+       res = false;
+
        for (i = 0; sig; i++) {
-               cur_bit = ((u32)0x1 << i);
+               cur_bit = (0x1UL << i);
                if (sig & cur_bit) {
-                       switch (cur_bit) {
-                       case AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "BRB");
+                       res |= true; /* Each bit is real error! */
+
+                       if (print) {
+                               switch (cur_bit) {
+                               case AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "BRB");
                                        _print_parity(bp,
                                                      BRB1_REG_BRB1_PRTY_STS);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "PARSER");
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR:
+                                       _print_next_block((*par_num)++,
+                                                         "PARSER");
                                        _print_parity(bp, PRS_REG_PRS_PRTY_STS);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "TSDM");
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "TSDM");
                                        _print_parity(bp,
                                                      TSDM_REG_TSDM_PRTY_STS);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++,
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR:
+                                       _print_next_block((*par_num)++,
                                                          "SEARCHER");
                                        _print_parity(bp, SRC_REG_SRC_PRTY_STS);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_TCM_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "TCM");
-                                       _print_parity(bp,
-                                                     TCM_REG_TCM_PRTY_STS);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "TSEMI");
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_TCM_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "TCM");
+                                       _print_parity(bp, TCM_REG_TCM_PRTY_STS);
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR:
+                                       _print_next_block((*par_num)++,
+                                                         "TSEMI");
                                        _print_parity(bp,
                                                      TSEM_REG_TSEM_PRTY_STS_0);
                                        _print_parity(bp,
                                                      TSEM_REG_TSEM_PRTY_STS_1);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "XPB");
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "XPB");
                                        _print_parity(bp, GRCBASE_XPB +
                                                          PB_REG_PB_PRTY_STS);
+                                       break;
                                }
-                               break;
                        }
 
                        /* Clear the bit */
@@ -4346,53 +4358,59 @@ static int bnx2x_check_blocks_with_parity0(struct bnx2x *bp, u32 sig,
                }
        }
 
-       return par_num;
+       return res;
 }
 
-static int bnx2x_check_blocks_with_parity1(struct bnx2x *bp, u32 sig,
-                                           int par_num, bool *global,
+static bool bnx2x_check_blocks_with_parity1(struct bnx2x *bp, u32 sig,
+                                           int *par_num, bool *global,
                                            bool print)
 {
-       int i = 0;
-       u32 cur_bit = 0;
+       u32 cur_bit;
+       bool res;
+       int i;
+
+       res = false;
+
        for (i = 0; sig; i++) {
-               cur_bit = ((u32)0x1 << i);
+               cur_bit = (0x1UL << i);
                if (sig & cur_bit) {
+                       res |= true; /* Each bit is real error! */
                        switch (cur_bit) {
                        case AEU_INPUTS_ATTN_BITS_PBF_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "PBF");
+                                       _print_next_block((*par_num)++, "PBF");
                                        _print_parity(bp, PBF_REG_PBF_PRTY_STS);
                                }
                                break;
                        case AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "QM");
+                                       _print_next_block((*par_num)++, "QM");
                                        _print_parity(bp, QM_REG_QM_PRTY_STS);
                                }
                                break;
                        case AEU_INPUTS_ATTN_BITS_TIMERS_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "TM");
+                                       _print_next_block((*par_num)++, "TM");
                                        _print_parity(bp, TM_REG_TM_PRTY_STS);
                                }
                                break;
                        case AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "XSDM");
+                                       _print_next_block((*par_num)++, "XSDM");
                                        _print_parity(bp,
                                                      XSDM_REG_XSDM_PRTY_STS);
                                }
                                break;
                        case AEU_INPUTS_ATTN_BITS_XCM_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "XCM");
+                                       _print_next_block((*par_num)++, "XCM");
                                        _print_parity(bp, XCM_REG_XCM_PRTY_STS);
                                }
                                break;
                        case AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "XSEMI");
+                                       _print_next_block((*par_num)++,
+                                                         "XSEMI");
                                        _print_parity(bp,
                                                      XSEM_REG_XSEM_PRTY_STS_0);
                                        _print_parity(bp,
@@ -4401,7 +4419,7 @@ static int bnx2x_check_blocks_with_parity1(struct bnx2x *bp, u32 sig,
                                break;
                        case AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++,
+                                       _print_next_block((*par_num)++,
                                                          "DOORBELLQ");
                                        _print_parity(bp,
                                                      DORQ_REG_DORQ_PRTY_STS);
@@ -4409,7 +4427,7 @@ static int bnx2x_check_blocks_with_parity1(struct bnx2x *bp, u32 sig,
                                break;
                        case AEU_INPUTS_ATTN_BITS_NIG_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "NIG");
+                                       _print_next_block((*par_num)++, "NIG");
                                        if (CHIP_IS_E1x(bp)) {
                                                _print_parity(bp,
                                                        NIG_REG_NIG_PRTY_STS);
@@ -4423,32 +4441,34 @@ static int bnx2x_check_blocks_with_parity1(struct bnx2x *bp, u32 sig,
                                break;
                        case AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR:
                                if (print)
-                                       _print_next_block(par_num++,
+                                       _print_next_block((*par_num)++,
                                                          "VAUX PCI CORE");
                                *global = true;
                                break;
                        case AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "DEBUG");
+                                       _print_next_block((*par_num)++,
+                                                         "DEBUG");
                                        _print_parity(bp, DBG_REG_DBG_PRTY_STS);
                                }
                                break;
                        case AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "USDM");
+                                       _print_next_block((*par_num)++, "USDM");
                                        _print_parity(bp,
                                                      USDM_REG_USDM_PRTY_STS);
                                }
                                break;
                        case AEU_INPUTS_ATTN_BITS_UCM_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "UCM");
+                                       _print_next_block((*par_num)++, "UCM");
                                        _print_parity(bp, UCM_REG_UCM_PRTY_STS);
                                }
                                break;
                        case AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "USEMI");
+                                       _print_next_block((*par_num)++,
+                                                         "USEMI");
                                        _print_parity(bp,
                                                      USEM_REG_USEM_PRTY_STS_0);
                                        _print_parity(bp,
@@ -4457,21 +4477,21 @@ static int bnx2x_check_blocks_with_parity1(struct bnx2x *bp, u32 sig,
                                break;
                        case AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "UPB");
+                                       _print_next_block((*par_num)++, "UPB");
                                        _print_parity(bp, GRCBASE_UPB +
                                                          PB_REG_PB_PRTY_STS);
                                }
                                break;
                        case AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "CSDM");
+                                       _print_next_block((*par_num)++, "CSDM");
                                        _print_parity(bp,
                                                      CSDM_REG_CSDM_PRTY_STS);
                                }
                                break;
                        case AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR:
                                if (print) {
-                                       _print_next_block(par_num++, "CCM");
+                                       _print_next_block((*par_num)++, "CCM");
                                        _print_parity(bp, CCM_REG_CCM_PRTY_STS);
                                }
                                break;
@@ -4482,80 +4502,73 @@ static int bnx2x_check_blocks_with_parity1(struct bnx2x *bp, u32 sig,
                }
        }
 
-       return par_num;
+       return res;
 }
 
-static int bnx2x_check_blocks_with_parity2(struct bnx2x *bp, u32 sig,
-                                           int par_num, bool print)
+static bool bnx2x_check_blocks_with_parity2(struct bnx2x *bp, u32 sig,
+                                           int *par_num, bool print)
 {
-       int i = 0;
-       u32 cur_bit = 0;
+       u32 cur_bit;
+       bool res;
+       int i;
+
+       res = false;
+
        for (i = 0; sig; i++) {
-               cur_bit = ((u32)0x1 << i);
+               cur_bit = (0x1UL << i);
                if (sig & cur_bit) {
-                       switch (cur_bit) {
-                       case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "CSEMI");
+                       res |= true; /* Each bit is real error! */
+                       if (print) {
+                               switch (cur_bit) {
+                               case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR:
+                                       _print_next_block((*par_num)++,
+                                                         "CSEMI");
                                        _print_parity(bp,
                                                      CSEM_REG_CSEM_PRTY_STS_0);
                                        _print_parity(bp,
                                                      CSEM_REG_CSEM_PRTY_STS_1);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "PXP");
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "PXP");
                                        _print_parity(bp, PXP_REG_PXP_PRTY_STS);
                                        _print_parity(bp,
                                                      PXP2_REG_PXP2_PRTY_STS_0);
                                        _print_parity(bp,
                                                      PXP2_REG_PXP2_PRTY_STS_1);
-                               }
-                               break;
-                       case AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR:
-                               if (print)
-                                       _print_next_block(par_num++,
-                                       "PXPPCICLOCKCLIENT");
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "CFC");
+                                       break;
+                               case AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR:
+                                       _print_next_block((*par_num)++,
+                                                         "PXPPCICLOCKCLIENT");
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "CFC");
                                        _print_parity(bp,
                                                      CFC_REG_CFC_PRTY_STS);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "CDU");
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "CDU");
                                        _print_parity(bp, CDU_REG_CDU_PRTY_STS);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_DMAE_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "DMAE");
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_DMAE_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "DMAE");
                                        _print_parity(bp,
                                                      DMAE_REG_DMAE_PRTY_STS);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "IGU");
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "IGU");
                                        if (CHIP_IS_E1x(bp))
                                                _print_parity(bp,
                                                        HC_REG_HC_PRTY_STS);
                                        else
                                                _print_parity(bp,
                                                        IGU_REG_IGU_PRTY_STS);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "MISC");
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "MISC");
                                        _print_parity(bp,
                                                      MISC_REG_MISC_PRTY_STS);
+                                       break;
                                }
-                               break;
                        }
 
                        /* Clear the bit */
@@ -4563,40 +4576,49 @@ static int bnx2x_check_blocks_with_parity2(struct bnx2x *bp, u32 sig,
                }
        }
 
-       return par_num;
+       return res;
 }
 
-static int bnx2x_check_blocks_with_parity3(u32 sig, int par_num,
-                                          bool *global, bool print)
+static bool bnx2x_check_blocks_with_parity3(struct bnx2x *bp, u32 sig,
+                                           int *par_num, bool *global,
+                                           bool print)
 {
-       int i = 0;
-       u32 cur_bit = 0;
+       bool res = false;
+       u32 cur_bit;
+       int i;
+
        for (i = 0; sig; i++) {
-               cur_bit = ((u32)0x1 << i);
+               cur_bit = (0x1UL << i);
                if (sig & cur_bit) {
                        switch (cur_bit) {
                        case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY:
                                if (print)
-                                       _print_next_block(par_num++, "MCP ROM");
+                                       _print_next_block((*par_num)++,
+                                                         "MCP ROM");
                                *global = true;
+                               res |= true;
                                break;
                        case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY:
                                if (print)
-                                       _print_next_block(par_num++,
+                                       _print_next_block((*par_num)++,
                                                          "MCP UMP RX");
                                *global = true;
+                               res |= true;
                                break;
                        case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY:
                                if (print)
-                                       _print_next_block(par_num++,
+                                       _print_next_block((*par_num)++,
                                                          "MCP UMP TX");
                                *global = true;
+                               res |= true;
                                break;
                        case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY:
                                if (print)
-                                       _print_next_block(par_num++,
+                                       _print_next_block((*par_num)++,
                                                          "MCP SCPAD");
-                               *global = true;
+                               /* clear latched SCPAD PATIRY from MCP */
+                               REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL,
+                                      1UL << 10);
                                break;
                        }
 
@@ -4605,45 +4627,50 @@ static int bnx2x_check_blocks_with_parity3(u32 sig, int par_num,
                }
        }
 
-       return par_num;
+       return res;
 }
 
-static int bnx2x_check_blocks_with_parity4(struct bnx2x *bp, u32 sig,
-                                           int par_num, bool print)
+static bool bnx2x_check_blocks_with_parity4(struct bnx2x *bp, u32 sig,
+                                           int *par_num, bool print)
 {
-       int i = 0;
-       u32 cur_bit = 0;
+       u32 cur_bit;
+       bool res;
+       int i;
+
+       res = false;
+
        for (i = 0; sig; i++) {
-               cur_bit = ((u32)0x1 << i);
+               cur_bit = (0x1UL << i);
                if (sig & cur_bit) {
-                       switch (cur_bit) {
-                       case AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "PGLUE_B");
+                       res |= true; /* Each bit is real error! */
+                       if (print) {
+                               switch (cur_bit) {
+                               case AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR:
+                                       _print_next_block((*par_num)++,
+                                                         "PGLUE_B");
                                        _print_parity(bp,
-                                               PGLUE_B_REG_PGLUE_B_PRTY_STS);
-                               }
-                               break;
-                       case AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR:
-                               if (print) {
-                                       _print_next_block(par_num++, "ATC");
+                                                     PGLUE_B_REG_PGLUE_B_PRTY_STS);
+                                       break;
+                               case AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR:
+                                       _print_next_block((*par_num)++, "ATC");
                                        _print_parity(bp,
                                                      ATC_REG_ATC_PRTY_STS);
+                                       break;
                                }
-                               break;
                        }
-
                        /* Clear the bit */
                        sig &= ~cur_bit;
                }
        }
 
-       return par_num;
+       return res;
 }
 
 static bool bnx2x_parity_attn(struct bnx2x *bp, bool *global, bool print,
                              u32 *sig)
 {
+       bool res = false;
+
        if ((sig[0] & HW_PRTY_ASSERT_SET_0) ||
            (sig[1] & HW_PRTY_ASSERT_SET_1) ||
            (sig[2] & HW_PRTY_ASSERT_SET_2) ||
@@ -4660,23 +4687,22 @@ static bool bnx2x_parity_attn(struct bnx2x *bp, bool *global, bool print,
                if (print)
                        netdev_err(bp->dev,
                                   "Parity errors detected in blocks: ");
-               par_num = bnx2x_check_blocks_with_parity0(bp,
-                       sig[0] & HW_PRTY_ASSERT_SET_0, par_num, print);
-               par_num = bnx2x_check_blocks_with_parity1(bp,
-                       sig[1] & HW_PRTY_ASSERT_SET_1, par_num, global, print);
-               par_num = bnx2x_check_blocks_with_parity2(bp,
-                       sig[2] & HW_PRTY_ASSERT_SET_2, par_num, print);
-               par_num = bnx2x_check_blocks_with_parity3(
-                       sig[3] & HW_PRTY_ASSERT_SET_3, par_num, global, print);
-               par_num = bnx2x_check_blocks_with_parity4(bp,
-                       sig[4] & HW_PRTY_ASSERT_SET_4, par_num, print);
+               res |= bnx2x_check_blocks_with_parity0(bp,
+                       sig[0] & HW_PRTY_ASSERT_SET_0, &par_num, print);
+               res |= bnx2x_check_blocks_with_parity1(bp,
+                       sig[1] & HW_PRTY_ASSERT_SET_1, &par_num, global, print);
+               res |= bnx2x_check_blocks_with_parity2(bp,
+                       sig[2] & HW_PRTY_ASSERT_SET_2, &par_num, print);
+               res |= bnx2x_check_blocks_with_parity3(bp,
+                       sig[3] & HW_PRTY_ASSERT_SET_3, &par_num, global, print);
+               res |= bnx2x_check_blocks_with_parity4(bp,
+                       sig[4] & HW_PRTY_ASSERT_SET_4, &par_num, print);
 
                if (print)
                        pr_cont("\n");
+       }
 
-               return true;
-       } else
-               return false;
+       return res;
 }
 
 /**
@@ -4703,6 +4729,14 @@ bool bnx2x_chk_parity_attn(struct bnx2x *bp, bool *global, bool print)
        attn.sig[3] = REG_RD(bp,
                MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 +
                             port*4);
+       /* Since MCP attentions can't be disabled inside the block, we need to
+        * read AEU registers to see whether they're currently disabled
+        */
+       attn.sig[3] &= ((REG_RD(bp,
+                               !port ? MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0
+                                     : MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0) &
+                        MISC_AEU_ENABLE_MCP_PRTY_BITS) |
+                       ~MISC_AEU_ENABLE_MCP_PRTY_BITS);
 
        if (!CHIP_IS_E1x(bp))
                attn.sig[4] = REG_RD(bp,
@@ -5447,26 +5481,24 @@ static void bnx2x_timer(unsigned long data)
        if (IS_PF(bp) &&
            !BP_NOMCP(bp)) {
                int mb_idx = BP_FW_MB_IDX(bp);
-               u32 drv_pulse;
-               u32 mcp_pulse;
+               u16 drv_pulse;
+               u16 mcp_pulse;
 
                ++bp->fw_drv_pulse_wr_seq;
                bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
-               /* TBD - add SYSTEM_TIME */
                drv_pulse = bp->fw_drv_pulse_wr_seq;
                bnx2x_drv_pulse(bp);
 
                mcp_pulse = (SHMEM_RD(bp, func_mb[mb_idx].mcp_pulse_mb) &
                             MCP_PULSE_SEQ_MASK);
                /* The delta between driver pulse and mcp response
-                * should be 1 (before mcp response) or 0 (after mcp response)
+                * should not get too big. If the MFW is more than 5 pulses
+                * behind, we should worry about it enough to generate an error
+                * log.
                 */
-               if ((drv_pulse != mcp_pulse) &&
-                   (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) {
-                       /* someone lost a heartbeat... */
-                       BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
+               if (((drv_pulse - mcp_pulse) & MCP_PULSE_SEQ_MASK) > 5)
+                       BNX2X_ERR("MFW seems hanged: drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
                                  drv_pulse, mcp_pulse);
-               }
        }
 
        if (bp->state == BNX2X_STATE_OPEN)
@@ -7120,7 +7152,7 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
        int port = BP_PORT(bp);
        int init_phase = port ? PHASE_PORT1 : PHASE_PORT0;
        u32 low, high;
-       u32 val;
+       u32 val, reg;
 
        DP(NETIF_MSG_HW, "starting port init  port %d\n", port);
 
@@ -7265,6 +7297,17 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
        val |= CHIP_IS_E1(bp) ? 0 : 0x10;
        REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, val);
 
+       /* SCPAD_PARITY should NOT trigger close the gates */
+       reg = port ? MISC_REG_AEU_ENABLE4_NIG_1 : MISC_REG_AEU_ENABLE4_NIG_0;
+       REG_WR(bp, reg,
+              REG_RD(bp, reg) &
+              ~AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY);
+
+       reg = port ? MISC_REG_AEU_ENABLE4_PXP_1 : MISC_REG_AEU_ENABLE4_PXP_0;
+       REG_WR(bp, reg,
+              REG_RD(bp, reg) &
+              ~AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY);
+
        bnx2x_init_block(bp, BLOCK_NIG, init_phase);
 
        if (!CHIP_IS_E1x(bp)) {
@@ -11679,9 +11722,6 @@ static int bnx2x_init_bp(struct bnx2x *bp)
 static int bnx2x_open(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
-       bool global = false;
-       int other_engine = BP_PATH(bp) ? 0 : 1;
-       bool other_load_status, load_status;
        int rc;
 
        bp->stats_init = true;
@@ -11697,6 +11737,10 @@ static int bnx2x_open(struct net_device *dev)
         * Parity recovery is only relevant for PF driver.
         */
        if (IS_PF(bp)) {
+               int other_engine = BP_PATH(bp) ? 0 : 1;
+               bool other_load_status, load_status;
+               bool global = false;
+
                other_load_status = bnx2x_get_load_status(bp, other_engine);
                load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
                if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
@@ -12074,7 +12118,6 @@ static int bnx2x_set_coherency_mask(struct bnx2x *bp)
        struct device *dev = &bp->pdev->dev;
 
        if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) {
-               bp->flags |= USING_DAC_FLAG;
                if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) {
                        dev_err(dev, "dma_set_coherent_mask failed, aborting\n");
                        return -EIO;
@@ -12242,8 +12285,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_HIGHDMA;
 
        dev->features |= dev->hw_features | NETIF_F_HW_VLAN_CTAG_RX;
-       if (bp->flags & USING_DAC_FLAG)
-               dev->features |= NETIF_F_HIGHDMA;
+       dev->features |= NETIF_F_HIGHDMA;
 
        /* Add Loopback capability to the device */
        dev->hw_features |= NETIF_F_LOOPBACK;
@@ -12606,24 +12648,24 @@ static int set_max_cos_est(int chip_id)
                return BNX2X_MULTI_TX_COS_E1X;
        case BCM57712:
        case BCM57712_MF:
-       case BCM57712_VF:
                return BNX2X_MULTI_TX_COS_E2_E3A0;
        case BCM57800:
        case BCM57800_MF:
-       case BCM57800_VF:
        case BCM57810:
        case BCM57810_MF:
        case BCM57840_4_10:
        case BCM57840_2_20:
        case BCM57840_O:
        case BCM57840_MFO:
-       case BCM57810_VF:
        case BCM57840_MF:
-       case BCM57840_VF:
        case BCM57811:
        case BCM57811_MF:
-       case BCM57811_VF:
                return BNX2X_MULTI_TX_COS_E3B0;
+       case BCM57712_VF:
+       case BCM57800_VF:
+       case BCM57810_VF:
+       case BCM57840_VF:
+       case BCM57811_VF:
                return 1;
        default:
                pr_err("Unknown board_type (%d), aborting\n", chip_id);
index 2604b62..bf08ad6 100644 (file)
@@ -470,10 +470,10 @@ static int bnx2x_vfop_qdtor_cmd(struct bnx2x *bp,
                                 bnx2x_vfop_qdtor, cmd->done);
                return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdtor,
                                             cmd->block);
+       } else {
+               BNX2X_ERR("VF[%d] failed to add a vfop\n", vf->abs_vfid);
+               return -ENOMEM;
        }
-       DP(BNX2X_MSG_IOV, "VF[%d] failed to add a vfop. rc %d\n",
-          vf->abs_vfid, vfop->rc);
-       return -ENOMEM;
 }
 
 static void
@@ -1819,7 +1819,7 @@ bnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
                fid = GET_FIELD((val), IGU_REG_MAPPING_MEMORY_FID);
                if (fid & IGU_FID_ENCODE_IS_PF)
                        current_pf = fid & IGU_FID_PF_NUM_MASK;
-               else if (current_pf == BP_ABS_FUNC(bp))
+               else if (current_pf == BP_FUNC(bp))
                        bnx2x_vf_set_igu_info(bp, sb_id,
                                              (fid & IGU_FID_VF_NUM_MASK));
                DP(BNX2X_MSG_IOV, "%s[%d], igu_sb_id=%d, msix=%d\n",
@@ -3180,6 +3180,7 @@ int bnx2x_enable_sriov(struct bnx2x *bp)
                /* set local queue arrays */
                vf->vfqs = &bp->vfdb->vfqs[qcount];
                qcount += vf_sb_count(vf);
+               bnx2x_iov_static_resc(bp, vf);
        }
 
        /* prepare msix vectors in VF configuration space */
@@ -3187,6 +3188,8 @@ int bnx2x_enable_sriov(struct bnx2x *bp)
                bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf_idx));
                REG_WR(bp, PCICFG_OFFSET + GRC_CONFIG_REG_VF_MSIX_CONTROL,
                       num_vf_queues);
+               DP(BNX2X_MSG_IOV, "set msix vec num in VF %d cfg space to %d\n",
+                  vf_idx, num_vf_queues);
        }
        bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
 
@@ -3387,14 +3390,16 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
                rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true);
                if (rc) {
                        BNX2X_ERR("failed to delete eth macs\n");
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto out;
                }
 
                /* remove existing uc list macs */
                rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_UC_LIST_MAC, true);
                if (rc) {
                        BNX2X_ERR("failed to delete uc_list macs\n");
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto out;
                }
 
                /* configure the new mac to device */
@@ -3402,6 +3407,7 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
                bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
                                  BNX2X_ETH_MAC, &ramrod_flags);
 
+out:
                bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
        }
 
@@ -3464,7 +3470,8 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
                                          &ramrod_flags);
                if (rc) {
                        BNX2X_ERR("failed to delete vlans\n");
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto out;
                }
 
                /* send queue update ramrod to configure default vlan and silent
@@ -3498,7 +3505,8 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
                        rc = bnx2x_config_vlan_mac(bp, &ramrod_param);
                        if (rc) {
                                BNX2X_ERR("failed to configure vlan\n");
-                               return -EINVAL;
+                               rc =  -EINVAL;
+                               goto out;
                        }
 
                        /* configure default vlan to vf queue and set silent
@@ -3516,18 +3524,18 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
                rc = bnx2x_queue_state_change(bp, &q_params);
                if (rc) {
                        BNX2X_ERR("Failed to configure default VLAN\n");
-                       return rc;
+                       goto out;
                }
 
                /* clear the flag indicating that this VF needs its vlan
-                * (will only be set if the HV configured th Vlan before vf was
-                * and we were called because the VF came up later
+                * (will only be set if the HV configured the Vlan before vf was
+                * up and we were called because the VF came up later
                 */
+out:
                vf->cfg_flags &= ~VF_CFG_VLAN;
-
                bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
        }
-       return 0;
+       return rc;
 }
 
 /* crc is the first field in the bulletin board. Compute the crc over the
index 86436c7..3b75070 100644 (file)
@@ -196,7 +196,7 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp)
 
        } else if (bp->func_stx) {
                *stats_comp = 0;
-               bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
+               bnx2x_issue_dmae_with_comp(bp, dmae, stats_comp);
        }
 }
 
index 6cfb887..28757df 100644 (file)
@@ -980,7 +980,7 @@ static int bnx2x_copy32_vf_dmae(struct bnx2x *bp, u8 from_vf,
        dmae.len = len32;
 
        /* issue the command and wait for completion */
-       return bnx2x_issue_dmae_with_comp(bp, &dmae);
+       return bnx2x_issue_dmae_with_comp(bp, &dmae, bnx2x_sp(bp, wb_comp));
 }
 
 static void bnx2x_vf_mbx_resp(struct bnx2x *bp, struct bnx2x_virtf *vf)
@@ -1765,28 +1765,28 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
                switch (mbx->first_tlv.tl.type) {
                case CHANNEL_TLV_ACQUIRE:
                        bnx2x_vf_mbx_acquire(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_INIT:
                        bnx2x_vf_mbx_init_vf(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_SETUP_Q:
                        bnx2x_vf_mbx_setup_q(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_SET_Q_FILTERS:
                        bnx2x_vf_mbx_set_q_filters(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_TEARDOWN_Q:
                        bnx2x_vf_mbx_teardown_q(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_CLOSE:
                        bnx2x_vf_mbx_close_vf(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_RELEASE:
                        bnx2x_vf_mbx_release_vf(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_UPDATE_RSS:
                        bnx2x_vf_mbx_update_rss(bp, vf, mbx);
-                       break;
+                       return;
                }
 
        } else {
@@ -1802,26 +1802,24 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
                for (i = 0; i < 20; i++)
                        DP_CONT(BNX2X_MSG_IOV, "%x ",
                                mbx->msg->req.tlv_buf_size.tlv_buffer[i]);
+       }
 
-               /* test whether we can respond to the VF (do we have an address
-                * for it?)
-                */
-               if (vf->state == VF_ACQUIRED || vf->state == VF_ENABLED) {
-                       /* mbx_resp uses the op_rc of the VF */
-                       vf->op_rc = PFVF_STATUS_NOT_SUPPORTED;
+       /* can we respond to VF (do we have an address for it?) */
+       if (vf->state == VF_ACQUIRED || vf->state == VF_ENABLED) {
+               /* mbx_resp uses the op_rc of the VF */
+               vf->op_rc = PFVF_STATUS_NOT_SUPPORTED;
 
-                       /* notify the VF that we do not support this request */
-                       bnx2x_vf_mbx_resp(bp, vf);
-               } else {
-                       /* can't send a response since this VF is unknown to us
-                        * just ack the FW to release the mailbox and unlock
-                        * the channel.
-                        */
-                       storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
-                       mmiowb();
-                       bnx2x_unlock_vf_pf_channel(bp, vf,
-                                                  mbx->first_tlv.tl.type);
-               }
+               /* notify the VF that we do not support this request */
+               bnx2x_vf_mbx_resp(bp, vf);
+       } else {
+               /* can't send a response since this VF is unknown to us
+                * just ack the FW to release the mailbox and unlock
+                * the channel.
+                */
+               storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
+               /* Firmware ack should be written before unlocking channel */
+               mmiowb();
+               bnx2x_unlock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
        }
 }
 
index 78d6d6b..48f5288 100644 (file)
 #define XGMAC_DMA_HW_FEATURE   0x00000f58      /* Enabled Hardware Features */
 
 #define XGMAC_ADDR_AE          0x80000000
-#define XGMAC_MAX_FILTER_ADDR  31
 
 /* PMT Control and Status */
 #define XGMAC_PMT_POINTER_RESET        0x80000000
@@ -384,6 +383,7 @@ struct xgmac_priv {
        struct device *device;
        struct napi_struct napi;
 
+       int max_macs;
        struct xgmac_extra_stats xstats;
 
        spinlock_t stats_lock;
@@ -1291,14 +1291,12 @@ static void xgmac_set_rx_mode(struct net_device *dev)
        netdev_dbg(priv->dev, "# mcasts %d, # unicast %d\n",
                 netdev_mc_count(dev), netdev_uc_count(dev));
 
-       if (dev->flags & IFF_PROMISC) {
-               writel(XGMAC_FRAME_FILTER_PR, ioaddr + XGMAC_FRAME_FILTER);
-               return;
-       }
+       if (dev->flags & IFF_PROMISC)
+               value |= XGMAC_FRAME_FILTER_PR;
 
        memset(hash_filter, 0, sizeof(hash_filter));
 
-       if (netdev_uc_count(dev) > XGMAC_MAX_FILTER_ADDR) {
+       if (netdev_uc_count(dev) > priv->max_macs) {
                use_hash = true;
                value |= XGMAC_FRAME_FILTER_HUC | XGMAC_FRAME_FILTER_HPF;
        }
@@ -1321,7 +1319,7 @@ static void xgmac_set_rx_mode(struct net_device *dev)
                goto out;
        }
 
-       if ((netdev_mc_count(dev) + reg - 1) > XGMAC_MAX_FILTER_ADDR) {
+       if ((netdev_mc_count(dev) + reg - 1) > priv->max_macs) {
                use_hash = true;
                value |= XGMAC_FRAME_FILTER_HMC | XGMAC_FRAME_FILTER_HPF;
        } else {
@@ -1342,8 +1340,8 @@ static void xgmac_set_rx_mode(struct net_device *dev)
        }
 
 out:
-       for (i = reg; i < XGMAC_MAX_FILTER_ADDR; i++)
-               xgmac_set_mac_addr(ioaddr, NULL, reg);
+       for (i = reg; i <= priv->max_macs; i++)
+               xgmac_set_mac_addr(ioaddr, NULL, i);
        for (i = 0; i < XGMAC_NUM_HASH; i++)
                writel(hash_filter[i], ioaddr + XGMAC_HASH(i));
 
@@ -1761,6 +1759,13 @@ static int xgmac_probe(struct platform_device *pdev)
        uid = readl(priv->base + XGMAC_VERSION);
        netdev_info(ndev, "h/w version is 0x%x\n", uid);
 
+       /* Figure out how many valid mac address filter registers we have */
+       writel(1, priv->base + XGMAC_ADDR_HIGH(31));
+       if (readl(priv->base + XGMAC_ADDR_HIGH(31)) == 1)
+               priv->max_macs = 31;
+       else
+               priv->max_macs = 7;
+
        writel(0, priv->base + XGMAC_DMA_INTR_ENA);
        ndev->irq = platform_get_irq(pdev, 0);
        if (ndev->irq == -ENXIO) {
index 5f5896e..a7a941b 100644 (file)
@@ -158,18 +158,6 @@ static inline board_info_t *to_dm9000_board(struct net_device *dev)
 
 /* DM9000 network board routine ---------------------------- */
 
-static void
-dm9000_reset(board_info_t * db)
-{
-       dev_dbg(db->dev, "resetting device\n");
-
-       /* RESET device */
-       writeb(DM9000_NCR, db->io_addr);
-       udelay(200);
-       writeb(NCR_RST, db->io_data);
-       udelay(200);
-}
-
 /*
  *   Read a byte from I/O port
  */
@@ -191,6 +179,27 @@ iow(board_info_t * db, int reg, int value)
        writeb(value, db->io_data);
 }
 
+static void
+dm9000_reset(board_info_t *db)
+{
+       dev_dbg(db->dev, "resetting device\n");
+
+       /* Reset DM9000, see DM9000 Application Notes V1.22 Jun 11, 2004 page 29
+        * The essential point is that we have to do a double reset, and the
+        * instruction is to set LBK into MAC internal loopback mode.
+        */
+       iow(db, DM9000_NCR, 0x03);
+       udelay(100); /* Application note says at least 20 us */
+       if (ior(db, DM9000_NCR) & 1)
+               dev_err(db->dev, "dm9000 did not respond to first reset\n");
+
+       iow(db, DM9000_NCR, 0);
+       iow(db, DM9000_NCR, 0x03);
+       udelay(100);
+       if (ior(db, DM9000_NCR) & 1)
+               dev_err(db->dev, "dm9000 did not respond to second reset\n");
+}
+
 /* routines for sending block to chip */
 
 static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count)
@@ -744,15 +753,20 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
 static void dm9000_show_carrier(board_info_t *db,
                                unsigned carrier, unsigned nsr)
 {
+       int lpa;
        struct net_device *ndev = db->ndev;
+       struct mii_if_info *mii = &db->mii;
        unsigned ncr = dm9000_read_locked(db, DM9000_NCR);
 
-       if (carrier)
-               dev_info(db->dev, "%s: link up, %dMbps, %s-duplex, no LPA\n",
+       if (carrier) {
+               lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
+               dev_info(db->dev,
+                        "%s: link up, %dMbps, %s-duplex, lpa 0x%04X\n",
                         ndev->name, (nsr & NSR_SPEED) ? 10 : 100,
-                        (ncr & NCR_FDX) ? "full" : "half");
-       else
+                        (ncr & NCR_FDX) ? "full" : "half", lpa);
+       } else {
                dev_info(db->dev, "%s: link down\n", ndev->name);
+       }
 }
 
 static void
@@ -890,9 +904,15 @@ dm9000_init_dm9000(struct net_device *dev)
                        (dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0);
 
        iow(db, DM9000_GPCR, GPCR_GEP_CNTL);    /* Let GPIO0 output */
+       iow(db, DM9000_GPR, 0);
 
-       dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */
-       dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); /* Init */
+       /* If we are dealing with DM9000B, some extra steps are required: a
+        * manual phy reset, and setting init params.
+        */
+       if (db->type == TYPE_DM9000B) {
+               dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);
+               dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM);
+       }
 
        ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;
 
index ace5050..db02023 100644 (file)
@@ -88,6 +88,7 @@ static inline char *nic_name(struct pci_dev *pdev)
 #define BE_MIN_MTU             256
 
 #define BE_NUM_VLANS_SUPPORTED 64
+#define BE_UMC_NUM_VLANS_SUPPORTED     15
 #define BE_MAX_EQD             96u
 #define        BE_MAX_TX_FRAG_COUNT    30
 
@@ -333,6 +334,7 @@ enum vf_state {
 
 #define BE_FLAGS_LINK_STATUS_INIT              1
 #define BE_FLAGS_WORKER_SCHEDULED              (1 << 3)
+#define BE_FLAGS_VLAN_PROMISC                  (1 << 4)
 #define BE_FLAGS_NAPI_ENABLED                  (1 << 9)
 #define BE_UC_PMAC_COUNT               30
 #define BE_VF_UC_PMAC_COUNT            2
index 1ab5dab..c08fd32 100644 (file)
@@ -180,6 +180,9 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
                        dev_err(&adapter->pdev->dev,
                                "opcode %d-%d failed:status %d-%d\n",
                                opcode, subsystem, compl_status, extd_status);
+
+                       if (extd_status == MCC_ADDL_STS_INSUFFICIENT_RESOURCES)
+                               return extd_status;
                }
        }
 done:
@@ -1195,7 +1198,6 @@ int be_cmd_txq_create(struct be_adapter *adapter, struct be_tx_obj *txo)
 
        if (lancer_chip(adapter)) {
                req->hdr.version = 1;
-               req->if_id = cpu_to_le16(adapter->if_handle);
        } else if (BEx_chip(adapter)) {
                if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC)
                        req->hdr.version = 2;
@@ -1203,6 +1205,8 @@ int be_cmd_txq_create(struct be_adapter *adapter, struct be_tx_obj *txo)
                req->hdr.version = 2;
        }
 
+       if (req->hdr.version > 0)
+               req->if_id = cpu_to_le16(adapter->if_handle);
        req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
        req->ulp_num = BE_ULP1_NUM;
        req->type = BE_ETH_TX_RING_TYPE_STANDARD;
@@ -1812,6 +1816,12 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
        } else if (flags & IFF_ALLMULTI) {
                req->if_flags_mask = req->if_flags =
                                cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS);
+       } else if (flags & BE_FLAGS_VLAN_PROMISC) {
+               req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
+
+               if (value == ON)
+                       req->if_flags =
+                               cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
        } else {
                struct netdev_hw_addr *ha;
                int i = 0;
index d026226..108ca8a 100644 (file)
@@ -60,6 +60,8 @@ enum {
        MCC_STATUS_NOT_SUPPORTED = 66
 };
 
+#define MCC_ADDL_STS_INSUFFICIENT_RESOURCES    0x16
+
 #define CQE_STATUS_COMPL_MASK          0xFFFF
 #define CQE_STATUS_COMPL_SHIFT         0       /* bits 0 - 15 */
 #define CQE_STATUS_EXTD_MASK           0xFFFF
@@ -1791,7 +1793,7 @@ struct be_nic_res_desc {
        u8 acpi_params;
        u8 wol_param;
        u16 rsvd7;
-       u32 rsvd8[3];
+       u32 rsvd8[7];
 } __packed;
 
 struct be_cmd_req_get_func_config {
index 100b528..2c38cc4 100644 (file)
@@ -855,11 +855,11 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
        unsigned int eth_hdr_len;
        struct iphdr *ip;
 
-       /* Lancer ASIC has a bug wherein packets that are 32 bytes or less
+       /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less
         * may cause a transmit stall on that port. So the work-around is to
-        * pad such packets to a 36-byte length.
+        * pad short packets (<= 32 bytes) to a 36-byte length.
         */
-       if (unlikely(lancer_chip(adapter) && skb->len <= 32)) {
+       if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
                if (skb_padto(skb, 36))
                        goto tx_drop;
                skb->len = 36;
@@ -1013,18 +1013,40 @@ static int be_vid_config(struct be_adapter *adapter)
        status = be_cmd_vlan_config(adapter, adapter->if_handle,
                                    vids, num, 1, 0);
 
-       /* Set to VLAN promisc mode as setting VLAN filter failed */
        if (status) {
-               dev_info(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n");
-               dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering.\n");
-               goto set_vlan_promisc;
+               /* Set to VLAN promisc mode as setting VLAN filter failed */
+               if (status == MCC_ADDL_STS_INSUFFICIENT_RESOURCES)
+                       goto set_vlan_promisc;
+               dev_err(&adapter->pdev->dev,
+                       "Setting HW VLAN filtering failed.\n");
+       } else {
+               if (adapter->flags & BE_FLAGS_VLAN_PROMISC) {
+                       /* hw VLAN filtering re-enabled. */
+                       status = be_cmd_rx_filter(adapter,
+                                                 BE_FLAGS_VLAN_PROMISC, OFF);
+                       if (!status) {
+                               dev_info(&adapter->pdev->dev,
+                                        "Disabling VLAN Promiscuous mode.\n");
+                               adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
+                               dev_info(&adapter->pdev->dev,
+                                        "Re-Enabling HW VLAN filtering\n");
+                       }
+               }
        }
 
        return status;
 
 set_vlan_promisc:
-       status = be_cmd_vlan_config(adapter, adapter->if_handle,
-                                   NULL, 0, 1, 1);
+       dev_warn(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n");
+
+       status = be_cmd_rx_filter(adapter, BE_FLAGS_VLAN_PROMISC, ON);
+       if (!status) {
+               dev_info(&adapter->pdev->dev, "Enable VLAN Promiscuous mode\n");
+               dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering\n");
+               adapter->flags |= BE_FLAGS_VLAN_PROMISC;
+       } else
+               dev_err(&adapter->pdev->dev,
+                       "Failed to enable VLAN Promiscuous mode.\n");
        return status;
 }
 
@@ -1033,10 +1055,6 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
        struct be_adapter *adapter = netdev_priv(netdev);
        int status = 0;
 
-       if (!lancer_chip(adapter) && !be_physfn(adapter)) {
-               status = -EINVAL;
-               goto ret;
-       }
 
        /* Packets with VID 0 are always received by Lancer by default */
        if (lancer_chip(adapter) && vid == 0)
@@ -1059,11 +1077,6 @@ static int be_vlan_rem_vid(struct net_device *netdev, __be16 proto, u16 vid)
        struct be_adapter *adapter = netdev_priv(netdev);
        int status = 0;
 
-       if (!lancer_chip(adapter) && !be_physfn(adapter)) {
-               status = -EINVAL;
-               goto ret;
-       }
-
        /* Packets with VID 0 are always received by Lancer by default */
        if (lancer_chip(adapter) && vid == 0)
                goto ret;
@@ -1188,8 +1201,8 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
 
        vi->vf = vf;
        vi->tx_rate = vf_cfg->tx_rate;
-       vi->vlan = vf_cfg->vlan_tag;
-       vi->qos = 0;
+       vi->vlan = vf_cfg->vlan_tag & VLAN_VID_MASK;
+       vi->qos = vf_cfg->vlan_tag >> VLAN_PRIO_SHIFT;
        memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN);
 
        return 0;
@@ -1199,28 +1212,29 @@ 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;
 
        if (!sriov_enabled(adapter))
                return -EPERM;
 
-       if (vf >= adapter->num_vfs || vlan > 4095)
+       if (vf >= adapter->num_vfs || vlan > 4095 || qos > 7)
                return -EINVAL;
 
-       if (vlan) {
-               if (adapter->vf_cfg[vf].vlan_tag != vlan) {
+       if (vlan || qos) {
+               vlan |= qos << VLAN_PRIO_SHIFT;
+               if (vf_cfg->vlan_tag != vlan) {
                        /* If this is new value, program it. Else skip. */
-                       adapter->vf_cfg[vf].vlan_tag = vlan;
-
-                       status = be_cmd_set_hsw_config(adapter, vlan,
-                               vf + 1, adapter->vf_cfg[vf].if_handle, 0);
+                       vf_cfg->vlan_tag = vlan;
+                       status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
+                                                      vf_cfg->if_handle, 0);
                }
        } else {
                /* Reset Transparent Vlan Tagging. */
-               adapter->vf_cfg[vf].vlan_tag = 0;
-               vlan = adapter->vf_cfg[vf].def_vid;
+               vf_cfg->vlan_tag = 0;
+               vlan = vf_cfg->def_vid;
                status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
-                       adapter->vf_cfg[vf].if_handle, 0);
+                                              vf_cfg->if_handle, 0);
        }
 
 
@@ -2963,6 +2977,8 @@ static void BEx_get_resources(struct be_adapter *adapter,
 
        if (adapter->function_mode & FLEX10_MODE)
                res->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
+       else if (adapter->function_mode & UMC_ENABLED)
+               res->max_vlans = BE_UMC_NUM_VLANS_SUPPORTED;
        else
                res->max_vlans = BE_NUM_VLANS_SUPPORTED;
        res->max_mcast_mac = BE_MAX_MC;
index c4eaade..9fbe4dd 100644 (file)
@@ -88,6 +88,7 @@
 
 #include <asm/io.h>
 #include <asm/reg.h>
+#include <asm/mpc85xx.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
@@ -939,9 +940,8 @@ static void gfar_init_filer_table(struct gfar_private *priv)
        }
 }
 
-static void gfar_detect_errata(struct gfar_private *priv)
+static void __gfar_detect_errata_83xx(struct gfar_private *priv)
 {
-       struct device *dev = &priv->ofdev->dev;
        unsigned int pvr = mfspr(SPRN_PVR);
        unsigned int svr = mfspr(SPRN_SVR);
        unsigned int mod = (svr >> 16) & 0xfff6; /* w/o E suffix */
@@ -957,15 +957,33 @@ static void gfar_detect_errata(struct gfar_private *priv)
            (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
                priv->errata |= GFAR_ERRATA_76;
 
-       /* MPC8313 and MPC837x all rev */
-       if ((pvr == 0x80850010 && mod == 0x80b0) ||
-           (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
-               priv->errata |= GFAR_ERRATA_A002;
+       /* MPC8313 Rev < 2.0 */
+       if (pvr == 0x80850010 && mod == 0x80b0 && rev < 0x0020)
+               priv->errata |= GFAR_ERRATA_12;
+}
 
-       /* MPC8313 Rev < 2.0, MPC8548 rev 2.0 */
-       if ((pvr == 0x80850010 && mod == 0x80b0 && rev < 0x0020) ||
-           (pvr == 0x80210020 && mod == 0x8030 && rev == 0x0020))
+static void __gfar_detect_errata_85xx(struct gfar_private *priv)
+{
+       unsigned int svr = mfspr(SPRN_SVR);
+
+       if ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) == 0x20))
                priv->errata |= GFAR_ERRATA_12;
+       if (((SVR_SOC_VER(svr) == SVR_P2020) && (SVR_REV(svr) < 0x20)) ||
+           ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20)))
+               priv->errata |= GFAR_ERRATA_76; /* aka eTSEC 20 */
+}
+
+static void gfar_detect_errata(struct gfar_private *priv)
+{
+       struct device *dev = &priv->ofdev->dev;
+
+       /* no plans to fix */
+       priv->errata |= GFAR_ERRATA_A002;
+
+       if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2))
+               __gfar_detect_errata_85xx(priv);
+       else /* non-mpc85xx parts, i.e. e300 core based */
+               __gfar_detect_errata_83xx(priv);
 
        if (priv->errata)
                dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
@@ -1599,7 +1617,7 @@ static int __gfar_is_rx_idle(struct gfar_private *priv)
        /* Normaly TSEC should not hang on GRS commands, so we should
         * actually wait for IEVENT_GRSC flag.
         */
-       if (likely(!gfar_has_errata(priv, GFAR_ERRATA_A002)))
+       if (!gfar_has_errata(priv, GFAR_ERRATA_A002))
                return 0;
 
        /* Read the eTSEC register at offset 0xD1C. If bits 7-14 are
index 098f133..e006a09 100644 (file)
@@ -452,7 +452,9 @@ static int gianfar_ptp_probe(struct platform_device *dev)
        err = -ENODEV;
 
        etsects->caps = ptp_gianfar_caps;
-       etsects->cksel = DEFAULT_CKSEL;
+
+       if (get_of_u32(node, "fsl,cksel", &etsects->cksel))
+               etsects->cksel = DEFAULT_CKSEL;
 
        if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) ||
            get_of_u32(node, "fsl,tmr-prsc", &etsects->tmr_prsc) ||
index 0c524fa..cfef7fc 100644 (file)
@@ -701,8 +701,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
 
        details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use);
        if (cmd_details) {
-               memcpy(details, cmd_details,
-                      sizeof(struct i40e_asq_cmd_details));
+               *details = *cmd_details;
 
                /* If the cmd_details are defined copy the cookie.  The
                 * cpu_to_le32 is not needed here because the data is ignored
@@ -760,7 +759,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
        desc_on_ring = I40E_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use);
 
        /* if the desc is available copy the temp desc to the right place */
-       memcpy(desc_on_ring, desc, sizeof(struct i40e_aq_desc));
+       *desc_on_ring = *desc;
 
        /* if buff is not NULL assume indirect command */
        if (buff != NULL) {
@@ -807,7 +806,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
 
        /* if ready, copy the desc back to temp */
        if (i40e_asq_done(hw)) {
-               memcpy(desc, desc_on_ring, sizeof(struct i40e_aq_desc));
+               *desc = *desc_on_ring;
                if (buff != NULL)
                        memcpy(buff, dma_buff->va, buff_size);
                retval = le16_to_cpu(desc->retval);
index c21df7b..1e4ea13 100644 (file)
@@ -507,7 +507,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
 
        /* save link status information */
        if (link)
-               memcpy(link, hw_link_info, sizeof(struct i40e_link_status));
+               *link = *hw_link_info;
 
        /* flag cleared so helper functions don't call AQ again */
        hw->phy.get_link_info = false;
index 601d482..221aa47 100644 (file)
@@ -101,10 +101,10 @@ int i40e_allocate_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem,
        mem->size = ALIGN(size, alignment);
        mem->va = dma_zalloc_coherent(&pf->pdev->dev, mem->size,
                                      &mem->pa, GFP_KERNEL);
-       if (mem->va)
-               return 0;
+       if (!mem->va)
+               return -ENOMEM;
 
-       return -ENOMEM;
+       return 0;
 }
 
 /**
@@ -136,10 +136,10 @@ int i40e_allocate_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem,
        mem->size = size;
        mem->va = kzalloc(size, GFP_KERNEL);
 
-       if (mem->va)
-               return 0;
+       if (!mem->va)
+               return -ENOMEM;
 
-       return -ENOMEM;
+       return 0;
 }
 
 /**
@@ -174,8 +174,7 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
                         u16 needed, u16 id)
 {
        int ret = -ENOMEM;
-       int i = 0;
-       int j = 0;
+       int i, j;
 
        if (!pile || needed == 0 || id >= I40E_PILE_VALID_BIT) {
                dev_info(&pf->pdev->dev,
@@ -186,7 +185,7 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
 
        /* start the linear search with an imperfect hint */
        i = pile->search_hint;
-       while (i < pile->num_entries && ret < 0) {
+       while (i < pile->num_entries) {
                /* skip already allocated entries */
                if (pile->list[i] & I40E_PILE_VALID_BIT) {
                        i++;
@@ -205,6 +204,7 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
                                pile->list[i+j] = id | I40E_PILE_VALID_BIT;
                        ret = i;
                        pile->search_hint = i + j;
+                       break;
                } else {
                        /* not enough, so skip over it and continue looking */
                        i += j;
@@ -1388,7 +1388,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
        bool add_happened = false;
        int filter_list_len = 0;
        u32 changed_flags = 0;
-       i40e_status ret = 0;
+       i40e_status aq_ret = 0;
        struct i40e_pf *pf;
        int num_add = 0;
        int num_del = 0;
@@ -1449,28 +1449,28 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 
                        /* flush a full buffer */
                        if (num_del == filter_list_len) {
-                               ret = i40e_aq_remove_macvlan(&pf->hw,
+                               aq_ret = i40e_aq_remove_macvlan(&pf->hw,
                                            vsi->seid, del_list, num_del,
                                            NULL);
                                num_del = 0;
                                memset(del_list, 0, sizeof(*del_list));
 
-                               if (ret)
+                               if (aq_ret)
                                        dev_info(&pf->pdev->dev,
                                                 "ignoring delete macvlan error, err %d, aq_err %d while flushing a full buffer\n",
-                                                ret,
+                                                aq_ret,
                                                 pf->hw.aq.asq_last_status);
                        }
                }
                if (num_del) {
-                       ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid,
+                       aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid,
                                                     del_list, num_del, NULL);
                        num_del = 0;
 
-                       if (ret)
+                       if (aq_ret)
                                dev_info(&pf->pdev->dev,
                                         "ignoring delete macvlan error, err %d, aq_err %d\n",
-                                        ret, pf->hw.aq.asq_last_status);
+                                        aq_ret, pf->hw.aq.asq_last_status);
                }
 
                kfree(del_list);
@@ -1515,32 +1515,30 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 
                        /* flush a full buffer */
                        if (num_add == filter_list_len) {
-                               ret = i40e_aq_add_macvlan(&pf->hw,
-                                                         vsi->seid,
-                                                         add_list,
-                                                         num_add,
-                                                         NULL);
+                               aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
+                                                            add_list, num_add,
+                                                            NULL);
                                num_add = 0;
 
-                               if (ret)
+                               if (aq_ret)
                                        break;
                                memset(add_list, 0, sizeof(*add_list));
                        }
                }
                if (num_add) {
-                       ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
-                                                 add_list, num_add, NULL);
+                       aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
+                                                    add_list, num_add, NULL);
                        num_add = 0;
                }
                kfree(add_list);
                add_list = NULL;
 
-               if (add_happened && (!ret)) {
+               if (add_happened && (!aq_ret)) {
                        /* do nothing */;
-               } else if (add_happened && (ret)) {
+               } else if (add_happened && (aq_ret)) {
                        dev_info(&pf->pdev->dev,
                                 "add filter failed, err %d, aq_err %d\n",
-                                ret, pf->hw.aq.asq_last_status);
+                                aq_ret, pf->hw.aq.asq_last_status);
                        if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOSPC) &&
                            !test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
                                      &vsi->state)) {
@@ -1556,28 +1554,27 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
        if (changed_flags & IFF_ALLMULTI) {
                bool cur_multipromisc;
                cur_multipromisc = !!(vsi->current_netdev_flags & IFF_ALLMULTI);
-               ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw,
-                                                           vsi->seid,
-                                                           cur_multipromisc,
-                                                           NULL);
-               if (ret)
+               aq_ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw,
+                                                              vsi->seid,
+                                                              cur_multipromisc,
+                                                              NULL);
+               if (aq_ret)
                        dev_info(&pf->pdev->dev,
                                 "set multi promisc failed, err %d, aq_err %d\n",
-                                ret, pf->hw.aq.asq_last_status);
+                                aq_ret, pf->hw.aq.asq_last_status);
        }
        if ((changed_flags & IFF_PROMISC) || promisc_forced_on) {
                bool cur_promisc;
                cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) ||
                               test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
                                        &vsi->state));
-               ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw,
-                                                         vsi->seid,
-                                                         cur_promisc,
-                                                         NULL);
-               if (ret)
+               aq_ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw,
+                                                            vsi->seid,
+                                                            cur_promisc, NULL);
+               if (aq_ret)
                        dev_info(&pf->pdev->dev,
                                 "set uni promisc failed, err %d, aq_err %d\n",
-                                ret, pf->hw.aq.asq_last_status);
+                                aq_ret, pf->hw.aq.asq_last_status);
        }
 
        clear_bit(__I40E_CONFIG_BUSY, &vsi->state);
@@ -1790,6 +1787,8 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
  * i40e_vsi_kill_vlan - Remove vsi membership for given vlan
  * @vsi: the vsi being configured
  * @vid: vlan id to be removed (0 = untagged only , -1 = any)
+ *
+ * Return: 0 on success or negative otherwise
  **/
 int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
 {
@@ -1863,37 +1862,39 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
  * i40e_vlan_rx_add_vid - Add a vlan id filter to HW offload
  * @netdev: network interface to be adjusted
  * @vid: vlan id to be added
+ *
+ * net_device_ops implementation for adding vlan ids
  **/
 static int i40e_vlan_rx_add_vid(struct net_device *netdev,
                                __always_unused __be16 proto, u16 vid)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
-       int ret;
+       int ret = 0;
 
        if (vid > 4095)
-               return 0;
+               return -EINVAL;
+
+       netdev_info(netdev, "adding %pM vid=%d\n", netdev->dev_addr, vid);
 
-       netdev_info(vsi->netdev, "adding %pM vid=%d\n",
-                   netdev->dev_addr, vid);
        /* If the network stack called us with vid = 0, we should
         * indicate to i40e_vsi_add_vlan() that we want to receive
         * any traffic (i.e. with any vlan tag, or untagged)
         */
        ret = i40e_vsi_add_vlan(vsi, vid ? vid : I40E_VLAN_ANY);
 
-       if (!ret) {
-               if (vid < VLAN_N_VID)
-                       set_bit(vid, vsi->active_vlans);
-       }
+       if (!ret && (vid < VLAN_N_VID))
+               set_bit(vid, vsi->active_vlans);
 
-       return 0;
+       return ret;
 }
 
 /**
  * i40e_vlan_rx_kill_vid - Remove a vlan id filter from HW offload
  * @netdev: network interface to be adjusted
  * @vid: vlan id to be removed
+ *
+ * net_device_ops implementation for adding vlan ids
  **/
 static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
                                 __always_unused __be16 proto, u16 vid)
@@ -1901,15 +1902,16 @@ static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
 
-       netdev_info(vsi->netdev, "removing %pM vid=%d\n",
-                   netdev->dev_addr, vid);
+       netdev_info(netdev, "removing %pM vid=%d\n", netdev->dev_addr, vid);
+
        /* return code is ignored as there is nothing a user
         * can do about failure to remove and a log message was
-        * already printed from another function
+        * already printed from the other function
         */
        i40e_vsi_kill_vlan(vsi, vid);
 
        clear_bit(vid, vsi->active_vlans);
+
        return 0;
 }
 
@@ -1936,10 +1938,10 @@ static void i40e_restore_vlan(struct i40e_vsi *vsi)
  * @vsi: the vsi being adjusted
  * @vid: the vlan id to set as a PVID
  **/
-i40e_status i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid)
+int i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid)
 {
        struct i40e_vsi_context ctxt;
-       i40e_status ret;
+       i40e_status aq_ret;
 
        vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
        vsi->info.pvid = cpu_to_le16(vid);
@@ -1948,14 +1950,15 @@ i40e_status i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid)
 
        ctxt.seid = vsi->seid;
        memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
-       ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL);
-       if (ret) {
+       aq_ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL);
+       if (aq_ret) {
                dev_info(&vsi->back->pdev->dev,
                         "%s: update vsi failed, aq_err=%d\n",
                         __func__, vsi->back->hw.aq.asq_last_status);
+               return -ENOENT;
        }
 
-       return ret;
+       return 0;
 }
 
 /**
@@ -3326,7 +3329,8 @@ static void i40e_pf_unquiesce_all_vsi(struct i40e_pf *pf)
  **/
 static u8 i40e_dcb_get_num_tc(struct i40e_dcbx_config *dcbcfg)
 {
-       int num_tc = 0, i;
+       u8 num_tc = 0;
+       int i;
 
        /* Scan the ETS Config Priority Table to find
         * traffic class enabled for a given priority
@@ -3341,9 +3345,7 @@ static u8 i40e_dcb_get_num_tc(struct i40e_dcbx_config *dcbcfg)
        /* Traffic class index starts from zero so
         * increment to return the actual count
         */
-       num_tc++;
-
-       return num_tc;
+       return num_tc + 1;
 }
 
 /**
@@ -3451,28 +3453,27 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi)
        struct i40e_aqc_query_vsi_bw_config_resp bw_config = {0};
        struct i40e_pf *pf = vsi->back;
        struct i40e_hw *hw = &pf->hw;
+       i40e_status aq_ret;
        u32 tc_bw_max;
-       int ret;
        int i;
 
        /* Get the VSI level BW configuration */
-       ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL);
-       if (ret) {
+       aq_ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL);
+       if (aq_ret) {
                dev_info(&pf->pdev->dev,
                         "couldn't get pf vsi bw config, err %d, aq_err %d\n",
-                        ret, pf->hw.aq.asq_last_status);
-               return ret;
+                        aq_ret, pf->hw.aq.asq_last_status);
+               return -EINVAL;
        }
 
        /* Get the VSI level BW configuration per TC */
-       ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid,
-                                              &bw_ets_config,
-                                              NULL);
-       if (ret) {
+       aq_ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config,
+                                                 NULL);
+       if (aq_ret) {
                dev_info(&pf->pdev->dev,
                         "couldn't get pf vsi ets bw config, err %d, aq_err %d\n",
-                        ret, pf->hw.aq.asq_last_status);
-               return ret;
+                        aq_ret, pf->hw.aq.asq_last_status);
+               return -EINVAL;
        }
 
        if (bw_config.tc_valid_bits != bw_ets_config.tc_valid_bits) {
@@ -3494,7 +3495,8 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi)
                /* 3 bits out of 4 for each TC */
                vsi->bw_ets_max_quanta[i] = (u8)((tc_bw_max >> (i*4)) & 0x7);
        }
-       return ret;
+
+       return 0;
 }
 
 /**
@@ -3505,30 +3507,30 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi)
  *
  * Returns 0 on success, negative value on failure
  **/
-static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi,
-                                      u8 enabled_tc,
+static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
                                       u8 *bw_share)
 {
        struct i40e_aqc_configure_vsi_tc_bw_data bw_data;
-       int i, ret = 0;
+       i40e_status aq_ret;
+       int i;
 
        bw_data.tc_valid_bits = enabled_tc;
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
                bw_data.tc_bw_credits[i] = bw_share[i];
 
-       ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid,
-                                      &bw_data, NULL);
-       if (ret) {
+       aq_ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid, &bw_data,
+                                         NULL);
+       if (aq_ret) {
                dev_info(&vsi->back->pdev->dev,
                         "%s: AQ command Config VSI BW allocation per TC failed = %d\n",
                         __func__, vsi->back->hw.aq.asq_last_status);
-               return ret;
+               return -EINVAL;
        }
 
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
                vsi->info.qs_handle[i] = bw_data.qs_handles[i];
 
-       return ret;
+       return 0;
 }
 
 /**
index 48cbc83..151e00c 100644 (file)
@@ -1607,6 +1607,9 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
                        igb_write_phy_reg(hw, I347AT4_PAGE_SELECT, 0);
                        igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);
                }
+       } else if (hw->phy.type == e1000_phy_82580) {
+               /* enable MII loopback */
+               igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041);
        }
 
        /* add small delay to avoid loopback test failure */
@@ -2652,6 +2655,8 @@ static int igb_set_eee(struct net_device *netdev,
            (hw->phy.media_type != e1000_media_type_copper))
                return -EOPNOTSUPP;
 
+       memset(&eee_curr, 0, sizeof(struct ethtool_eee));
+
        ret_val = igb_get_eee(netdev, &eee_curr);
        if (ret_val)
                return ret_val;
index 7fb5677..2c210ec 100644 (file)
@@ -1131,15 +1131,13 @@ static void mib_counters_update(struct mv643xx_eth_private *mp)
        p->rx_discard += rdlp(mp, RX_DISCARD_FRAME_CNT);
        p->rx_overrun += rdlp(mp, RX_OVERRUN_FRAME_CNT);
        spin_unlock_bh(&mp->mib_counters_lock);
-
-       mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ);
 }
 
 static void mib_counters_timer_wrapper(unsigned long _mp)
 {
        struct mv643xx_eth_private *mp = (void *)_mp;
-
        mib_counters_update(mp);
+       mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ);
 }
 
 
@@ -2237,6 +2235,7 @@ static int mv643xx_eth_open(struct net_device *dev)
                mp->int_mask |= INT_TX_END_0 << i;
        }
 
+       add_timer(&mp->mib_counters_timer);
        port_start(mp);
 
        wrlp(mp, INT_MASK_EXT, INT_EXT_LINK_PHY | INT_EXT_TX);
@@ -2534,6 +2533,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
        if (!ppdev)
                return -ENOMEM;
        ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+       ppdev->dev.of_node = pnp;
 
        ret = platform_device_add_resources(ppdev, &res, 1);
        if (ret)
@@ -2916,7 +2916,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
        mp->mib_counters_timer.data = (unsigned long)mp;
        mp->mib_counters_timer.function = mib_counters_timer_wrapper;
        mp->mib_counters_timer.expires = jiffies + 30 * HZ;
-       add_timer(&mp->mib_counters_timer);
 
        spin_lock_init(&mp->mib_counters_lock);
 
index 1a9c4f6..ecc7f7b 100644 (file)
@@ -3086,13 +3086,16 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
                                               PCI_DMA_FROMDEVICE);
                skge_rx_reuse(e, skge->rx_buf_size);
        } else {
+               struct skge_element ee;
                struct sk_buff *nskb;
 
                nskb = netdev_alloc_skb_ip_align(dev, skge->rx_buf_size);
                if (!nskb)
                        goto resubmit;
 
-               skb = e->skb;
+               ee = *e;
+
+               skb = ee.skb;
                prefetch(skb->data);
 
                if (skge_rx_setup(skge, e, nskb, skge->rx_buf_size) < 0) {
@@ -3101,8 +3104,8 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
                }
 
                pci_unmap_single(skge->hw->pdev,
-                                dma_unmap_addr(e, mapaddr),
-                                dma_unmap_len(e, maplen),
+                                dma_unmap_addr(&ee, mapaddr),
+                                dma_unmap_len(&ee, maplen),
                                 PCI_DMA_FROMDEVICE);
        }
 
index dec455c..afe2efa 100644 (file)
@@ -70,14 +70,15 @@ static int mlx4_alloc_pages(struct mlx4_en_priv *priv,
                put_page(page);
                return -ENOMEM;
        }
-       page_alloc->size = PAGE_SIZE << order;
+       page_alloc->page_size = PAGE_SIZE << order;
        page_alloc->page = page;
        page_alloc->dma = dma;
-       page_alloc->offset = frag_info->frag_align;
+       page_alloc->page_offset = frag_info->frag_align;
        /* Not doing get_page() for each frag is a big win
         * on asymetric workloads.
         */
-       atomic_set(&page->_count, page_alloc->size / frag_info->frag_stride);
+       atomic_set(&page->_count,
+                  page_alloc->page_size / frag_info->frag_stride);
        return 0;
 }
 
@@ -96,16 +97,19 @@ static int mlx4_en_alloc_frags(struct mlx4_en_priv *priv,
        for (i = 0; i < priv->num_frags; i++) {
                frag_info = &priv->frag_info[i];
                page_alloc[i] = ring_alloc[i];
-               page_alloc[i].offset += frag_info->frag_stride;
-               if (page_alloc[i].offset + frag_info->frag_stride <= ring_alloc[i].size)
+               page_alloc[i].page_offset += frag_info->frag_stride;
+
+               if (page_alloc[i].page_offset + frag_info->frag_stride <=
+                   ring_alloc[i].page_size)
                        continue;
+
                if (mlx4_alloc_pages(priv, &page_alloc[i], frag_info, gfp))
                        goto out;
        }
 
        for (i = 0; i < priv->num_frags; i++) {
                frags[i] = ring_alloc[i];
-               dma = ring_alloc[i].dma + ring_alloc[i].offset;
+               dma = ring_alloc[i].dma + ring_alloc[i].page_offset;
                ring_alloc[i] = page_alloc[i];
                rx_desc->data[i].addr = cpu_to_be64(dma);
        }
@@ -117,7 +121,7 @@ out:
                frag_info = &priv->frag_info[i];
                if (page_alloc[i].page != ring_alloc[i].page) {
                        dma_unmap_page(priv->ddev, page_alloc[i].dma,
-                               page_alloc[i].size, PCI_DMA_FROMDEVICE);
+                               page_alloc[i].page_size, PCI_DMA_FROMDEVICE);
                        page = page_alloc[i].page;
                        atomic_set(&page->_count, 1);
                        put_page(page);
@@ -131,10 +135,12 @@ static void mlx4_en_free_frag(struct mlx4_en_priv *priv,
                              int i)
 {
        const struct mlx4_en_frag_info *frag_info = &priv->frag_info[i];
+       u32 next_frag_end = frags[i].page_offset + 2 * frag_info->frag_stride;
+
 
-       if (frags[i].offset + frag_info->frag_stride > frags[i].size)
-               dma_unmap_page(priv->ddev, frags[i].dma, frags[i].size,
-                                        PCI_DMA_FROMDEVICE);
+       if (next_frag_end > frags[i].page_size)
+               dma_unmap_page(priv->ddev, frags[i].dma, frags[i].page_size,
+                              PCI_DMA_FROMDEVICE);
 
        if (frags[i].page)
                put_page(frags[i].page);
@@ -161,7 +167,7 @@ out:
 
                page_alloc = &ring->page_alloc[i];
                dma_unmap_page(priv->ddev, page_alloc->dma,
-                              page_alloc->size, PCI_DMA_FROMDEVICE);
+                              page_alloc->page_size, PCI_DMA_FROMDEVICE);
                page = page_alloc->page;
                atomic_set(&page->_count, 1);
                put_page(page);
@@ -184,10 +190,11 @@ static void mlx4_en_destroy_allocator(struct mlx4_en_priv *priv,
                       i, page_count(page_alloc->page));
 
                dma_unmap_page(priv->ddev, page_alloc->dma,
-                               page_alloc->size, PCI_DMA_FROMDEVICE);
-               while (page_alloc->offset + frag_info->frag_stride < page_alloc->size) {
+                               page_alloc->page_size, PCI_DMA_FROMDEVICE);
+               while (page_alloc->page_offset + frag_info->frag_stride <
+                      page_alloc->page_size) {
                        put_page(page_alloc->page);
-                       page_alloc->offset += frag_info->frag_stride;
+                       page_alloc->page_offset += frag_info->frag_stride;
                }
                page_alloc->page = NULL;
        }
@@ -478,7 +485,7 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
                /* Save page reference in skb */
                __skb_frag_set_page(&skb_frags_rx[nr], frags[nr].page);
                skb_frag_size_set(&skb_frags_rx[nr], frag_info->frag_size);
-               skb_frags_rx[nr].page_offset = frags[nr].offset;
+               skb_frags_rx[nr].page_offset = frags[nr].page_offset;
                skb->truesize += frag_info->frag_stride;
                frags[nr].page = NULL;
        }
@@ -517,7 +524,7 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
 
        /* Get pointer to first fragment so we could copy the headers into the
         * (linear part of the) skb */
-       va = page_address(frags[0].page) + frags[0].offset;
+       va = page_address(frags[0].page) + frags[0].page_offset;
 
        if (length <= SMALL_PACKET_SIZE) {
                /* We are copying all relevant data to the skb - temporarily
@@ -645,7 +652,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                        dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
                                                DMA_FROM_DEVICE);
                        ethh = (struct ethhdr *)(page_address(frags[0].page) +
-                                                frags[0].offset);
+                                                frags[0].page_offset);
 
                        if (is_multicast_ether_addr(ethh->h_dest)) {
                                struct mlx4_mac_entry *entry;
index 5e0aa56..bf06e36 100644 (file)
@@ -237,8 +237,8 @@ struct mlx4_en_tx_desc {
 struct mlx4_en_rx_alloc {
        struct page     *page;
        dma_addr_t      dma;
-       u32             offset;
-       u32             size;
+       u32             page_offset;
+       u32             page_size;
 };
 
 struct mlx4_en_tx_ring {
index 5472cbd..6ca3073 100644 (file)
@@ -180,28 +180,32 @@ static int verify_block_sig(struct mlx5_cmd_prot_block *block)
        return 0;
 }
 
-static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token)
+static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token,
+                          int csum)
 {
        block->token = token;
-       block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 2);
-       block->sig = ~xor8_buf(block, sizeof(*block) - 1);
+       if (csum) {
+               block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) -
+                                           sizeof(block->data) - 2);
+               block->sig = ~xor8_buf(block, sizeof(*block) - 1);
+       }
 }
 
-static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token)
+static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token, int csum)
 {
        struct mlx5_cmd_mailbox *next = msg->next;
 
        while (next) {
-               calc_block_sig(next->buf, token);
+               calc_block_sig(next->buf, token, csum);
                next = next->next;
        }
 }
 
-static void set_signature(struct mlx5_cmd_work_ent *ent)
+static void set_signature(struct mlx5_cmd_work_ent *ent, int csum)
 {
        ent->lay->sig = ~xor8_buf(ent->lay, sizeof(*ent->lay));
-       calc_chain_sig(ent->in, ent->token);
-       calc_chain_sig(ent->out, ent->token);
+       calc_chain_sig(ent->in, ent->token, csum);
+       calc_chain_sig(ent->out, ent->token, csum);
 }
 
 static void poll_timeout(struct mlx5_cmd_work_ent *ent)
@@ -539,8 +543,7 @@ static void cmd_work_handler(struct work_struct *work)
        lay->type = MLX5_PCI_CMD_XPORT;
        lay->token = ent->token;
        lay->status_own = CMD_OWNER_HW;
-       if (!cmd->checksum_disabled)
-               set_signature(ent);
+       set_signature(ent, !cmd->checksum_disabled);
        dump_command(dev, ent, 1);
        ktime_get_ts(&ent->ts1);
 
@@ -773,8 +776,6 @@ static int mlx5_copy_from_msg(void *to, struct mlx5_cmd_msg *from, int size)
 
                copy = min_t(int, size, MLX5_CMD_DATA_BLOCK_SIZE);
                block = next->buf;
-               if (xor8_buf(block, sizeof(*block)) != 0xff)
-                       return -EINVAL;
 
                memcpy(to, block->data, copy);
                to += copy;
@@ -1361,6 +1362,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)
                goto err_map;
        }
 
+       cmd->checksum_disabled = 1;
        cmd->max_reg_cmds = (1 << cmd->log_sz) - 1;
        cmd->bitmask = (1 << cmd->max_reg_cmds) - 1;
 
@@ -1510,7 +1512,7 @@ int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr)
        case MLX5_CMD_STAT_BAD_SYS_STATE_ERR:           return -EIO;
        case MLX5_CMD_STAT_BAD_RES_ERR:                 return -EINVAL;
        case MLX5_CMD_STAT_RES_BUSY:                    return -EBUSY;
-       case MLX5_CMD_STAT_LIM_ERR:                     return -EINVAL;
+       case MLX5_CMD_STAT_LIM_ERR:                     return -ENOMEM;
        case MLX5_CMD_STAT_BAD_RES_STATE_ERR:           return -EINVAL;
        case MLX5_CMD_STAT_IX_ERR:                      return -EINVAL;
        case MLX5_CMD_STAT_NO_RES_ERR:                  return -EAGAIN;
index 443cc4d..2231d93 100644 (file)
@@ -366,9 +366,11 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
                goto err_in;
        }
 
+       snprintf(eq->name, MLX5_MAX_EQ_NAME, "%s@pci:%s",
+                name, pci_name(dev->pdev));
        eq->eqn = out.eq_number;
        err = request_irq(table->msix_arr[vecidx].vector, mlx5_msix_handler, 0,
-                         name, eq);
+                         eq->name, eq);
        if (err)
                goto err_eq;
 
index b47739b..bc0f5fb 100644 (file)
@@ -165,9 +165,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
        struct mlx5_cmd_set_hca_cap_mbox_in *set_ctx = NULL;
        struct mlx5_cmd_query_hca_cap_mbox_in query_ctx;
        struct mlx5_cmd_set_hca_cap_mbox_out set_out;
-       struct mlx5_profile *prof = dev->profile;
        u64 flags;
-       int csum = 1;
        int err;
 
        memset(&query_ctx, 0, sizeof(query_ctx));
@@ -197,20 +195,14 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
        memcpy(&set_ctx->hca_cap, &query_out->hca_cap,
               sizeof(set_ctx->hca_cap));
 
-       if (prof->mask & MLX5_PROF_MASK_CMDIF_CSUM) {
-               csum = !!prof->cmdif_csum;
-               flags = be64_to_cpu(set_ctx->hca_cap.flags);
-               if (csum)
-                       flags |= MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
-               else
-                       flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
-
-               set_ctx->hca_cap.flags = cpu_to_be64(flags);
-       }
-
        if (dev->profile->mask & MLX5_PROF_MASK_QP_SIZE)
                set_ctx->hca_cap.log_max_qp = dev->profile->log_max_qp;
 
+       flags = be64_to_cpu(query_out->hca_cap.flags);
+       /* disable checksum */
+       flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
+
+       set_ctx->hca_cap.flags = cpu_to_be64(flags);
        memset(&set_out, 0, sizeof(set_out));
        set_ctx->hca_cap.log_uar_page_sz = cpu_to_be16(PAGE_SHIFT - 12);
        set_ctx->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_SET_HCA_CAP);
@@ -225,9 +217,6 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
        if (err)
                goto query_ex;
 
-       if (!csum)
-               dev->cmd.checksum_disabled = 1;
-
 query_ex:
        kfree(query_out);
        kfree(set_ctx);
index 3a2408d..7b12acf 100644 (file)
@@ -90,6 +90,10 @@ struct mlx5_manage_pages_outbox {
        __be64                  pas[0];
 };
 
+enum {
+       MAX_RECLAIM_TIME_MSECS  = 5000,
+};
+
 static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u16 func_id)
 {
        struct rb_root *root = &dev->priv.page_root;
@@ -279,6 +283,9 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
        int err;
        int i;
 
+       if (nclaimed)
+               *nclaimed = 0;
+
        memset(&in, 0, sizeof(in));
        outlen = sizeof(*out) + npages * sizeof(out->pas[0]);
        out = mlx5_vzalloc(outlen);
@@ -388,20 +395,25 @@ static int optimal_reclaimed_pages(void)
 
 int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)
 {
-       unsigned long end = jiffies + msecs_to_jiffies(5000);
+       unsigned long end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS);
        struct fw_page *fwp;
        struct rb_node *p;
+       int nclaimed = 0;
        int err;
 
        do {
                p = rb_first(&dev->priv.page_root);
                if (p) {
                        fwp = rb_entry(p, struct fw_page, rb_node);
-                       err = reclaim_pages(dev, fwp->func_id, optimal_reclaimed_pages(), NULL);
+                       err = reclaim_pages(dev, fwp->func_id,
+                                           optimal_reclaimed_pages(),
+                                           &nclaimed);
                        if (err) {
                                mlx5_core_warn(dev, "failed reclaiming pages (%d)\n", err);
                                return err;
                        }
+                       if (nclaimed)
+                               end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS);
                }
                if (time_after(jiffies, end)) {
                        mlx5_core_warn(dev, "FW did not return all pages. giving up...\n");
index 83c2091..ea54d95 100644 (file)
@@ -448,7 +448,8 @@ static int moxart_mac_probe(struct platform_device *pdev)
        irq = irq_of_parse_and_map(node, 0);
        if (irq <= 0) {
                netdev_err(ndev, "irq_of_parse_and_map failed\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto irq_map_fail;
        }
 
        priv = netdev_priv(ndev);
@@ -472,24 +473,32 @@ static int moxart_mac_probe(struct platform_device *pdev)
        priv->tx_desc_base = dma_alloc_coherent(NULL, TX_REG_DESC_SIZE *
                                                TX_DESC_NUM, &priv->tx_base,
                                                GFP_DMA | GFP_KERNEL);
-       if (priv->tx_desc_base == NULL)
+       if (priv->tx_desc_base == NULL) {
+               ret = -ENOMEM;
                goto init_fail;
+       }
 
        priv->rx_desc_base = dma_alloc_coherent(NULL, RX_REG_DESC_SIZE *
                                                RX_DESC_NUM, &priv->rx_base,
                                                GFP_DMA | GFP_KERNEL);
-       if (priv->rx_desc_base == NULL)
+       if (priv->rx_desc_base == NULL) {
+               ret = -ENOMEM;
                goto init_fail;
+       }
 
        priv->tx_buf_base = kmalloc(priv->tx_buf_size * TX_DESC_NUM,
                                    GFP_ATOMIC);
-       if (!priv->tx_buf_base)
+       if (!priv->tx_buf_base) {
+               ret = -ENOMEM;
                goto init_fail;
+       }
 
        priv->rx_buf_base = kmalloc(priv->rx_buf_size * RX_DESC_NUM,
                                    GFP_ATOMIC);
-       if (!priv->rx_buf_base)
+       if (!priv->rx_buf_base) {
+               ret = -ENOMEM;
                goto init_fail;
+       }
 
        platform_set_drvdata(pdev, ndev);
 
@@ -522,7 +531,8 @@ static int moxart_mac_probe(struct platform_device *pdev)
 init_fail:
        netdev_err(ndev, "init failed\n");
        moxart_mac_free_memory(ndev);
-
+irq_map_fail:
+       free_netdev(ndev);
        return ret;
 }
 
@@ -543,7 +553,7 @@ static const struct of_device_id moxart_mac_match[] = {
        { }
 };
 
-struct __initdata platform_driver moxart_mac_driver = {
+static struct platform_driver moxart_mac_driver = {
        .probe  = moxart_mac_probe,
        .remove = moxart_remove,
        .driver = {
index 4d7ad00..ff83a9f 100644 (file)
@@ -665,7 +665,7 @@ static int qlcnic_set_channels(struct net_device *dev,
                        return err;
        }
 
-       if (channel->tx_count) {
+       if (qlcnic_82xx_check(adapter) && channel->tx_count) {
                err = qlcnic_validate_max_tx_rings(adapter, channel->tx_count);
                if (err)
                        return err;
@@ -1794,3 +1794,11 @@ const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops = {
        .set_msglevel           = qlcnic_set_msglevel,
        .get_msglevel           = qlcnic_get_msglevel,
 };
+
+const struct ethtool_ops qlcnic_ethtool_failed_ops = {
+       .get_settings           = qlcnic_get_settings,
+       .get_drvinfo            = qlcnic_get_drvinfo,
+       .set_msglevel           = qlcnic_set_msglevel,
+       .get_msglevel           = qlcnic_get_msglevel,
+       .set_dump               = qlcnic_set_dump,
+};
index c4c5023..9e61eb8 100644 (file)
@@ -431,6 +431,9 @@ static void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter)
        while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
                usleep_range(10000, 11000);
 
+       if (!adapter->fw_work.work.func)
+               return;
+
        cancel_delayed_work_sync(&adapter->fw_work);
 }
 
@@ -2254,7 +2257,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        err = qlcnic_alloc_adapter_resources(adapter);
        if (err)
-               goto err_out_free_netdev;
+               goto err_out_free_wq;
 
        adapter->dev_rst_time = jiffies;
        adapter->ahw->revision_id = pdev->revision;
@@ -2275,8 +2278,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                adapter->portnum = adapter->ahw->pci_func;
                err = qlcnic_start_firmware(adapter);
                if (err) {
-                       dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
-                       goto err_out_free_hw;
+                       dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"
+                               "\t\tIf reboot doesn't help, try flashing the card\n");
+                       goto err_out_maintenance_mode;
                }
 
                qlcnic_get_multiq_capability(adapter);
@@ -2392,6 +2396,9 @@ err_out_disable_msi:
 err_out_free_hw:
        qlcnic_free_adapter_resources(adapter);
 
+err_out_free_wq:
+       destroy_workqueue(adapter->qlcnic_wq);
+
 err_out_free_netdev:
        free_netdev(netdev);
 
@@ -2408,6 +2415,22 @@ err_out_disable_pdev:
        pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
        return err;
+
+err_out_maintenance_mode:
+       netdev->netdev_ops = &qlcnic_netdev_failed_ops;
+       SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
+       err = register_netdev(netdev);
+
+       if (err) {
+               dev_err(&pdev->dev, "Failed to register net device\n");
+               qlcnic_clr_all_drv_state(adapter, 0);
+               goto err_out_free_hw;
+       }
+
+       pci_set_drvdata(pdev, adapter);
+       qlcnic_add_sysfs(adapter);
+
+       return 0;
 }
 
 static void qlcnic_remove(struct pci_dev *pdev)
@@ -2518,8 +2541,16 @@ static int qlcnic_resume(struct pci_dev *pdev)
 static int qlcnic_open(struct net_device *netdev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       u32 state;
        int err;
 
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD) {
+               netdev_err(netdev, "%s: Device is in FAILED state\n", __func__);
+
+               return -EIO;
+       }
+
        netif_carrier_off(netdev);
 
        err = qlcnic_attach(adapter);
@@ -3228,6 +3259,13 @@ void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key)
                return;
 
        state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD) {
+               netdev_err(adapter->netdev, "%s: Device is in FAILED state\n",
+                          __func__);
+               qlcnic_api_unlock(adapter);
+
+               return;
+       }
 
        if (state == QLCNIC_DEV_READY) {
                QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
@@ -3613,11 +3651,6 @@ int qlcnic_validate_max_tx_rings(struct qlcnic_adapter *adapter, u32 txq)
        u8 max_hw = QLCNIC_MAX_TX_RINGS;
        u32 max_allowed;
 
-       if (!qlcnic_82xx_check(adapter)) {
-               netdev_err(netdev, "No Multi TX-Q support\n");
-               return -EINVAL;
-       }
-
        if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
                netdev_err(netdev, "No Multi TX-Q support in INT-x mode\n");
                return -EINVAL;
@@ -3657,8 +3690,7 @@ int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter,
        u8 max_hw = adapter->ahw->max_rx_ques;
        u32 max_allowed;
 
-       if (qlcnic_82xx_check(adapter) && !qlcnic_use_msi_x &&
-           !qlcnic_use_msi) {
+       if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
                netdev_err(netdev, "No RSS support in INT-x mode\n");
                return -EINVAL;
        }
index 330d9a8..686f460 100644 (file)
@@ -397,6 +397,7 @@ static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
 
+       rtnl_lock();
        if (netif_running(netdev))
                __qlcnic_down(adapter, netdev);
 
@@ -407,12 +408,15 @@ static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter)
        /* After disabling SRIOV re-init the driver in default mode
           configure opmode based on op_mode of function
         */
-       if (qlcnic_83xx_configure_opmode(adapter))
+       if (qlcnic_83xx_configure_opmode(adapter)) {
+               rtnl_unlock();
                return -EIO;
+       }
 
        if (netif_running(netdev))
                __qlcnic_up(adapter, netdev);
 
+       rtnl_unlock();
        return 0;
 }
 
@@ -533,6 +537,7 @@ static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs)
                return -EIO;
        }
 
+       rtnl_lock();
        if (netif_running(netdev))
                __qlcnic_down(adapter, netdev);
 
@@ -555,6 +560,7 @@ static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs)
                __qlcnic_up(adapter, netdev);
 
 error:
+       rtnl_unlock();
        return err;
 }
 
index c6165d0..019f437 100644 (file)
@@ -1272,6 +1272,7 @@ void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
 void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
+       u32 state;
 
        if (device_create_bin_file(dev, &bin_attr_port_stats))
                dev_info(dev, "failed to create port stats sysfs entry");
@@ -1285,8 +1286,13 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
        if (device_create_bin_file(dev, &bin_attr_mem))
                dev_info(dev, "failed to create mem sysfs entry\n");
 
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD)
+               return;
+
        if (device_create_bin_file(dev, &bin_attr_pci_config))
                dev_info(dev, "failed to create pci config sysfs entry");
+
        if (device_create_file(dev, &dev_attr_beacon))
                dev_info(dev, "failed to create beacon sysfs entry");
 
@@ -1307,6 +1313,7 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
+       u32 state;
 
        device_remove_bin_file(dev, &bin_attr_port_stats);
 
@@ -1315,6 +1322,11 @@ void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
        device_remove_file(dev, &dev_attr_diag_mode);
        device_remove_bin_file(dev, &bin_attr_crb);
        device_remove_bin_file(dev, &bin_attr_mem);
+
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD)
+               return;
+
        device_remove_bin_file(dev, &bin_attr_pci_config);
        device_remove_file(dev, &dev_attr_beacon);
        if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
index 10093f0..6bc5db7 100644 (file)
@@ -740,8 +740,8 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
        int i;
 
        if (!mpi_coredump) {
-               netif_err(qdev, drv, qdev->ndev, "No memory available\n");
-               return -ENOMEM;
+               netif_err(qdev, drv, qdev->ndev, "No memory allocated\n");
+               return -EINVAL;
        }
 
        /* Try to get the spinlock, but dont worry if
index ff2bf8a..7ad1460 100644 (file)
@@ -1274,7 +1274,7 @@ void ql_mpi_reset_work(struct work_struct *work)
                return;
        }
 
-       if (!ql_core_dump(qdev, qdev->mpi_coredump)) {
+       if (qdev->mpi_coredump && !ql_core_dump(qdev, qdev->mpi_coredump)) {
                netif_err(qdev, drv, qdev->ndev, "Core is dumped!\n");
                qdev->core_is_dumped = 1;
                queue_delayed_work(qdev->workqueue,
index 5cd831e..b57c278 100644 (file)
@@ -688,12 +688,16 @@ static struct sh_eth_cpu_data r8a7740_data = {
        .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
                          EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
                          EESR_TDE | EESR_ECI,
+       .fdr_value      = 0x0000070f,
+       .rmcr_value     = 0x00000001,
 
        .apr            = 1,
        .mpr            = 1,
        .tpauser        = 1,
        .bculr          = 1,
        .hw_swap        = 1,
+       .rpadir         = 1,
+       .rpadir_value   = 2 << 16,
        .no_trimd       = 1,
        .no_ade         = 1,
        .tsu            = 1,
index 9f18ae9..21f9ad6 100644 (file)
@@ -444,6 +444,18 @@ static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = {
        EF10_DMA_STAT(rx_align_error, RX_ALIGN_ERROR_PKTS),
        EF10_DMA_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS),
        EF10_DMA_STAT(rx_nodesc_drops, RX_NODESC_DROPS),
+       EF10_DMA_STAT(rx_pm_trunc_bb_overflow, PM_TRUNC_BB_OVERFLOW),
+       EF10_DMA_STAT(rx_pm_discard_bb_overflow, PM_DISCARD_BB_OVERFLOW),
+       EF10_DMA_STAT(rx_pm_trunc_vfifo_full, PM_TRUNC_VFIFO_FULL),
+       EF10_DMA_STAT(rx_pm_discard_vfifo_full, PM_DISCARD_VFIFO_FULL),
+       EF10_DMA_STAT(rx_pm_trunc_qbb, PM_TRUNC_QBB),
+       EF10_DMA_STAT(rx_pm_discard_qbb, PM_DISCARD_QBB),
+       EF10_DMA_STAT(rx_pm_discard_mapping, PM_DISCARD_MAPPING),
+       EF10_DMA_STAT(rx_dp_q_disabled_packets, RXDP_Q_DISABLED_PKTS),
+       EF10_DMA_STAT(rx_dp_di_dropped_packets, RXDP_DI_DROPPED_PKTS),
+       EF10_DMA_STAT(rx_dp_streaming_packets, RXDP_STREAMING_PKTS),
+       EF10_DMA_STAT(rx_dp_emerg_fetch, RXDP_EMERGENCY_FETCH_CONDITIONS),
+       EF10_DMA_STAT(rx_dp_emerg_wait, RXDP_EMERGENCY_WAIT_CONDITIONS),
 };
 
 #define HUNT_COMMON_STAT_MASK ((1ULL << EF10_STAT_tx_bytes) |          \
@@ -498,44 +510,72 @@ static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = {
 #define HUNT_40G_EXTRA_STAT_MASK ((1ULL << EF10_STAT_rx_align_error) | \
                                  (1ULL << EF10_STAT_rx_length_error))
 
-#if BITS_PER_LONG == 64
-#define STAT_MASK_BITMAP(bits) (bits)
-#else
-#define STAT_MASK_BITMAP(bits) (bits) & 0xffffffff, (bits) >> 32
-#endif
-
-static const unsigned long *efx_ef10_stat_mask(struct efx_nic *efx)
-{
-       static const unsigned long hunt_40g_stat_mask[] = {
-               STAT_MASK_BITMAP(HUNT_COMMON_STAT_MASK |
-                                HUNT_40G_EXTRA_STAT_MASK)
-       };
-       static const unsigned long hunt_10g_only_stat_mask[] = {
-               STAT_MASK_BITMAP(HUNT_COMMON_STAT_MASK |
-                                HUNT_10G_ONLY_STAT_MASK)
-       };
+/* These statistics are only provided if the firmware supports the
+ * capability PM_AND_RXDP_COUNTERS.
+ */
+#define HUNT_PM_AND_RXDP_STAT_MASK (                                   \
+       (1ULL << EF10_STAT_rx_pm_trunc_bb_overflow) |                   \
+       (1ULL << EF10_STAT_rx_pm_discard_bb_overflow) |                 \
+       (1ULL << EF10_STAT_rx_pm_trunc_vfifo_full) |                    \
+       (1ULL << EF10_STAT_rx_pm_discard_vfifo_full) |                  \
+       (1ULL << EF10_STAT_rx_pm_trunc_qbb) |                           \
+       (1ULL << EF10_STAT_rx_pm_discard_qbb) |                         \
+       (1ULL << EF10_STAT_rx_pm_discard_mapping) |                     \
+       (1ULL << EF10_STAT_rx_dp_q_disabled_packets) |                  \
+       (1ULL << EF10_STAT_rx_dp_di_dropped_packets) |                  \
+       (1ULL << EF10_STAT_rx_dp_streaming_packets) |                   \
+       (1ULL << EF10_STAT_rx_dp_emerg_fetch) |                         \
+       (1ULL << EF10_STAT_rx_dp_emerg_wait))
+
+static u64 efx_ef10_raw_stat_mask(struct efx_nic *efx)
+{
+       u64 raw_mask = HUNT_COMMON_STAT_MASK;
        u32 port_caps = efx_mcdi_phy_get_caps(efx);
+       struct efx_ef10_nic_data *nic_data = efx->nic_data;
 
        if (port_caps & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
-               return hunt_40g_stat_mask;
+               raw_mask |= HUNT_40G_EXTRA_STAT_MASK;
        else
-               return hunt_10g_only_stat_mask;
+               raw_mask |= HUNT_10G_ONLY_STAT_MASK;
+
+       if (nic_data->datapath_caps &
+           (1 << MC_CMD_GET_CAPABILITIES_OUT_PM_AND_RXDP_COUNTERS_LBN))
+               raw_mask |= HUNT_PM_AND_RXDP_STAT_MASK;
+
+       return raw_mask;
+}
+
+static void efx_ef10_get_stat_mask(struct efx_nic *efx, unsigned long *mask)
+{
+       u64 raw_mask = efx_ef10_raw_stat_mask(efx);
+
+#if BITS_PER_LONG == 64
+       mask[0] = raw_mask;
+#else
+       mask[0] = raw_mask & 0xffffffff;
+       mask[1] = raw_mask >> 32;
+#endif
 }
 
 static size_t efx_ef10_describe_stats(struct efx_nic *efx, u8 *names)
 {
+       DECLARE_BITMAP(mask, EF10_STAT_COUNT);
+
+       efx_ef10_get_stat_mask(efx, mask);
        return efx_nic_describe_stats(efx_ef10_stat_desc, EF10_STAT_COUNT,
-                                     efx_ef10_stat_mask(efx), names);
+                                     mask, names);
 }
 
 static int efx_ef10_try_update_nic_stats(struct efx_nic *efx)
 {
        struct efx_ef10_nic_data *nic_data = efx->nic_data;
-       const unsigned long *stats_mask = efx_ef10_stat_mask(efx);
+       DECLARE_BITMAP(mask, EF10_STAT_COUNT);
        __le64 generation_start, generation_end;
        u64 *stats = nic_data->stats;
        __le64 *dma_stats;
 
+       efx_ef10_get_stat_mask(efx, mask);
+
        dma_stats = efx->stats_buffer.addr;
        nic_data = efx->nic_data;
 
@@ -543,8 +583,9 @@ static int efx_ef10_try_update_nic_stats(struct efx_nic *efx)
        if (generation_end == EFX_MC_STATS_GENERATION_INVALID)
                return 0;
        rmb();
-       efx_nic_update_stats(efx_ef10_stat_desc, EF10_STAT_COUNT, stats_mask,
+       efx_nic_update_stats(efx_ef10_stat_desc, EF10_STAT_COUNT, mask,
                             stats, efx->stats_buffer.addr, false);
+       rmb();
        generation_start = dma_stats[MC_CMD_MAC_GENERATION_START];
        if (generation_end != generation_start)
                return -EAGAIN;
@@ -563,12 +604,14 @@ static int efx_ef10_try_update_nic_stats(struct efx_nic *efx)
 static size_t efx_ef10_update_stats(struct efx_nic *efx, u64 *full_stats,
                                    struct rtnl_link_stats64 *core_stats)
 {
-       const unsigned long *mask = efx_ef10_stat_mask(efx);
+       DECLARE_BITMAP(mask, EF10_STAT_COUNT);
        struct efx_ef10_nic_data *nic_data = efx->nic_data;
        u64 *stats = nic_data->stats;
        size_t stats_count = 0, index;
        int retry;
 
+       efx_ef10_get_stat_mask(efx, mask);
+
        /* If we're unlucky enough to read statistics during the DMA, wait
         * up to 10ms for it to finish (typically takes <500us)
         */
index 128d7cd..366c8e3 100644 (file)
 
 /* A reboot/assertion causes the MCDI status word to be set after the
  * command word is set or a REBOOT event is sent. If we notice a reboot
- * via these mechanisms then wait 20ms for the status word to be set.
+ * via these mechanisms then wait 250ms for the status word to be set.
  */
 #define MCDI_STATUS_DELAY_US           100
-#define MCDI_STATUS_DELAY_COUNT                200
+#define MCDI_STATUS_DELAY_COUNT                2500
 #define MCDI_STATUS_SLEEP_MS                                           \
        (MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000)
 
@@ -800,9 +800,6 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
        } else {
                int count;
 
-               /* Nobody was waiting for an MCDI request, so trigger a reset */
-               efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
-
                /* Consume the status word since efx_mcdi_rpc_finish() won't */
                for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) {
                        if (efx_mcdi_poll_reboot(efx))
@@ -810,6 +807,9 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
                        udelay(MCDI_STATUS_DELAY_US);
                }
                mcdi->new_epoch = true;
+
+               /* Nobody was waiting for an MCDI request, so trigger a reset */
+               efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
        }
 
        spin_unlock(&mcdi->iface_lock);
@@ -963,7 +963,7 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
                               bool *was_attached)
 {
        MCDI_DECLARE_BUF(inbuf, MC_CMD_DRV_ATTACH_IN_LEN);
-       MCDI_DECLARE_BUF(outbuf, MC_CMD_DRV_ATTACH_OUT_LEN);
+       MCDI_DECLARE_BUF(outbuf, MC_CMD_DRV_ATTACH_EXT_OUT_LEN);
        size_t outlen;
        int rc;
 
@@ -981,6 +981,22 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
                goto fail;
        }
 
+       /* We currently assume we have control of the external link
+        * and are completely trusted by firmware.  Abort probing
+        * if that's not true for this function.
+        */
+       if (driver_operating &&
+           outlen >= MC_CMD_DRV_ATTACH_EXT_OUT_LEN &&
+           (MCDI_DWORD(outbuf, DRV_ATTACH_EXT_OUT_FUNC_FLAGS) &
+            (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL |
+             1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)) !=
+           (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL |
+            1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)) {
+               netif_err(efx, probe, efx->net_dev,
+                         "This driver version only supports one function per port\n");
+               return -ENODEV;
+       }
+
        if (was_attached != NULL)
                *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE);
        return 0;
index b5cf624..e0a63dd 100644 (file)
 #define          MC_CMD_MAC_RX_LANES01_DISP_ERR  0x39 /* enum */
 #define          MC_CMD_MAC_RX_LANES23_DISP_ERR  0x3a /* enum */
 #define          MC_CMD_MAC_RX_MATCH_FAULT  0x3b /* enum */
-#define          MC_CMD_GMAC_DMABUF_START  0x40 /* enum */
-#define          MC_CMD_GMAC_DMABUF_END    0x5f /* enum */
+/* enum: PM trunc_bb_overflow counter. Valid for EF10 with PM_AND_RXDP_COUNTERS
+ * capability only.
+ */
+#define          MC_CMD_MAC_PM_TRUNC_BB_OVERFLOW  0x3c
+/* enum: PM discard_bb_overflow counter. Valid for EF10 with
+ * PM_AND_RXDP_COUNTERS capability only.
+ */
+#define          MC_CMD_MAC_PM_DISCARD_BB_OVERFLOW  0x3d
+/* enum: PM trunc_vfifo_full counter. Valid for EF10 with PM_AND_RXDP_COUNTERS
+ * capability only.
+ */
+#define          MC_CMD_MAC_PM_TRUNC_VFIFO_FULL  0x3e
+/* enum: PM discard_vfifo_full counter. Valid for EF10 with
+ * PM_AND_RXDP_COUNTERS capability only.
+ */
+#define          MC_CMD_MAC_PM_DISCARD_VFIFO_FULL  0x3f
+/* enum: PM trunc_qbb counter. Valid for EF10 with PM_AND_RXDP_COUNTERS
+ * capability only.
+ */
+#define          MC_CMD_MAC_PM_TRUNC_QBB  0x40
+/* enum: PM discard_qbb counter. Valid for EF10 with PM_AND_RXDP_COUNTERS
+ * capability only.
+ */
+#define          MC_CMD_MAC_PM_DISCARD_QBB  0x41
+/* enum: PM discard_mapping counter. Valid for EF10 with PM_AND_RXDP_COUNTERS
+ * capability only.
+ */
+#define          MC_CMD_MAC_PM_DISCARD_MAPPING  0x42
+/* enum: RXDP counter: Number of packets dropped due to the queue being
+ * disabled. Valid for EF10 with PM_AND_RXDP_COUNTERS capability only.
+ */
+#define          MC_CMD_MAC_RXDP_Q_DISABLED_PKTS  0x43
+/* enum: RXDP counter: Number of packets dropped by the DICPU. Valid for EF10
+ * with PM_AND_RXDP_COUNTERS capability only.
+ */
+#define          MC_CMD_MAC_RXDP_DI_DROPPED_PKTS  0x45
+/* enum: RXDP counter: Number of non-host packets. Valid for EF10 with
+ * PM_AND_RXDP_COUNTERS capability only.
+ */
+#define          MC_CMD_MAC_RXDP_STREAMING_PKTS  0x46
+/* enum: RXDP counter: Number of times an emergency descriptor fetch was
+ * performed. Valid for EF10 with PM_AND_RXDP_COUNTERS capability only.
+ */
+#define          MC_CMD_MAC_RXDP_EMERGENCY_FETCH_CONDITIONS  0x47
+/* enum: RXDP counter: Number of times the DPCPU waited for an existing
+ * descriptor fetch. Valid for EF10 with PM_AND_RXDP_COUNTERS capability only.
+ */
+#define          MC_CMD_MAC_RXDP_EMERGENCY_WAIT_CONDITIONS  0x48
+/* enum: Start of GMAC stats buffer space, for Siena only. */
+#define          MC_CMD_GMAC_DMABUF_START  0x40
+/* enum: End of GMAC stats buffer space, for Siena only. */
+#define          MC_CMD_GMAC_DMABUF_END    0x5f
 #define          MC_CMD_MAC_GENERATION_END 0x60 /* enum */
 #define          MC_CMD_MAC_NSTATS  0x61 /* enum */
 
 #define        MC_CMD_GET_CAPABILITIES_OUT_RX_BATCHING_WIDTH 1
 #define        MC_CMD_GET_CAPABILITIES_OUT_MCAST_FILTER_CHAINING_LBN 26
 #define        MC_CMD_GET_CAPABILITIES_OUT_MCAST_FILTER_CHAINING_WIDTH 1
+#define        MC_CMD_GET_CAPABILITIES_OUT_PM_AND_RXDP_COUNTERS_LBN 27
+#define        MC_CMD_GET_CAPABILITIES_OUT_PM_AND_RXDP_COUNTERS_WIDTH 1
 /* RxDPCPU firmware id. */
 #define       MC_CMD_GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID_OFST 4
 #define       MC_CMD_GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID_LEN 2
index e7dbd2d..9826594 100644 (file)
@@ -469,8 +469,7 @@ size_t efx_nic_describe_stats(const struct efx_hw_stat_desc *desc, size_t count,
  * @count: Length of the @desc array
  * @mask: Bitmask of which elements of @desc are enabled
  * @stats: Buffer to update with the converted statistics.  The length
- *     of this array must be at least the number of set bits in the
- *     first @count bits of @mask.
+ *     of this array must be at least @count.
  * @dma_buf: DMA buffer containing hardware statistics
  * @accumulate: If set, the converted values will be added rather than
  *     directly stored to the corresponding elements of @stats
@@ -503,11 +502,9 @@ void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count,
                        }
 
                        if (accumulate)
-                               *stats += val;
+                               stats[index] += val;
                        else
-                               *stats = val;
+                               stats[index] = val;
                }
-
-               ++stats;
        }
 }
index fda29d3..890bbbe 100644 (file)
@@ -386,6 +386,18 @@ enum {
        EF10_STAT_rx_align_error,
        EF10_STAT_rx_length_error,
        EF10_STAT_rx_nodesc_drops,
+       EF10_STAT_rx_pm_trunc_bb_overflow,
+       EF10_STAT_rx_pm_discard_bb_overflow,
+       EF10_STAT_rx_pm_trunc_vfifo_full,
+       EF10_STAT_rx_pm_discard_vfifo_full,
+       EF10_STAT_rx_pm_trunc_qbb,
+       EF10_STAT_rx_pm_discard_qbb,
+       EF10_STAT_rx_pm_discard_mapping,
+       EF10_STAT_rx_dp_q_disabled_packets,
+       EF10_STAT_rx_dp_di_dropped_packets,
+       EF10_STAT_rx_dp_streaming_packets,
+       EF10_STAT_rx_dp_emerg_fetch,
+       EF10_STAT_rx_dp_emerg_wait,
        EF10_STAT_COUNT
 };
 
index 5730fe2..98eedb9 100644 (file)
@@ -1124,8 +1124,7 @@ static const char * chip_ids[ 16 ] =  {
                        void __iomem *__ioaddr = ioaddr;                \
                        if (__len >= 2 && (unsigned long)__ptr & 2) {   \
                                __len -= 2;                             \
-                               SMC_outw(*(u16 *)__ptr, ioaddr,         \
-                                       DATA_REG(lp));          \
+                               SMC_outsw(ioaddr, DATA_REG(lp), __ptr, 1); \
                                __ptr += 2;                             \
                        }                                               \
                        if (SMC_CAN_USE_DATACS && lp->datacs)           \
@@ -1133,8 +1132,7 @@ static const char * chip_ids[ 16 ] =  {
                        SMC_outsl(__ioaddr, DATA_REG(lp), __ptr, __len>>2); \
                        if (__len & 2) {                                \
                                __ptr += (__len & ~3);                  \
-                               SMC_outw(*((u16 *)__ptr), ioaddr,       \
-                                        DATA_REG(lp));         \
+                               SMC_outsw(ioaddr, DATA_REG(lp), __ptr, 1); \
                        }                                               \
                } else if (SMC_16BIT(lp))                               \
                        SMC_outsw(ioaddr, DATA_REG(lp), p, (l) >> 1);   \
index 79974e3..cc3ce55 100644 (file)
@@ -639,13 +639,6 @@ void cpsw_rx_handler(void *token, int len, int status)
 static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
 {
        struct cpsw_priv *priv = dev_id;
-       u32 rx, tx, rx_thresh;
-
-       rx_thresh = __raw_readl(&priv->wr_regs->rx_thresh_stat);
-       rx = __raw_readl(&priv->wr_regs->rx_stat);
-       tx = __raw_readl(&priv->wr_regs->tx_stat);
-       if (!rx_thresh && !rx && !tx)
-               return IRQ_NONE;
 
        cpsw_intr_disable(priv);
        if (priv->irq_enabled == true) {
@@ -1169,9 +1162,9 @@ static int cpsw_ndo_open(struct net_device *ndev)
                }
        }
 
+       napi_enable(&priv->napi);
        cpdma_ctlr_start(priv->dma);
        cpsw_intr_enable(priv);
-       napi_enable(&priv->napi);
        cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
        cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
 
@@ -1771,8 +1764,8 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
        }
        data->mac_control = prop;
 
-       if (!of_property_read_u32(node, "dual_emac", &prop))
-               data->dual_emac = prop;
+       if (of_property_read_bool(node, "dual_emac"))
+               data->dual_emac = 1;
 
        /*
         * Populate all the child nodes here...
@@ -1782,7 +1775,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
        if (ret)
                pr_warn("Doesn't have any child node\n");
 
-       for_each_node_by_name(slave_node, "slave") {
+       for_each_child_of_node(node, slave_node) {
                struct cpsw_slave_data *slave_data = data->slave_data + i;
                const void *mac_addr = NULL;
                u32 phyid;
@@ -1791,6 +1784,10 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                struct device_node *mdio_node;
                struct platform_device *mdio;
 
+               /* This is no slave child node, continue */
+               if (strcmp(slave_node->name, "slave"))
+                       continue;
+
                parp = of_get_property(slave_node, "phy_id", &lenp);
                if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) {
                        pr_err("Missing slave[%d] phy_id property\n", i);
index 67df09e..6a32ef9 100644 (file)
@@ -876,8 +876,7 @@ static void emac_dev_mcast_set(struct net_device *ndev)
                    netdev_mc_count(ndev) > EMAC_DEF_MAX_MULTICAST_ADDRESSES) {
                        mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST);
                        emac_add_mcast(priv, EMAC_ALL_MULTI_SET, NULL);
-               }
-               if (!netdev_mc_empty(ndev)) {
+               } else if (!netdev_mc_empty(ndev)) {
                        struct netdev_hw_addr *ha;
 
                        mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST);
index c8f088a..bdf697b 100644 (file)
@@ -32,7 +32,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #define DRV_NAME       "via-rhine"
-#define DRV_VERSION    "1.5.0"
+#define DRV_VERSION    "1.5.1"
 #define DRV_RELDATE    "2010-10-09"
 
 #include <linux/types.h>
@@ -1704,7 +1704,12 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
        if (unlikely(vlan_tx_tag_present(skb))) {
-               rp->tx_ring[entry].tx_status = cpu_to_le32((vlan_tx_tag_get(skb)) << 16);
+               u16 vid_pcp = vlan_tx_tag_get(skb);
+
+               /* drop CFI/DEI bit, register needs VID and PCP */
+               vid_pcp = (vid_pcp & VLAN_VID_MASK) |
+                         ((vid_pcp & VLAN_PRIO_MASK) >> 1);
+               rp->tx_ring[entry].tx_status = cpu_to_le32((vid_pcp) << 16);
                /* request tagging */
                rp->tx_ring[entry].desc_length |= cpu_to_le32(0x020000);
        }
index b88121f..0029148 100644 (file)
@@ -297,6 +297,12 @@ static int temac_dma_bd_init(struct net_device *ndev)
                       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
        lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
 
+       /* Init descriptor indexes */
+       lp->tx_bd_ci = 0;
+       lp->tx_bd_next = 0;
+       lp->tx_bd_tail = 0;
+       lp->rx_bd_ci = 0;
+
        return 0;
 
 out:
index 0721e72..5af1c3e 100644 (file)
@@ -975,7 +975,6 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        return -EINVAL;         /* Cannot change this parameter when up */
                if ((ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_KERNEL)) == NULL)
                        return -ENOBUFS;
-               ym->bitrate = 9600;
                if (copy_from_user(ym, ifr->ifr_data, sizeof(struct yamdrv_ioctl_mcs))) {
                        kfree(ym);
                        return -EFAULT;
index 42e6dee..0632d34 100644 (file)
@@ -82,7 +82,6 @@ struct mrf24j40 {
 
        struct mutex buffer_mutex; /* only used to protect buf */
        struct completion tx_complete;
-       struct work_struct irqwork;
        u8 *buf; /* 3 bytes. Used for SPI single-register transfers. */
 };
 
@@ -344,6 +343,8 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
        if (ret)
                goto err;
 
+       INIT_COMPLETION(devrec->tx_complete);
+
        /* Set TXNTRIG bit of TXNCON to send packet */
        ret = read_short_reg(devrec, REG_TXNCON, &val);
        if (ret)
@@ -354,8 +355,6 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
                val |= 0x4;
        write_short_reg(devrec, REG_TXNCON, val);
 
-       INIT_COMPLETION(devrec->tx_complete);
-
        /* Wait for the device to send the TX complete interrupt. */
        ret = wait_for_completion_interruptible_timeout(
                                                &devrec->tx_complete,
@@ -590,17 +589,6 @@ static struct ieee802154_ops mrf24j40_ops = {
 static irqreturn_t mrf24j40_isr(int irq, void *data)
 {
        struct mrf24j40 *devrec = data;
-
-       disable_irq_nosync(irq);
-
-       schedule_work(&devrec->irqwork);
-
-       return IRQ_HANDLED;
-}
-
-static void mrf24j40_isrwork(struct work_struct *work)
-{
-       struct mrf24j40 *devrec = container_of(work, struct mrf24j40, irqwork);
        u8 intstat;
        int ret;
 
@@ -618,7 +606,7 @@ static void mrf24j40_isrwork(struct work_struct *work)
                mrf24j40_handle_rx(devrec);
 
 out:
-       enable_irq(devrec->spi->irq);
+       return IRQ_HANDLED;
 }
 
 static int mrf24j40_probe(struct spi_device *spi)
@@ -642,7 +630,6 @@ static int mrf24j40_probe(struct spi_device *spi)
 
        mutex_init(&devrec->buffer_mutex);
        init_completion(&devrec->tx_complete);
-       INIT_WORK(&devrec->irqwork, mrf24j40_isrwork);
        devrec->spi = spi;
        spi_set_drvdata(spi, devrec);
 
@@ -688,11 +675,12 @@ static int mrf24j40_probe(struct spi_device *spi)
        val &= ~0x3; /* Clear RX mode (normal) */
        write_short_reg(devrec, REG_RXMCR, val);
 
-       ret = request_irq(spi->irq,
-                         mrf24j40_isr,
-                         IRQF_TRIGGER_FALLING,
-                         dev_name(&spi->dev),
-                         devrec);
+       ret = request_threaded_irq(spi->irq,
+                                  NULL,
+                                  mrf24j40_isr,
+                                  IRQF_TRIGGER_LOW|IRQF_ONESHOT,
+                                  dev_name(&spi->dev),
+                                  devrec);
 
        if (ret) {
                dev_err(printdev(devrec), "Unable to get IRQ");
@@ -721,7 +709,6 @@ static int mrf24j40_remove(struct spi_device *spi)
        dev_dbg(printdev(devrec), "remove\n");
 
        free_irq(spi->irq, devrec);
-       flush_work(&devrec->irqwork); /* TODO: Is this the right call? */
        ieee802154_unregister_device(devrec->dev);
        ieee802154_free_device(devrec->dev);
        /* TODO: Will ieee802154_free_device() wait until ->xmit() is
index a34d6bf..cc70ecf 100644 (file)
@@ -429,11 +429,13 @@ static void slip_write_wakeup(struct tty_struct *tty)
        if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
                return;
 
+       spin_lock(&sl->lock);
        if (sl->xleft <= 0)  {
                /* Now serial buffer is almost free & we can start
                 * transmission of another packet */
                sl->dev->stats.tx_packets++;
                clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+               spin_unlock(&sl->lock);
                sl_unlock(sl);
                return;
        }
@@ -441,6 +443,7 @@ static void slip_write_wakeup(struct tty_struct *tty)
        actual = tty->ops->write(tty, sl->xhead, sl->xleft);
        sl->xleft -= actual;
        sl->xhead += actual;
+       spin_unlock(&sl->lock);
 }
 
 static void sl_tx_timeout(struct net_device *dev)
index 807815f..7cb105c 100644 (file)
@@ -1293,7 +1293,8 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
        if (unlikely(!noblock))
                add_wait_queue(&tfile->wq.wait, &wait);
        while (len) {
-               current->state = TASK_INTERRUPTIBLE;
+               if (unlikely(!noblock))
+                       current->state = TASK_INTERRUPTIBLE;
 
                /* Read frames from the queue */
                if (!(skb = skb_dequeue(&tfile->socket.sk->sk_receive_queue))) {
@@ -1320,9 +1321,10 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
                break;
        }
 
-       current->state = TASK_RUNNING;
-       if (unlikely(!noblock))
+       if (unlikely(!noblock)) {
+               current->state = TASK_RUNNING;
                remove_wait_queue(&tfile->wq.wait, &wait);
+       }
 
        return ret;
 }
index 3569293..846cc19 100644 (file)
@@ -36,8 +36,8 @@
 #define AX_RXHDR_L4_TYPE_TCP                   16
 #define AX_RXHDR_L3CSUM_ERR                    2
 #define AX_RXHDR_L4CSUM_ERR                    1
-#define AX_RXHDR_CRC_ERR                       ((u32)BIT(31))
-#define AX_RXHDR_DROP_ERR                      ((u32)BIT(30))
+#define AX_RXHDR_CRC_ERR                       ((u32)BIT(29))
+#define AX_RXHDR_DROP_ERR                      ((u32)BIT(31))
 #define AX_ACCESS_MAC                          0x01
 #define AX_ACCESS_PHY                          0x02
 #define AX_ACCESS_EEPROM                       0x04
@@ -1406,6 +1406,19 @@ static const struct driver_info sitecom_info = {
        .tx_fixup = ax88179_tx_fixup,
 };
 
+static const struct driver_info samsung_info = {
+       .description = "Samsung USB Ethernet Adapter",
+       .bind = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset = ax88179_reset,
+       .stop = ax88179_stop,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+};
+
 static const struct usb_device_id products[] = {
 {
        /* ASIX AX88179 10/100/1000 */
@@ -1418,7 +1431,11 @@ static const struct usb_device_id products[] = {
 }, {
        /* Sitecom USB 3.0 to Gigabit Adapter */
        USB_DEVICE(0x0df6, 0x0072),
-       .driver_info = (unsigned long) &sitecom_info,
+       .driver_info = (unsigned long)&sitecom_info,
+}, {
+       /* Samsung USB Ethernet Adapter */
+       USB_DEVICE(0x04e8, 0xa100),
+       .driver_info = (unsigned long)&samsung_info,
 },
        { },
 };
index 2dbb946..c6867f9 100644 (file)
@@ -303,7 +303,7 @@ static void dm9601_set_multicast(struct net_device *net)
                rx_ctl |= 0x02;
        } else if (net->flags & IFF_ALLMULTI ||
                   netdev_mc_count(net) > DM_MAX_MCAST) {
-               rx_ctl |= 0x04;
+               rx_ctl |= 0x08;
        } else if (!netdev_mc_empty(net)) {
                struct netdev_hw_addr *ha;
 
index 6312332..818ce90 100644 (file)
@@ -714,7 +714,8 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x2357, 0x0201, 4)},    /* TP-LINK HSUPA Modem MA180 */
        {QMI_FIXED_INTF(0x2357, 0x9000, 4)},    /* TP-LINK MA260 */
        {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},    /* Telit LE920 */
-       {QMI_FIXED_INTF(0x1e2d, 0x12d1, 4)},    /* Cinterion PLxx */
+       {QMI_FIXED_INTF(0x0b3c, 0xc005, 6)},    /* Olivetti Olicard 200 */
+       {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)},    /* Cinterion PLxx */
 
        /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
index 7b331e6..90a429b 100644 (file)
@@ -1241,7 +1241,9 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
        if (num_sgs == 1)
                return 0;
 
-       urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), GFP_ATOMIC);
+       /* reserve one for zero packet */
+       urb->sg = kmalloc((num_sgs + 1) * sizeof(struct scatterlist),
+                         GFP_ATOMIC);
        if (!urb->sg)
                return -ENOMEM;
 
@@ -1305,7 +1307,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
                if (build_dma_sg(skb, urb) < 0)
                        goto drop;
        }
-       entry->length = length = urb->transfer_buffer_length;
+       length = urb->transfer_buffer_length;
 
        /* don't assume the hardware handles USB_ZERO_PACKET
         * NOTE:  strictly conforming cdc-ether devices should expect
@@ -1317,15 +1319,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
        if (length % dev->maxpacket == 0) {
                if (!(info->flags & FLAG_SEND_ZLP)) {
                        if (!(info->flags & FLAG_MULTI_PACKET)) {
-                               urb->transfer_buffer_length++;
-                               if (skb_tailroom(skb)) {
+                               length++;
+                               if (skb_tailroom(skb) && !urb->num_sgs) {
                                        skb->data[skb->len] = 0;
                                        __skb_put(skb, 1);
-                               }
+                               } else if (urb->num_sgs)
+                                       sg_set_buf(&urb->sg[urb->num_sgs++],
+                                                       dev->padding_pkt, 1);
                        }
                } else
                        urb->transfer_flags |= URB_ZERO_PACKET;
        }
+       entry->length = urb->transfer_buffer_length = length;
 
        spin_lock_irqsave(&dev->txq.lock, flags);
        retval = usb_autopm_get_interface_async(dev->intf);
@@ -1509,6 +1514,7 @@ void usbnet_disconnect (struct usb_interface *intf)
 
        usb_kill_urb(dev->interrupt);
        usb_free_urb(dev->interrupt);
+       kfree(dev->padding_pkt);
 
        free_netdev(net);
 }
@@ -1679,9 +1685,18 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        /* initialize max rx_qlen and tx_qlen */
        usbnet_update_max_qlen(dev);
 
+       if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) &&
+               !(info->flags & FLAG_MULTI_PACKET)) {
+               dev->padding_pkt = kzalloc(1, GFP_KERNEL);
+               if (!dev->padding_pkt) {
+                       status = -ENOMEM;
+                       goto out4;
+               }
+       }
+
        status = register_netdev (net);
        if (status)
-               goto out4;
+               goto out5;
        netif_info(dev, probe, dev->net,
                   "register '%s' at usb-%s-%s, %s, %pM\n",
                   udev->dev.driver->name,
@@ -1699,6 +1714,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 
        return 0;
 
+out5:
+       kfree(dev->padding_pkt);
 out4:
        usb_free_urb(dev->interrupt);
 out3:
index defec2b..9fbdfcd 100644 (file)
@@ -938,7 +938,9 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
                return -EINVAL;
        } else {
                vi->curr_queue_pairs = queue_pairs;
-               schedule_delayed_work(&vi->refill, 0);
+               /* virtnet_open() will refill when device is going to up. */
+               if (dev->flags & IFF_UP)
+                       schedule_delayed_work(&vi->refill, 0);
        }
 
        return 0;
@@ -1116,6 +1118,11 @@ static int virtnet_cpu_callback(struct notifier_block *nfb,
 {
        struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb);
 
+       mutex_lock(&vi->config_lock);
+
+       if (!vi->config_enable)
+               goto done;
+
        switch(action & ~CPU_TASKS_FROZEN) {
        case CPU_ONLINE:
        case CPU_DOWN_FAILED:
@@ -1128,6 +1135,9 @@ static int virtnet_cpu_callback(struct notifier_block *nfb,
        default:
                break;
        }
+
+done:
+       mutex_unlock(&vi->config_lock);
        return NOTIFY_OK;
 }
 
@@ -1733,7 +1743,9 @@ static int virtnet_restore(struct virtio_device *vdev)
        vi->config_enable = true;
        mutex_unlock(&vi->config_lock);
 
+       rtnl_lock();
        virtnet_set_queues(vi, vi->curr_queue_pairs);
+       rtnl_unlock();
 
        return 0;
 }
index d1292fe..2ef5b62 100644 (file)
@@ -952,8 +952,7 @@ void vxlan_sock_release(struct vxlan_sock *vs)
 
        spin_lock(&vn->sock_lock);
        hlist_del_rcu(&vs->hlist);
-       smp_wmb();
-       vs->sock->sk->sk_user_data = NULL;
+       rcu_assign_sk_user_data(vs->sock->sk, NULL);
        vxlan_notify_del_rx_port(sk);
        spin_unlock(&vn->sock_lock);
 
@@ -1048,8 +1047,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 
        port = inet_sk(sk)->inet_sport;
 
-       smp_read_barrier_depends();
-       vs = (struct vxlan_sock *)sk->sk_user_data;
+       vs = rcu_dereference_sk_user_data(sk);
        if (!vs)
                goto drop;
 
@@ -2302,8 +2300,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
        atomic_set(&vs->refcnt, 1);
        vs->rcv = rcv;
        vs->data = data;
-       smp_wmb();
-       vs->sock->sk->sk_user_data = vs;
+       rcu_assign_sk_user_data(vs->sock->sk, vs);
 
        spin_lock(&vn->sock_lock);
        hlist_add_head_rcu(&vs->hlist, vs_head(net, port));
index 3f0c4f2..bcfff0d 100644 (file)
@@ -1972,6 +1972,7 @@ fst_get_iface(struct fst_card_info *card, struct fst_port_info *port,
        }
 
        i = port->index;
+       memset(&sync, 0, sizeof(sync));
        sync.clock_rate = FST_RDL(card, portConfig[i].lineSpeed);
        /* Lucky card and linux use same encoding here */
        sync.clock_type = FST_RDB(card, portConfig[i].internalClock) ==
index 6a24a5a..4c0a697 100644 (file)
@@ -355,6 +355,7 @@ static int wanxl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        ifr->ifr_settings.size = size; /* data size wanted */
                        return -ENOBUFS;
                }
+               memset(&line, 0, sizeof(line));
                line.clock_type = get_status(port)->clocking;
                line.clock_rate = 0;
                line.loopback = 0;
index e4f6590..709301f 100644 (file)
@@ -208,6 +208,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        unsigned long flags;
+       int i;
 
        if (ath_startrecv(sc) != 0) {
                ath_err(common, "Unable to restart recv logic\n");
@@ -235,6 +236,15 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
                }
        work:
                ath_restart_work(sc);
+
+               for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+                       if (!ATH_TXQ_SETUP(sc, i))
+                               continue;
+
+                       spin_lock_bh(&sc->tx.txq[i].axq_lock);
+                       ath_txq_schedule(sc, &sc->tx.txq[i]);
+                       spin_unlock_bh(&sc->tx.txq[i].axq_lock);
+               }
        }
 
        ieee80211_wake_queues(sc->hw);
@@ -539,21 +549,10 @@ chip_reset:
 
 static int ath_reset(struct ath_softc *sc)
 {
-       int i, r;
+       int r;
 
        ath9k_ps_wakeup(sc);
-
        r = ath_reset_internal(sc, NULL);
-
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-               if (!ATH_TXQ_SETUP(sc, i))
-                       continue;
-
-               spin_lock_bh(&sc->tx.txq[i].axq_lock);
-               ath_txq_schedule(sc, &sc->tx.txq[i]);
-               spin_unlock_bh(&sc->tx.txq[i].axq_lock);
-       }
-
        ath9k_ps_restore(sc);
 
        return r;
index 4ee472a..ab9e3a8 100644 (file)
@@ -1269,13 +1269,6 @@ static void ath9k_antenna_check(struct ath_softc *sc,
        if (!(ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB))
                return;
 
-       /*
-        * All MPDUs in an aggregate will use the same LNA
-        * as the first MPDU.
-        */
-       if (rs->rs_isaggr && !rs->rs_firstaggr)
-               return;
-
        /*
         * Change the default rx antenna if rx diversity
         * chooses the other antenna 3 times in a row.
index 35b515f..dd30452 100644 (file)
@@ -399,6 +399,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
        tbf->bf_buf_addr = bf->bf_buf_addr;
        memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
        tbf->bf_state = bf->bf_state;
+       tbf->bf_state.stale = false;
 
        return tbf;
 }
@@ -1389,11 +1390,15 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
                      u16 tid, u16 *ssn)
 {
        struct ath_atx_tid *txtid;
+       struct ath_txq *txq;
        struct ath_node *an;
        u8 density;
 
        an = (struct ath_node *)sta->drv_priv;
        txtid = ATH_AN_2_TID(an, tid);
+       txq = txtid->ac->txq;
+
+       ath_txq_lock(sc, txq);
 
        /* update ampdu factor/density, they may have changed. This may happen
         * in HT IBSS when a beacon with HT-info is received after the station
@@ -1417,6 +1422,8 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
        memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf));
        txtid->baw_head = txtid->baw_tail = 0;
 
+       ath_txq_unlock_complete(sc, txq);
+
        return 0;
 }
 
@@ -1555,8 +1562,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
                        __skb_unlink(bf->bf_mpdu, tid_q);
                        list_add_tail(&bf->list, &bf_q);
                        ath_set_rates(tid->an->vif, tid->an->sta, bf);
-                       ath_tx_addto_baw(sc, tid, bf);
-                       bf->bf_state.bf_type &= ~BUF_AGGR;
+                       if (bf_isampdu(bf)) {
+                               ath_tx_addto_baw(sc, tid, bf);
+                               bf->bf_state.bf_type &= ~BUF_AGGR;
+                       }
                        if (bf_tail)
                                bf_tail->bf_next = bf;
 
@@ -1950,7 +1959,9 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
                        if (bf_is_ampdu_not_probing(bf))
                                txq->axq_ampdu_depth++;
 
-                       bf = bf->bf_lastbf->bf_next;
+                       bf_last = bf->bf_lastbf;
+                       bf = bf_last->bf_next;
+                       bf_last->bf_next = NULL;
                }
        }
 }
@@ -1958,15 +1969,18 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
                               struct ath_atx_tid *tid, struct sk_buff *skb)
 {
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ath_frame_info *fi = get_frame_info(skb);
        struct list_head bf_head;
-       struct ath_buf *bf;
-
-       bf = fi->bf;
+       struct ath_buf *bf = fi->bf;
 
        INIT_LIST_HEAD(&bf_head);
        list_add_tail(&bf->list, &bf_head);
        bf->bf_state.bf_type = 0;
+       if (tid && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
+               bf->bf_state.bf_type = BUF_AMPDU;
+               ath_tx_addto_baw(sc, tid, bf);
+       }
 
        bf->bf_next = NULL;
        bf->bf_lastbf = bf;
index 64f4a2b..c3462b7 100644 (file)
@@ -464,8 +464,6 @@ static struct sdio_driver brcmf_sdmmc_driver = {
 
 static int brcmf_sdio_pd_probe(struct platform_device *pdev)
 {
-       int ret;
-
        brcmf_dbg(SDIO, "Enter\n");
 
        brcmfmac_sdio_pdata = pdev->dev.platform_data;
@@ -473,11 +471,7 @@ static int brcmf_sdio_pd_probe(struct platform_device *pdev)
        if (brcmfmac_sdio_pdata->power_on)
                brcmfmac_sdio_pdata->power_on();
 
-       ret = sdio_register_driver(&brcmf_sdmmc_driver);
-       if (ret)
-               brcmf_err("sdio_register_driver failed: %d\n", ret);
-
-       return ret;
+       return 0;
 }
 
 static int brcmf_sdio_pd_remove(struct platform_device *pdev)
@@ -500,6 +494,15 @@ static struct platform_driver brcmf_sdio_pd = {
        }
 };
 
+void brcmf_sdio_register(void)
+{
+       int ret;
+
+       ret = sdio_register_driver(&brcmf_sdmmc_driver);
+       if (ret)
+               brcmf_err("sdio_register_driver failed: %d\n", ret);
+}
+
 void brcmf_sdio_exit(void)
 {
        brcmf_dbg(SDIO, "Enter\n");
@@ -510,18 +513,13 @@ void brcmf_sdio_exit(void)
                sdio_unregister_driver(&brcmf_sdmmc_driver);
 }
 
-void brcmf_sdio_init(void)
+void __init brcmf_sdio_init(void)
 {
        int ret;
 
        brcmf_dbg(SDIO, "Enter\n");
 
        ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
-       if (ret == -ENODEV) {
-               brcmf_dbg(SDIO, "No platform data available, registering without.\n");
-               ret = sdio_register_driver(&brcmf_sdmmc_driver);
-       }
-
-       if (ret)
-               brcmf_err("driver registration failed: %d\n", ret);
+       if (ret == -ENODEV)
+               brcmf_dbg(SDIO, "No platform data available.\n");
 }
index f7c1985..74156f8 100644 (file)
@@ -156,10 +156,11 @@ extern int brcmf_bus_start(struct device *dev);
 #ifdef CONFIG_BRCMFMAC_SDIO
 extern void brcmf_sdio_exit(void);
 extern void brcmf_sdio_init(void);
+extern void brcmf_sdio_register(void);
 #endif
 #ifdef CONFIG_BRCMFMAC_USB
 extern void brcmf_usb_exit(void);
-extern void brcmf_usb_init(void);
+extern void brcmf_usb_register(void);
 #endif
 
 #endif                         /* _BRCMF_BUS_H_ */
index e067aec..40e7f85 100644 (file)
@@ -1231,21 +1231,23 @@ u32 brcmf_get_chip_info(struct brcmf_if *ifp)
        return bus->chip << 4 | bus->chiprev;
 }
 
-static void brcmf_driver_init(struct work_struct *work)
+static void brcmf_driver_register(struct work_struct *work)
 {
-       brcmf_debugfs_init();
-
 #ifdef CONFIG_BRCMFMAC_SDIO
-       brcmf_sdio_init();
+       brcmf_sdio_register();
 #endif
 #ifdef CONFIG_BRCMFMAC_USB
-       brcmf_usb_init();
+       brcmf_usb_register();
 #endif
 }
-static DECLARE_WORK(brcmf_driver_work, brcmf_driver_init);
+static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
 
 static int __init brcmfmac_module_init(void)
 {
+       brcmf_debugfs_init();
+#ifdef CONFIG_BRCMFMAC_SDIO
+       brcmf_sdio_init();
+#endif
        if (!schedule_work(&brcmf_driver_work))
                return -EBUSY;
 
index 39e01a7..f4aea47 100644 (file)
@@ -1539,7 +1539,7 @@ void brcmf_usb_exit(void)
        brcmf_release_fw(&fw_image_list);
 }
 
-void brcmf_usb_init(void)
+void brcmf_usb_register(void)
 {
        brcmf_dbg(USB, "Enter\n");
        INIT_LIST_HEAD(&fw_image_list);
index 3a65447..edc5d10 100644 (file)
@@ -457,6 +457,8 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
        if (err != 0)
                brcms_err(wl->wlc->hw->d11core, "%s: brcms_up() returned %d\n",
                          __func__, err);
+
+       bcma_core_pci_power_save(wl->wlc->hw->d11core->bus, true);
        return err;
 }
 
@@ -479,6 +481,8 @@ static void brcms_ops_stop(struct ieee80211_hw *hw)
                return;
        }
 
+       bcma_core_pci_power_save(wl->wlc->hw->d11core->bus, false);
+
        /* put driver in down state */
        spin_lock_bh(&wl->lock);
        brcms_down(wl);
index f5e6b48..755a0c8 100644 (file)
@@ -42,7 +42,6 @@ struct hwbus_priv {
        spinlock_t              lock; /* Serialize all bus operations */
        wait_queue_head_t       wq;
        int claimed;
-       int irq_disabled;
 };
 
 #define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2)
@@ -238,9 +237,9 @@ static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id)
        struct hwbus_priv *self = dev_id;
 
        if (self->core) {
-               disable_irq_nosync(self->func->irq);
-               self->irq_disabled = 1;
+               cw1200_spi_lock(self);
                cw1200_irq_handler(self->core);
+               cw1200_spi_unlock(self);
                return IRQ_HANDLED;
        } else {
                return IRQ_NONE;
@@ -253,9 +252,10 @@ static int cw1200_spi_irq_subscribe(struct hwbus_priv *self)
 
        pr_debug("SW IRQ subscribe\n");
 
-       ret = request_any_context_irq(self->func->irq, cw1200_spi_irq_handler,
-                                     IRQF_TRIGGER_HIGH,
-                                     "cw1200_wlan_irq", self);
+       ret = request_threaded_irq(self->func->irq, NULL,
+                                  cw1200_spi_irq_handler,
+                                  IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                  "cw1200_wlan_irq", self);
        if (WARN_ON(ret < 0))
                goto exit;
 
@@ -273,22 +273,13 @@ exit:
 
 static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self)
 {
+       int ret = 0;
+
        pr_debug("SW IRQ unsubscribe\n");
        disable_irq_wake(self->func->irq);
        free_irq(self->func->irq, self);
 
-       return 0;
-}
-
-static int cw1200_spi_irq_enable(struct hwbus_priv *self, int enable)
-{
-       /* Disables are handled by the interrupt handler */
-       if (enable && self->irq_disabled) {
-               enable_irq(self->func->irq);
-               self->irq_disabled = 0;
-       }
-
-       return 0;
+       return ret;
 }
 
 static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
@@ -368,7 +359,6 @@ static struct hwbus_ops cw1200_spi_hwbus_ops = {
        .unlock                 = cw1200_spi_unlock,
        .align_size             = cw1200_spi_align_size,
        .power_mgmt             = cw1200_spi_pm,
-       .irq_enable             = cw1200_spi_irq_enable,
 };
 
 /* Probe Function to be called by SPI stack when device is discovered */
index 0b2061b..acdff0f 100644 (file)
@@ -485,7 +485,7 @@ int cw1200_load_firmware(struct cw1200_common *priv)
 
        /* Enable interrupt signalling */
        priv->hwbus_ops->lock(priv->hwbus_priv);
-       ret = __cw1200_irq_enable(priv, 2);
+       ret = __cw1200_irq_enable(priv, 1);
        priv->hwbus_ops->unlock(priv->hwbus_priv);
        if (ret < 0)
                goto unsubscribe;
index 51dfb3a..8b2fc83 100644 (file)
@@ -28,7 +28,6 @@ struct hwbus_ops {
        void (*unlock)(struct hwbus_priv *self);
        size_t (*align_size)(struct hwbus_priv *self, size_t size);
        int (*power_mgmt)(struct hwbus_priv *self, bool suspend);
-       int (*irq_enable)(struct hwbus_priv *self, int enable);
 };
 
 #endif /* CW1200_HWBUS_H */
index 41bd761..ff230b7 100644 (file)
@@ -273,21 +273,6 @@ int __cw1200_irq_enable(struct cw1200_common *priv, int enable)
        u16 val16;
        int ret;
 
-       /* We need to do this hack because the SPI layer can sleep on I/O
-          and the general path involves I/O to the device in interrupt
-          context.
-
-          However, the initial enable call needs to go to the hardware.
-
-          We don't worry about shutdown because we do a full reset which
-          clears the interrupt enabled bits.
-       */
-       if (priv->hwbus_ops->irq_enable) {
-               ret = priv->hwbus_ops->irq_enable(priv->hwbus_priv, enable);
-               if (ret || enable < 2)
-                       return ret;
-       }
-
        if (HIF_8601_SILICON == priv->hw_type) {
                ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32);
                if (ret < 0) {
index 30d45e2..8ac305b 100644 (file)
@@ -240,6 +240,12 @@ const struct iwl_cfg iwl6035_2agn_cfg = {
        .ht_params = &iwl6000_ht_params,
 };
 
+const struct iwl_cfg iwl6035_2agn_sff_cfg = {
+       .name = "Intel(R) Centrino(R) Ultimate-N 6235 AGN",
+       IWL_DEVICE_6035,
+       .ht_params = &iwl6000_ht_params,
+};
+
 const struct iwl_cfg iwl1030_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
        IWL_DEVICE_6030,
index e4d370b..b03c25e 100644 (file)
@@ -280,6 +280,7 @@ extern const struct iwl_cfg iwl2000_2bgn_cfg;
 extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
 extern const struct iwl_cfg iwl2030_2bgn_cfg;
 extern const struct iwl_cfg iwl6035_2agn_cfg;
+extern const struct iwl_cfg iwl6035_2agn_sff_cfg;
 extern const struct iwl_cfg iwl105_bgn_cfg;
 extern const struct iwl_cfg iwl105_bgn_d_cfg;
 extern const struct iwl_cfg iwl135_bgn_cfg;
index dd57a36..80b4750 100644 (file)
@@ -601,8 +601,10 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
 {
        int ret;
 
-       WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
-                 "%s bad state = %d", __func__, trans->state);
+       if (trans->state != IWL_TRANS_FW_ALIVE) {
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+               return -EIO;
+       }
 
        if (!(cmd->flags & CMD_ASYNC))
                lock_map_acquire_read(&trans->sync_cmd_lockdep_map);
index 21407a3..d58e393 100644 (file)
@@ -273,7 +273,10 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
                if (!mvmvif->queue_params[ac].uapsd)
                        continue;
 
-               cmd->flags |= cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
+               if (mvm->cur_ucode != IWL_UCODE_WOWLAN)
+                       cmd->flags |=
+                               cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
+
                cmd->uapsd_ac_flags |= BIT(ac);
 
                /* QNDP TID - the highest TID with no admission control */
index 9a7ab84..621fb71 100644 (file)
@@ -394,6 +394,11 @@ static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
                        return false;
                }
 
+               /*
+                * If scan cannot be aborted, it means that we had a
+                * SCAN_COMPLETE_NOTIFICATION in the pipe and it called
+                * ieee80211_scan_completed already.
+                */
                IWL_DEBUG_SCAN(mvm, "Scan cannot be aborted, exit now: %d\n",
                               *resp);
                return true;
@@ -417,14 +422,19 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
                                               SCAN_COMPLETE_NOTIFICATION };
        int ret;
 
+       if (mvm->scan_status == IWL_MVM_SCAN_NONE)
+               return;
+
        iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
                                   scan_abort_notif,
                                   ARRAY_SIZE(scan_abort_notif),
                                   iwl_mvm_scan_abort_notif, NULL);
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL);
+       ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD,
+                                  CMD_SYNC | CMD_SEND_IN_RFKILL, 0, NULL);
        if (ret) {
                IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret);
+               /* mac80211's state will be cleaned in the fw_restart flow */
                goto out_remove_notif;
        }
 
index dc02cb9..26108a1 100644 (file)
@@ -139,13 +139,16 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
 
 /* 6x00 Series */
        {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)},
+       {IWL_PCI_DEVICE(0x422B, 0x1108, iwl6000_3agn_cfg)},
        {IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)},
+       {IWL_PCI_DEVICE(0x422B, 0x1128, iwl6000_3agn_cfg)},
        {IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)},
        {IWL_PCI_DEVICE(0x422C, 0x1306, iwl6000i_2abg_cfg)},
        {IWL_PCI_DEVICE(0x422C, 0x1307, iwl6000i_2bg_cfg)},
        {IWL_PCI_DEVICE(0x422C, 0x1321, iwl6000i_2agn_cfg)},
        {IWL_PCI_DEVICE(0x422C, 0x1326, iwl6000i_2abg_cfg)},
        {IWL_PCI_DEVICE(0x4238, 0x1111, iwl6000_3agn_cfg)},
+       {IWL_PCI_DEVICE(0x4238, 0x1118, iwl6000_3agn_cfg)},
        {IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
        {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
 
@@ -153,12 +156,16 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6005_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6005_2abg_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6005_2bg_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1308, iwl6005_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6005_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6005_2abg_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1328, iwl6005_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0085, 0x1318, iwl6005_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
+       {IWL_PCI_DEVICE(0x0085, 0xC228, iwl6005_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0x4820, iwl6005_2agn_d_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_mow1_cfg)},/* low 5GHz active */
        {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_mow2_cfg)},/* high 5GHz active */
@@ -240,8 +247,11 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
 
 /* 6x35 Series */
        {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x088E, 0x406A, iwl6035_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x088F, 0x426A, iwl6035_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x088E, 0x446A, iwl6035_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)},
        {IWL_PCI_DEVICE(0x088F, 0x5260, iwl6035_2agn_cfg)},
 
@@ -260,54 +270,86 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
 #if IS_ENABLED(CONFIG_IWLMVM)
 /* 7000 Series */
        {IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0x4072, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4170, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4060, iwl7260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0x406A, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4160, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4062, iwl7260_n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4162, iwl7260_n_cfg)},
        {IWL_PCI_DEVICE(0x08B2, 0x4270, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B2, 0x4272, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B2, 0x4260, iwl7260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x08B2, 0x426A, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B2, 0x4262, iwl7260_n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4470, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0x4472, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4460, iwl7260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0x446A, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4462, iwl7260_n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4870, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x486E, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4A70, iwl7260_2ac_cfg_high_temp)},
        {IWL_PCI_DEVICE(0x08B1, 0x4A6E, iwl7260_2ac_cfg_high_temp)},
        {IWL_PCI_DEVICE(0x08B1, 0x4A6C, iwl7260_2ac_cfg_high_temp)},
+       {IWL_PCI_DEVICE(0x08B1, 0x4570, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0x4560, iwl7260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x08B2, 0x4370, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B2, 0x4360, iwl7260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0x5070, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4020, iwl7260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0x402A, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B2, 0x4220, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0x4420, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC070, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0xC072, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC170, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC060, iwl7260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0xC06A, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC160, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC062, iwl7260_n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC162, iwl7260_n_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0xC770, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0xC760, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B2, 0xC270, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B2, 0xC272, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B2, 0xC260, iwl7260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x08B2, 0xC26A, iwl7260_n_cfg)},
        {IWL_PCI_DEVICE(0x08B2, 0xC262, iwl7260_n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC470, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0xC472, iwl7260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC460, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC462, iwl7260_n_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0xC570, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0xC560, iwl7260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x08B2, 0xC370, iwl7260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0xC360, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC020, iwl7260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x08B1, 0xC02A, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B2, 0xC220, iwl7260_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B1, 0xC420, iwl7260_2n_cfg)},
 
 /* 3160 Series */
        {IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B3, 0x0072, iwl3160_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B3, 0x0170, iwl3160_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B3, 0x0172, iwl3160_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B3, 0x0060, iwl3160_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B3, 0x0062, iwl3160_n_cfg)},
        {IWL_PCI_DEVICE(0x08B4, 0x0270, iwl3160_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B4, 0x0272, iwl3160_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B3, 0x0470, iwl3160_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B3, 0x0472, iwl3160_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B4, 0x0370, iwl3160_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B3, 0x8072, iwl3160_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B3, 0x8170, iwl3160_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B3, 0x8172, iwl3160_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B3, 0x8060, iwl3160_2n_cfg)},
        {IWL_PCI_DEVICE(0x08B3, 0x8062, iwl3160_n_cfg)},
        {IWL_PCI_DEVICE(0x08B4, 0x8270, iwl3160_2ac_cfg)},
        {IWL_PCI_DEVICE(0x08B3, 0x8470, iwl3160_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x08B3, 0x8570, iwl3160_2ac_cfg)},
 #endif /* CONFIG_IWLMVM */
 
        {0}
index bad95d2..c3f904d 100644 (file)
@@ -1401,6 +1401,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        spin_lock_init(&trans_pcie->reg_lock);
        init_waitqueue_head(&trans_pcie->ucode_write_waitq);
 
+       err = pci_enable_device(pdev);
+       if (err)
+               goto out_no_pci;
+
        if (!cfg->base_params->pcie_l1_allowed) {
                /*
                 * W/A - seems to solve weird behavior. We need to remove this
@@ -1412,10 +1416,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
                                       PCIE_LINK_STATE_CLKPM);
        }
 
-       err = pci_enable_device(pdev);
-       if (err)
-               goto out_no_pci;
-
        pci_set_master(pdev);
 
        err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
index f45eb29..1424335 100644 (file)
@@ -1102,6 +1102,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
                 * non-AGG queue.
                 */
                iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+
+               ssn = trans_pcie->txq[txq_id].q.read_ptr;
        }
 
        /* Place first TFD at index corresponding to start sequence number.
index 21c6882..1214c58 100644 (file)
@@ -150,7 +150,7 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
  */
 int
 mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
-                         struct mwifiex_ra_list_tbl *pra_list, int headroom,
+                         struct mwifiex_ra_list_tbl *pra_list,
                          int ptrindex, unsigned long ra_list_flags)
                          __releases(&priv->wmm.ra_list_spinlock)
 {
@@ -160,6 +160,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
        int pad = 0, ret;
        struct mwifiex_tx_param tx_param;
        struct txpd *ptx_pd = NULL;
+       int headroom = adapter->iface_type == MWIFIEX_USB ? 0 : INTF_HEADER_LEN;
 
        skb_src = skb_peek(&pra_list->skb_head);
        if (!skb_src) {
index 900e1c6..892098d 100644 (file)
@@ -26,7 +26,7 @@
 int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
                                struct sk_buff *skb);
 int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
-                             struct mwifiex_ra_list_tbl *ptr, int headroom,
+                             struct mwifiex_ra_list_tbl *ptr,
                              int ptr_index, unsigned long flags)
                              __releases(&priv->wmm.ra_list_spinlock);
 
index 2d76147..a6c46f3 100644 (file)
@@ -1155,7 +1155,7 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
        uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions);
 
        if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE) &&
-           adapter->iface_type == MWIFIEX_SDIO) {
+           adapter->iface_type != MWIFIEX_USB) {
                mwifiex_hs_activated_event(priv, true);
                return 0;
        } else {
@@ -1167,8 +1167,7 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
        }
        if (conditions != HS_CFG_CANCEL) {
                adapter->is_hs_configured = true;
-               if (adapter->iface_type == MWIFIEX_USB ||
-                   adapter->iface_type == MWIFIEX_PCIE)
+               if (adapter->iface_type == MWIFIEX_USB)
                        mwifiex_hs_activated_event(priv, true);
        } else {
                adapter->is_hs_configured = false;
index 9d7c0e6..37f873b 100644 (file)
@@ -1422,13 +1422,19 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
  */
 int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
 {
+       int ret = 0;
+
        if (!priv->media_connected)
                return 0;
 
        switch (priv->bss_mode) {
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
-               return mwifiex_deauthenticate_infra(priv, mac);
+               ret = mwifiex_deauthenticate_infra(priv, mac);
+               if (ret)
+                       cfg80211_disconnected(priv->netdev, 0, NULL, 0,
+                                             GFP_KERNEL);
+               break;
        case NL80211_IFTYPE_ADHOC:
                return mwifiex_send_cmd_sync(priv,
                                             HostCmd_CMD_802_11_AD_HOC_STOP,
@@ -1440,7 +1446,7 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
                break;
        }
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(mwifiex_deauthenticate);
 
index fd77833..c2b91f5 100644 (file)
@@ -358,10 +358,12 @@ process_start:
                }
        } while (true);
 
-       if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter))
+       spin_lock_irqsave(&adapter->main_proc_lock, flags);
+       if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) {
+               spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
                goto process_start;
+       }
 
-       spin_lock_irqsave(&adapter->main_proc_lock, flags);
        adapter->mwifiex_processing = false;
        spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
 
index 8b05752..8c351f7 100644 (file)
@@ -118,7 +118,8 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
        dev_dbg(adapter->dev,
                "info: successfully disconnected from %pM: reason code %d\n",
                priv->cfg_bssid, reason_code);
-       if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+       if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+           priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
                cfg80211_disconnected(priv->netdev, reason_code, NULL, 0,
                                      GFP_KERNEL);
        }
index 2472d4b..1c70b8d 100644 (file)
@@ -447,9 +447,6 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
         */
        adapter->is_suspended = true;
 
-       for (i = 0; i < adapter->priv_num; i++)
-               netif_carrier_off(adapter->priv[i]->netdev);
-
        if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb)
                usb_kill_urb(card->rx_cmd.urb);
 
@@ -509,10 +506,6 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
                                                  MWIFIEX_RX_CMD_BUF_SIZE);
        }
 
-       for (i = 0; i < adapter->priv_num; i++)
-               if (adapter->priv[i]->media_connected)
-                       netif_carrier_on(adapter->priv[i]->netdev);
-
        /* Disable Host Sleep */
        if (adapter->hs_activated)
                mwifiex_cancel_hs(mwifiex_get_priv(adapter,
index 2e8f9cd..95fa359 100644 (file)
@@ -1239,8 +1239,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
                if (enable_tx_amsdu && mwifiex_is_amsdu_allowed(priv, tid) &&
                    mwifiex_is_11n_aggragation_possible(priv, ptr,
                                                        adapter->tx_buf_size))
-                       mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
-                                                 ptr_index, flags);
+                       mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags);
                        /* ra_list_spinlock has been freed in
                           mwifiex_11n_aggregate_pkt() */
                else
index b9deef6..e328d30 100644 (file)
@@ -83,6 +83,7 @@ static struct usb_device_id p54u_table[] = {
        {USB_DEVICE(0x06a9, 0x000e)},   /* Westell 802.11g USB (A90-211WG-01) */
        {USB_DEVICE(0x06b9, 0x0121)},   /* Thomson SpeedTouch 121g */
        {USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
+       {USB_DEVICE(0x07aa, 0x0020)},   /* Corega WLUSB2GTST USB */
        {USB_DEVICE(0x0803, 0x4310)},   /* Zoom 4410a */
        {USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
        {USB_DEVICE(0x083a, 0x4531)},   /* T-Com Sinus 154 data II */
@@ -979,6 +980,7 @@ static int p54u_load_firmware(struct ieee80211_hw *dev,
        if (err) {
                dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
                                          "(%d)!\n", p54u_fwlist[i].fw, err);
+               usb_put_dev(udev);
        }
 
        return err;
index 76d95de..dc49e52 100644 (file)
@@ -105,13 +105,11 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
                goto exit_release_regions;
        }
 
-       pci_enable_msi(pci_dev);
-
        hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
        if (!hw) {
                rt2x00_probe_err("Failed to allocate hardware\n");
                retval = -ENOMEM;
-               goto exit_disable_msi;
+               goto exit_release_regions;
        }
 
        pci_set_drvdata(pci_dev, hw);
@@ -152,9 +150,6 @@ exit_free_reg:
 exit_free_device:
        ieee80211_free_hw(hw);
 
-exit_disable_msi:
-       pci_disable_msi(pci_dev);
-
 exit_release_regions:
        pci_release_regions(pci_dev);
 
@@ -179,8 +174,6 @@ void rt2x00pci_remove(struct pci_dev *pci_dev)
        rt2x00pci_free_reg(rt2x00dev);
        ieee80211_free_hw(hw);
 
-       pci_disable_msi(pci_dev);
-
        /*
         * Free the PCI device data.
         */
index 763cf1d..5a060e5 100644 (file)
@@ -343,7 +343,8 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
                                        (bool)GET_RX_DESC_PAGGR(pdesc));
        rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
        if (phystatus) {
-               p_drvinfo = (struct rx_fwinfo_92c *)(pdesc + RTL_RX_DESC_SIZE);
+               p_drvinfo = (struct rx_fwinfo_92c *)(skb->data +
+                                                    stats->rx_bufshift);
                rtl92c_translate_rx_signal_stuff(hw, skb, stats, pdesc,
                                                 p_drvinfo);
        }
index cc03e7c..7032587 100644 (file)
@@ -2057,7 +2057,7 @@ struct rtl_priv {
           that it points to the data allocated
           beyond  this structure like:
           rtl_pci_priv or rtl_usb_priv */
-       u8 priv[0];
+       u8 priv[0] __aligned(sizeof(void *));
 };
 
 #define rtl_priv(hw)           (((struct rtl_priv *)(hw)->priv))
index a53782e..1b08d87 100644 (file)
 struct backend_info {
        struct xenbus_device *dev;
        struct xenvif *vif;
+
+       /* This is the state that will be reflected in xenstore when any
+        * active hotplug script completes.
+        */
+       enum xenbus_state state;
+
        enum xenbus_state frontend_state;
        struct xenbus_watch hotplug_status_watch;
        u8 have_hotplug_status_watch:1;
@@ -33,11 +39,15 @@ static int connect_rings(struct backend_info *);
 static void connect(struct backend_info *);
 static void backend_create_xenvif(struct backend_info *be);
 static void unregister_hotplug_status_watch(struct backend_info *be);
+static void set_backend_state(struct backend_info *be,
+                             enum xenbus_state state);
 
 static int netback_remove(struct xenbus_device *dev)
 {
        struct backend_info *be = dev_get_drvdata(&dev->dev);
 
+       set_backend_state(be, XenbusStateClosed);
+
        unregister_hotplug_status_watch(be);
        if (be->vif) {
                kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
@@ -136,6 +146,8 @@ static int netback_probe(struct xenbus_device *dev,
        if (err)
                goto fail;
 
+       be->state = XenbusStateInitWait;
+
        /* This kicks hotplug scripts, so do it immediately. */
        backend_create_xenvif(be);
 
@@ -208,24 +220,113 @@ static void backend_create_xenvif(struct backend_info *be)
        kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
 }
 
-
-static void disconnect_backend(struct xenbus_device *dev)
+static void backend_disconnect(struct backend_info *be)
 {
-       struct backend_info *be = dev_get_drvdata(&dev->dev);
-
        if (be->vif)
                xenvif_disconnect(be->vif);
 }
 
-static void destroy_backend(struct xenbus_device *dev)
+static void backend_connect(struct backend_info *be)
 {
-       struct backend_info *be = dev_get_drvdata(&dev->dev);
+       if (be->vif)
+               connect(be);
+}
 
-       if (be->vif) {
-               kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-               xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
-               xenvif_free(be->vif);
-               be->vif = NULL;
+static inline void backend_switch_state(struct backend_info *be,
+                                       enum xenbus_state state)
+{
+       struct xenbus_device *dev = be->dev;
+
+       pr_debug("%s -> %s\n", dev->nodename, xenbus_strstate(state));
+       be->state = state;
+
+       /* If we are waiting for a hotplug script then defer the
+        * actual xenbus state change.
+        */
+       if (!be->have_hotplug_status_watch)
+               xenbus_switch_state(dev, state);
+}
+
+/* Handle backend state transitions:
+ *
+ * The backend state starts in InitWait and the following transitions are
+ * allowed.
+ *
+ * InitWait -> Connected
+ *
+ *    ^    \         |
+ *    |     \        |
+ *    |      \       |
+ *    |       \      |
+ *    |        \     |
+ *    |         \    |
+ *    |          V   V
+ *
+ *  Closed  <-> Closing
+ *
+ * The state argument specifies the eventual state of the backend and the
+ * function transitions to that state via the shortest path.
+ */
+static void set_backend_state(struct backend_info *be,
+                             enum xenbus_state state)
+{
+       while (be->state != state) {
+               switch (be->state) {
+               case XenbusStateClosed:
+                       switch (state) {
+                       case XenbusStateInitWait:
+                       case XenbusStateConnected:
+                               pr_info("%s: prepare for reconnect\n",
+                                       be->dev->nodename);
+                               backend_switch_state(be, XenbusStateInitWait);
+                               break;
+                       case XenbusStateClosing:
+                               backend_switch_state(be, XenbusStateClosing);
+                               break;
+                       default:
+                               BUG();
+                       }
+                       break;
+               case XenbusStateInitWait:
+                       switch (state) {
+                       case XenbusStateConnected:
+                               backend_connect(be);
+                               backend_switch_state(be, XenbusStateConnected);
+                               break;
+                       case XenbusStateClosing:
+                       case XenbusStateClosed:
+                               backend_switch_state(be, XenbusStateClosing);
+                               break;
+                       default:
+                               BUG();
+                       }
+                       break;
+               case XenbusStateConnected:
+                       switch (state) {
+                       case XenbusStateInitWait:
+                       case XenbusStateClosing:
+                       case XenbusStateClosed:
+                               backend_disconnect(be);
+                               backend_switch_state(be, XenbusStateClosing);
+                               break;
+                       default:
+                               BUG();
+                       }
+                       break;
+               case XenbusStateClosing:
+                       switch (state) {
+                       case XenbusStateInitWait:
+                       case XenbusStateConnected:
+                       case XenbusStateClosed:
+                               backend_switch_state(be, XenbusStateClosed);
+                               break;
+                       default:
+                               BUG();
+                       }
+                       break;
+               default:
+                       BUG();
+               }
        }
 }
 
@@ -237,40 +338,33 @@ static void frontend_changed(struct xenbus_device *dev,
 {
        struct backend_info *be = dev_get_drvdata(&dev->dev);
 
-       pr_debug("frontend state %s\n", xenbus_strstate(frontend_state));
+       pr_debug("%s -> %s\n", dev->otherend, xenbus_strstate(frontend_state));
 
        be->frontend_state = frontend_state;
 
        switch (frontend_state) {
        case XenbusStateInitialising:
-               if (dev->state == XenbusStateClosed) {
-                       pr_info("%s: prepare for reconnect\n", dev->nodename);
-                       xenbus_switch_state(dev, XenbusStateInitWait);
-               }
+               set_backend_state(be, XenbusStateInitWait);
                break;
 
        case XenbusStateInitialised:
                break;
 
        case XenbusStateConnected:
-               if (dev->state == XenbusStateConnected)
-                       break;
-               if (be->vif)
-                       connect(be);
+               set_backend_state(be, XenbusStateConnected);
                break;
 
        case XenbusStateClosing:
-               disconnect_backend(dev);
-               xenbus_switch_state(dev, XenbusStateClosing);
+               set_backend_state(be, XenbusStateClosing);
                break;
 
        case XenbusStateClosed:
-               xenbus_switch_state(dev, XenbusStateClosed);
+               set_backend_state(be, XenbusStateClosed);
                if (xenbus_dev_is_online(dev))
                        break;
-               destroy_backend(dev);
                /* fall through if not online */
        case XenbusStateUnknown:
+               set_backend_state(be, XenbusStateClosed);
                device_unregister(&dev->dev);
                break;
 
@@ -363,7 +457,9 @@ static void hotplug_status_changed(struct xenbus_watch *watch,
        if (IS_ERR(str))
                return;
        if (len == sizeof("connected")-1 && !memcmp(str, "connected", len)) {
-               xenbus_switch_state(be->dev, XenbusStateConnected);
+               /* Complete any pending state change */
+               xenbus_switch_state(be->dev, be->state);
+
                /* Not interested in this watch anymore. */
                unregister_hotplug_status_watch(be);
        }
@@ -393,12 +489,8 @@ static void connect(struct backend_info *be)
        err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
                                   hotplug_status_changed,
                                   "%s/%s", dev->nodename, "hotplug-status");
-       if (err) {
-               /* Switch now, since we can't do a watch. */
-               xenbus_switch_state(dev, XenbusStateConnected);
-       } else {
+       if (!err)
                be->have_hotplug_status_watch = 1;
-       }
 
        netif_wake_queue(be->vif->dev);
 }
index 9d2009a..78cc760 100644 (file)
@@ -74,10 +74,4 @@ config OF_MTD
        depends on MTD
        def_bool y
 
-config OF_RESERVED_MEM
-       depends on OF_FLATTREE && (DMA_CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK))
-       def_bool y
-       help
-         Initialization code for DMA reserved memory
-
 endmenu # OF
index ed9660a..efd0510 100644 (file)
@@ -9,4 +9,3 @@ obj-$(CONFIG_OF_MDIO)   += of_mdio.o
 obj-$(CONFIG_OF_PCI)   += of_pci.o
 obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
 obj-$(CONFIG_OF_MTD)   += of_mtd.o
-obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
index 865d3f6..7d4c70f 100644 (file)
@@ -303,10 +303,8 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
        struct device_node *cpun, *cpus;
 
        cpus = of_find_node_by_path("/cpus");
-       if (!cpus) {
-               pr_warn("Missing cpus node, bailing out\n");
+       if (!cpus)
                return NULL;
-       }
 
        for_each_child_of_node(cpus, cpun) {
                if (of_node_cmp(cpun->type, "cpu"))
index 229dd9d..a4fa9ad 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/random.h>
 
 #include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
 #ifdef CONFIG_PPC
@@ -803,14 +802,3 @@ void __init unflatten_device_tree(void)
 }
 
 #endif /* CONFIG_OF_EARLY_FLATTREE */
-
-/* Feed entire flattened device tree into the random pool */
-static int __init add_fdt_randomness(void)
-{
-       if (initial_boot_params)
-               add_device_randomness(initial_boot_params,
-                               be32_to_cpu(initial_boot_params->totalsize));
-
-       return 0;
-}
-core_initcall(add_fdt_randomness);
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
deleted file mode 100644 (file)
index 0fe40c7..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Device tree based initialization code for reserved memory.
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- * Author: Marek Szyprowski <m.szyprowski@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 optional) any later version of the license.
- */
-
-#include <linux/memblock.h>
-#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/of_fdt.h>
-#include <linux/of_platform.h>
-#include <linux/mm.h>
-#include <linux/sizes.h>
-#include <linux/mm_types.h>
-#include <linux/dma-contiguous.h>
-#include <linux/dma-mapping.h>
-#include <linux/of_reserved_mem.h>
-
-#define MAX_RESERVED_REGIONS   16
-struct reserved_mem {
-       phys_addr_t             base;
-       unsigned long           size;
-       struct cma              *cma;
-       char                    name[32];
-};
-static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
-static int reserved_mem_count;
-
-static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname,
-                                       int depth, void *data)
-{
-       struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
-       phys_addr_t base, size;
-       int is_cma, is_reserved;
-       unsigned long len;
-       const char *status;
-       __be32 *prop;
-
-       is_cma = IS_ENABLED(CONFIG_DMA_CMA) &&
-              of_flat_dt_is_compatible(node, "linux,contiguous-memory-region");
-       is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region");
-
-       if (!is_reserved && !is_cma) {
-               /* ignore node and scan next one */
-               return 0;
-       }
-
-       status = of_get_flat_dt_prop(node, "status", &len);
-       if (status && strcmp(status, "okay") != 0) {
-               /* ignore disabled node nad scan next one */
-               return 0;
-       }
-
-       prop = of_get_flat_dt_prop(node, "reg", &len);
-       if (!prop || (len < (dt_root_size_cells + dt_root_addr_cells) *
-                            sizeof(__be32))) {
-               pr_err("Reserved mem: node %s, incorrect \"reg\" property\n",
-                      uname);
-               /* ignore node and scan next one */
-               return 0;
-       }
-       base = dt_mem_next_cell(dt_root_addr_cells, &prop);
-       size = dt_mem_next_cell(dt_root_size_cells, &prop);
-
-       if (!size) {
-               /* ignore node and scan next one */
-               return 0;
-       }
-
-       pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n",
-               uname, (unsigned long)base, (unsigned long)size / SZ_1M);
-
-       if (reserved_mem_count == ARRAY_SIZE(reserved_mem))
-               return -ENOSPC;
-
-       rmem->base = base;
-       rmem->size = size;
-       strlcpy(rmem->name, uname, sizeof(rmem->name));
-
-       if (is_cma) {
-               struct cma *cma;
-               if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) {
-                       rmem->cma = cma;
-                       reserved_mem_count++;
-                       if (of_get_flat_dt_prop(node,
-                                               "linux,default-contiguous-region",
-                                               NULL))
-                               dma_contiguous_set_default(cma);
-               }
-       } else if (is_reserved) {
-               if (memblock_remove(base, size) == 0)
-                       reserved_mem_count++;
-               else
-                       pr_err("Failed to reserve memory for %s\n", uname);
-       }
-
-       return 0;
-}
-
-static struct reserved_mem *get_dma_memory_region(struct device *dev)
-{
-       struct device_node *node;
-       const char *name;
-       int i;
-
-       node = of_parse_phandle(dev->of_node, "memory-region", 0);
-       if (!node)
-               return NULL;
-
-       name = kbasename(node->full_name);
-       for (i = 0; i < reserved_mem_count; i++)
-               if (strcmp(name, reserved_mem[i].name) == 0)
-                       return &reserved_mem[i];
-       return NULL;
-}
-
-/**
- * of_reserved_mem_device_init() - assign reserved memory region to given device
- *
- * This function assign memory region pointed by "memory-region" device tree
- * property to the given device.
- */
-void of_reserved_mem_device_init(struct device *dev)
-{
-       struct reserved_mem *region = get_dma_memory_region(dev);
-       if (!region)
-               return;
-
-       if (region->cma) {
-               dev_set_cma_area(dev, region->cma);
-               pr_info("Assigned CMA %s to %s device\n", region->name,
-                       dev_name(dev));
-       } else {
-               if (dma_declare_coherent_memory(dev, region->base, region->base,
-                   region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0)
-                       pr_info("Declared reserved memory %s to %s device\n",
-                               region->name, dev_name(dev));
-       }
-}
-
-/**
- * of_reserved_mem_device_release() - release reserved memory device structures
- *
- * This function releases structures allocated for memory region handling for
- * the given device.
- */
-void of_reserved_mem_device_release(struct device *dev)
-{
-       struct reserved_mem *region = get_dma_memory_region(dev);
-       if (!region && !region->cma)
-               dma_release_declared_memory(dev);
-}
-
-/**
- * early_init_dt_scan_reserved_mem() - create reserved memory regions
- *
- * This function grabs memory from early allocator for device exclusive use
- * defined in device tree structures. It should be called by arch specific code
- * once the early allocator (memblock) has been activated and all other
- * subsystems have already allocated/reserved memory.
- */
-void __init early_init_dt_scan_reserved_mem(void)
-{
-       of_scan_flat_dt_by_path("/memory/reserved-memory",
-                               fdt_scan_reserved_mem, NULL);
-}
index 9b439ac..f6dcde2 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
-#include <linux/of_reserved_mem.h>
 #include <linux/platform_device.h>
 
 const struct of_device_id of_default_bus_match_table[] = {
@@ -219,8 +218,6 @@ static struct platform_device *of_platform_device_create_pdata(
        dev->dev.bus = &platform_bus_type;
        dev->dev.platform_data = platform_data;
 
-       of_reserved_mem_device_init(&dev->dev);
-
        /* We do not fill the DMA ops for platform devices by default.
         * This is currently the responsibility of the platform code
         * to do such, possibly using a device notifier
@@ -228,7 +225,6 @@ static struct platform_device *of_platform_device_create_pdata(
 
        if (of_device_add(dev) != 0) {
                platform_device_put(dev);
-               of_reserved_mem_device_release(&dev->dev);
                return NULL;
        }
 
index 0b7d23b..1ea7523 100644 (file)
@@ -552,9 +552,8 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
        struct acpiphp_func *func;
        int max, pass;
        LIST_HEAD(add_list);
-       int nr_found;
 
-       nr_found = acpiphp_rescan_slot(slot);
+       acpiphp_rescan_slot(slot);
        max = acpiphp_max_busnr(bus);
        for (pass = 0; pass < 2; pass++) {
                list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -574,9 +573,6 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
                }
        }
        __pci_bus_assign_resources(bus, &add_list, NULL);
-       /* Nothing more to do here if there are no new devices on this bus. */
-       if (!nr_found && (slot->flags & SLOT_ENABLED))
-               return;
 
        acpiphp_sanitize_bus(bus);
        acpiphp_set_hpp_values(bus);
@@ -994,14 +990,16 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
 
                /*
                 * This bridge should have been registered as a hotplug function
-                * under its parent, so the context has to be there.  If not, we
-                * are in deep goo.
+                * under its parent, so the context should be there, unless the
+                * parent is going to be handled by pciehp, in which case this
+                * bridge is not interesting to us either.
                 */
                mutex_lock(&acpiphp_context_lock);
                context = acpiphp_get_context(handle);
-               if (WARN_ON(!context)) {
+               if (!context) {
                        mutex_unlock(&acpiphp_context_lock);
                        put_device(&bus->dev);
+                       pci_dev_put(bridge->pci_dev);
                        kfree(bridge);
                        return;
                }
index a138965..b8fcc38 100644 (file)
@@ -490,7 +490,7 @@ exit:
  * <devicename> <state> <pinname> are values that should match the pinctrl-maps
  * <newvalue> reflects the new config and is driver dependant
  */
-static int pinconf_dbg_config_write(struct file *file,
+static ssize_t pinconf_dbg_config_write(struct file *file,
        const char __user *user_buf, size_t count, loff_t *ppos)
 {
        struct pinctrl_maps *maps_node;
@@ -508,7 +508,7 @@ static int pinconf_dbg_config_write(struct file *file,
        int i;
 
        /* Get userspace string and assure termination */
-       buf_size = min(count, (size_t)(sizeof(buf)-1));
+       buf_size = min(count, sizeof(buf) - 1);
        if (copy_from_user(buf, user_buf, buf_size))
                return -EFAULT;
        buf[buf_size] = 0;
index 2689f8d..155b1b3 100644 (file)
@@ -663,18 +663,18 @@ static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
 /* pin banks of s5pv210 pin-controller */
 static struct samsung_pin_bank s5pv210_pin_bank[] = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpa1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
        EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c),
        EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10),
        EXYNOS_PIN_BANK_EINTG(4, 0x0a0, "gpd0", 0x14),
-       EXYNOS_PIN_BANK_EINTG(4, 0x0c0, "gpd1", 0x18),
-       EXYNOS_PIN_BANK_EINTG(5, 0x0e0, "gpe0", 0x1c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20),
-       EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpf0", 0x24),
+       EXYNOS_PIN_BANK_EINTG(6, 0x0c0, "gpd1", 0x18),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpe0", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(5, 0x100, "gpe1", 0x20),
+       EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpf0", 0x24),
        EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpf1", 0x28),
        EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpf2", 0x2c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf3", 0x30),
+       EXYNOS_PIN_BANK_EINTG(6, 0x180, "gpf3", 0x30),
        EXYNOS_PIN_BANK_EINTG(7, 0x1a0, "gpg0", 0x34),
        EXYNOS_PIN_BANK_EINTG(7, 0x1c0, "gpg1", 0x38),
        EXYNOS_PIN_BANK_EINTG(7, 0x1e0, "gpg2", 0x3c),
index 82638fa..30c4d35 100644 (file)
@@ -891,9 +891,10 @@ static int palmas_pinconf_set(struct pinctrl_dev *pctldev,
                param = pinconf_to_config_param(configs[i]);
                param_val = pinconf_to_config_argument(configs[i]);
 
+               if (param == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+                       continue;
+
                switch (param) {
-               case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
-                       return 0;
                case PIN_CONFIG_BIAS_DISABLE:
                case PIN_CONFIG_BIAS_PULL_UP:
                case PIN_CONFIG_BIAS_PULL_DOWN:
index 622c485..93c9e38 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
  *
- * Arthur:  Pritesh Raithatha <praithatha@nvidia.com>
+ * Author:  Pritesh Raithatha <praithatha@nvidia.com>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -2763,7 +2763,6 @@ static struct platform_driver tegra114_pinctrl_driver = {
 };
 module_platform_driver(tegra114_pinctrl_driver);
 
-MODULE_ALIAS("platform:tegra114-pinctrl");
 MODULE_AUTHOR("Pritesh Raithatha <praithatha@nvidia.com>");
-MODULE_DESCRIPTION("NVIDIA Tegra114 pincontrol driver");
+MODULE_DESCRIPTION("NVIDIA Tegra114 pinctrl driver");
 MODULE_LICENSE("GPL v2");
index 96d6b2e..b51a746 100644 (file)
@@ -504,6 +504,7 @@ config ASUS_WMI
        depends on BACKLIGHT_CLASS_DEVICE
        depends on RFKILL || RFKILL = n
        depends on HOTPLUG_PCI
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        select INPUT_SPARSEKMAP
        select LEDS_CLASS
        select NEW_LEDS
index d3fd520..13ec195 100644 (file)
@@ -127,18 +127,17 @@ MODULE_PARM_DESC(minor,
                 "default is -1 (automatic)");
 #endif
 
-static int kbd_backlight = 1;
+static int kbd_backlight = -1;
 module_param(kbd_backlight, int, 0444);
 MODULE_PARM_DESC(kbd_backlight,
                 "set this to 0 to disable keyboard backlight, "
-                "1 to enable it (default: 0)");
+                "1 to enable it (default: no change from current value)");
 
-static int kbd_backlight_timeout;      /* = 0 */
+static int kbd_backlight_timeout = -1;
 module_param(kbd_backlight_timeout, int, 0444);
 MODULE_PARM_DESC(kbd_backlight_timeout,
-                "set this to 0 to set the default 10 seconds timeout, "
-                "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
-                "(default: 0)");
+                "meaningful values vary from 0 to 3 and their meaning depends "
+                "on the model (default: no change from current value)");
 
 #ifdef CONFIG_PM_SLEEP
 static void sony_nc_kbd_backlight_resume(void);
@@ -1844,6 +1843,8 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
        if (!kbdbl_ctl)
                return -ENOMEM;
 
+       kbdbl_ctl->mode = kbd_backlight;
+       kbdbl_ctl->timeout = kbd_backlight_timeout;
        kbdbl_ctl->handle = handle;
        if (handle == 0x0137)
                kbdbl_ctl->base = 0x0C00;
@@ -1870,8 +1871,8 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
        if (ret)
                goto outmode;
 
-       __sony_nc_kbd_backlight_mode_set(kbd_backlight);
-       __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
+       __sony_nc_kbd_backlight_mode_set(kbdbl_ctl->mode);
+       __sony_nc_kbd_backlight_timeout_set(kbdbl_ctl->timeout);
 
        return 0;
 
@@ -1886,17 +1887,8 @@ outkzalloc:
 static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
 {
        if (kbdbl_ctl) {
-               int result;
-
                device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
                device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr);
-
-               /* restore the default hw behaviour */
-               sony_call_snc_handle(kbdbl_ctl->handle,
-                               kbdbl_ctl->base | 0x10000, &result);
-               sony_call_snc_handle(kbdbl_ctl->handle,
-                               kbdbl_ctl->base + 0x200, &result);
-
                kfree(kbdbl_ctl);
                kbdbl_ctl = NULL;
        }
index 1a78163..b9f2653 100644 (file)
@@ -709,7 +709,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
                struct of_regulator_match **da9063_reg_matches)
 {
        da9063_reg_matches = NULL;
-       return PTR_ERR(-ENODEV);
+       return ERR_PTR(-ENODEV);
 }
 #endif
 
index 488dfe7..7e2b165 100644 (file)
@@ -201,13 +201,7 @@ static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500};
 #define SMPS_CTRL_MODE_ECO             0x02
 #define SMPS_CTRL_MODE_PWM             0x03
 
-/* These values are derived from the data sheet. And are the number of steps
- * where there is a voltage change, the ranges at beginning and end of register
- * max/min values where there are no change are ommitted.
- *
- * So they are basically (maxV-minV)/stepV
- */
-#define PALMAS_SMPS_NUM_VOLTAGES       117
+#define PALMAS_SMPS_NUM_VOLTAGES       122
 #define PALMAS_SMPS10_NUM_VOLTAGES     2
 #define PALMAS_LDO_NUM_VOLTAGES                50
 
@@ -979,6 +973,7 @@ static int palmas_regulators_probe(struct platform_device *pdev)
                        pmic->desc[id].min_uV = 900000;
                        pmic->desc[id].uV_step = 50000;
                        pmic->desc[id].linear_min_sel = 1;
+                       pmic->desc[id].enable_time = 500;
                        pmic->desc[id].vsel_reg =
                                        PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
                                                palmas_regs_info[id].vsel_addr);
@@ -997,6 +992,11 @@ static int palmas_regulators_probe(struct platform_device *pdev)
                                pmic->desc[id].min_uV = 450000;
                                pmic->desc[id].uV_step = 25000;
                        }
+
+                       /* LOD6 in vibrator mode will have enable time 2000us */
+                       if (pdata && pdata->ldo6_vibrator &&
+                               (id == PALMAS_REG_LDO6))
+                               pmic->desc[id].enable_time = 2000;
                } else {
                        pmic->desc[id].n_voltages = 1;
                        pmic->desc[id].ops = &palmas_ops_extreg;
index d8e3e12..20c271d 100644 (file)
@@ -279,8 +279,12 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
        ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg,
                   abb->base);
 
-       /* program LDO VBB vset override if needed */
-       if (abb->ldo_base)
+       /*
+        * program LDO VBB vset override if needed for !bypass mode
+        * XXX: Do not switch sequence - for !bypass, LDO override reset *must*
+        * be performed *before* switch to bias mode else VBB glitches.
+        */
+       if (abb->ldo_base && info->opp_sel != TI_ABB_NOMINAL_OPP)
                ti_abb_program_ldovbb(dev, abb, info);
 
        /* Initiate ABB ldo change */
@@ -295,6 +299,14 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
        if (ret)
                goto out;
 
+       /*
+        * Reset LDO VBB vset override bypass mode
+        * XXX: Do not switch sequence - for bypass, LDO override reset *must*
+        * be performed *after* switch to bypass else VBB glitches.
+        */
+       if (abb->ldo_base && info->opp_sel == TI_ABB_NOMINAL_OPP)
+               ti_abb_program_ldovbb(dev, abb, info);
+
 out:
        return ret;
 }
index 1432b26..2205fbc 100644 (file)
@@ -63,7 +63,7 @@ static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data)
  */
 
 static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = {
-       { .min_uV =  900000, .max_uV = 1650000, .min_sel =  0, .max_sel = 14,
+       { .min_uV =  900000, .max_uV = 1600000, .min_sel =  0, .max_sel = 14,
          .uV_step =  50000 },
        { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31,
          .uV_step = 100000 },
@@ -332,7 +332,7 @@ static struct platform_driver wm831x_gp_ldo_driver = {
  */
 
 static const struct regulator_linear_range wm831x_aldo_ranges[] = {
-       { .min_uV = 1000000, .max_uV = 1650000, .min_sel =  0, .max_sel = 12,
+       { .min_uV = 1000000, .max_uV = 1600000, .min_sel =  0, .max_sel = 12,
          .uV_step =  50000 },
        { .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31,
          .uV_step = 100000 },
index 835b5f0..61ca929 100644 (file)
@@ -543,7 +543,7 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
 }
 
 static const struct regulator_linear_range wm8350_ldo_ranges[] = {
-       { .min_uV =  900000, .max_uV = 1750000, .min_sel =  0, .max_sel = 15,
+       { .min_uV =  900000, .max_uV = 1650000, .min_sel =  0, .max_sel = 15,
          .uV_step =  50000 },
        { .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31,
          .uV_step = 100000 },
index 5adb204..cee7e27 100644 (file)
@@ -2077,6 +2077,7 @@ dasd_eckd_build_format(struct dasd_device *base,
        int intensity = 0;
        int r0_perm;
        int nr_tracks;
+       int use_prefix;
 
        startdev = dasd_alias_get_start_dev(base);
        if (!startdev)
@@ -2106,28 +2107,46 @@ dasd_eckd_build_format(struct dasd_device *base,
                intensity = fdata->intensity;
        }
 
+       use_prefix = base_priv->features.feature[8] & 0x01;
+
        switch (intensity) {
        case 0x00:      /* Normal format */
        case 0x08:      /* Normal format, use cdl. */
                cplength = 2 + (rpt*nr_tracks);
-               datasize = sizeof(struct PFX_eckd_data) +
-                       sizeof(struct LO_eckd_data) +
-                       rpt * nr_tracks * sizeof(struct eckd_count);
+               if (use_prefix)
+                       datasize = sizeof(struct PFX_eckd_data) +
+                               sizeof(struct LO_eckd_data) +
+                               rpt * nr_tracks * sizeof(struct eckd_count);
+               else
+                       datasize = sizeof(struct DE_eckd_data) +
+                               sizeof(struct LO_eckd_data) +
+                               rpt * nr_tracks * sizeof(struct eckd_count);
                break;
        case 0x01:      /* Write record zero and format track. */
        case 0x09:      /* Write record zero and format track, use cdl. */
                cplength = 2 + rpt * nr_tracks;
-               datasize = sizeof(struct PFX_eckd_data) +
-                       sizeof(struct LO_eckd_data) +
-                       sizeof(struct eckd_count) +
-                       rpt * nr_tracks * sizeof(struct eckd_count);
+               if (use_prefix)
+                       datasize = sizeof(struct PFX_eckd_data) +
+                               sizeof(struct LO_eckd_data) +
+                               sizeof(struct eckd_count) +
+                               rpt * nr_tracks * sizeof(struct eckd_count);
+               else
+                       datasize = sizeof(struct DE_eckd_data) +
+                               sizeof(struct LO_eckd_data) +
+                               sizeof(struct eckd_count) +
+                               rpt * nr_tracks * sizeof(struct eckd_count);
                break;
        case 0x04:      /* Invalidate track. */
        case 0x0c:      /* Invalidate track, use cdl. */
                cplength = 3;
-               datasize = sizeof(struct PFX_eckd_data) +
-                       sizeof(struct LO_eckd_data) +
-                       sizeof(struct eckd_count);
+               if (use_prefix)
+                       datasize = sizeof(struct PFX_eckd_data) +
+                               sizeof(struct LO_eckd_data) +
+                               sizeof(struct eckd_count);
+               else
+                       datasize = sizeof(struct DE_eckd_data) +
+                               sizeof(struct LO_eckd_data) +
+                               sizeof(struct eckd_count);
                break;
        default:
                dev_warn(&startdev->cdev->dev,
@@ -2147,14 +2166,25 @@ dasd_eckd_build_format(struct dasd_device *base,
 
        switch (intensity & ~0x08) {
        case 0x00: /* Normal format. */
-               prefix(ccw++, (struct PFX_eckd_data *) data,
-                      fdata->start_unit, fdata->stop_unit,
-                      DASD_ECKD_CCW_WRITE_CKD, base, startdev);
-               /* grant subsystem permission to format R0 */
-               if (r0_perm)
-                       ((struct PFX_eckd_data *)data)
-                               ->define_extent.ga_extended |= 0x04;
-               data += sizeof(struct PFX_eckd_data);
+               if (use_prefix) {
+                       prefix(ccw++, (struct PFX_eckd_data *) data,
+                              fdata->start_unit, fdata->stop_unit,
+                              DASD_ECKD_CCW_WRITE_CKD, base, startdev);
+                       /* grant subsystem permission to format R0 */
+                       if (r0_perm)
+                               ((struct PFX_eckd_data *)data)
+                                       ->define_extent.ga_extended |= 0x04;
+                       data += sizeof(struct PFX_eckd_data);
+               } else {
+                       define_extent(ccw++, (struct DE_eckd_data *) data,
+                                     fdata->start_unit, fdata->stop_unit,
+                                     DASD_ECKD_CCW_WRITE_CKD, startdev);
+                       /* grant subsystem permission to format R0 */
+                       if (r0_perm)
+                               ((struct DE_eckd_data *) data)
+                                       ->ga_extended |= 0x04;
+                       data += sizeof(struct DE_eckd_data);
+               }
                ccw[-1].flags |= CCW_FLAG_CC;
                locate_record(ccw++, (struct LO_eckd_data *) data,
                              fdata->start_unit, 0, rpt*nr_tracks,
@@ -2163,11 +2193,18 @@ dasd_eckd_build_format(struct dasd_device *base,
                data += sizeof(struct LO_eckd_data);
                break;
        case 0x01: /* Write record zero + format track. */
-               prefix(ccw++, (struct PFX_eckd_data *) data,
-                      fdata->start_unit, fdata->stop_unit,
-                      DASD_ECKD_CCW_WRITE_RECORD_ZERO,
-                      base, startdev);
-               data += sizeof(struct PFX_eckd_data);
+               if (use_prefix) {
+                       prefix(ccw++, (struct PFX_eckd_data *) data,
+                              fdata->start_unit, fdata->stop_unit,
+                              DASD_ECKD_CCW_WRITE_RECORD_ZERO,
+                              base, startdev);
+                       data += sizeof(struct PFX_eckd_data);
+               } else {
+                       define_extent(ccw++, (struct DE_eckd_data *) data,
+                              fdata->start_unit, fdata->stop_unit,
+                              DASD_ECKD_CCW_WRITE_RECORD_ZERO, startdev);
+                       data += sizeof(struct DE_eckd_data);
+               }
                ccw[-1].flags |= CCW_FLAG_CC;
                locate_record(ccw++, (struct LO_eckd_data *) data,
                              fdata->start_unit, 0, rpt * nr_tracks + 1,
@@ -2176,10 +2213,17 @@ dasd_eckd_build_format(struct dasd_device *base,
                data += sizeof(struct LO_eckd_data);
                break;
        case 0x04: /* Invalidate track. */
-               prefix(ccw++, (struct PFX_eckd_data *) data,
-                      fdata->start_unit, fdata->stop_unit,
-                      DASD_ECKD_CCW_WRITE_CKD, base, startdev);
-               data += sizeof(struct PFX_eckd_data);
+               if (use_prefix) {
+                       prefix(ccw++, (struct PFX_eckd_data *) data,
+                              fdata->start_unit, fdata->stop_unit,
+                              DASD_ECKD_CCW_WRITE_CKD, base, startdev);
+                       data += sizeof(struct PFX_eckd_data);
+               } else {
+                       define_extent(ccw++, (struct DE_eckd_data *) data,
+                              fdata->start_unit, fdata->stop_unit,
+                              DASD_ECKD_CCW_WRITE_CKD, startdev);
+                       data += sizeof(struct DE_eckd_data);
+               }
                ccw[-1].flags |= CCW_FLAG_CC;
                locate_record(ccw++, (struct LO_eckd_data *) data,
                              fdata->start_unit, 0, 1,
index a3aa374..1fe2643 100644 (file)
@@ -486,7 +486,7 @@ sclp_sync_wait(void)
        timeout = 0;
        if (timer_pending(&sclp_request_timer)) {
                /* Get timeout TOD value */
-               timeout = get_tod_clock() +
+               timeout = get_tod_clock_fast() +
                          sclp_tod_from_jiffies(sclp_request_timer.expires -
                                                jiffies);
        }
@@ -508,7 +508,7 @@ sclp_sync_wait(void)
        while (sclp_running_state != sclp_running_state_idle) {
                /* Check for expired request timer */
                if (timer_pending(&sclp_request_timer) &&
-                   get_tod_clock() > timeout &&
+                   get_tod_clock_fast() > timeout &&
                    del_timer(&sclp_request_timer))
                        sclp_request_timer.function(sclp_request_timer.data);
                cpu_relax();
index 8cd34bf..77df9cb 100644 (file)
@@ -145,9 +145,11 @@ bool __init sclp_has_linemode(void)
 
        if (sccb->header.response_code != 0x20)
                return 0;
-       if (sccb->sclp_send_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))
-               return 1;
-       return 0;
+       if (!(sccb->sclp_send_mask & (EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK)))
+               return 0;
+       if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
+               return 0;
+       return 1;
 }
 
 bool __init sclp_has_vt220(void)
index a0f47c8..3f4ca4e 100644 (file)
@@ -810,7 +810,7 @@ static void tty3270_resize_work(struct work_struct *work)
        struct winsize ws;
 
        screen = tty3270_alloc_screen(tp->n_rows, tp->n_cols);
-       if (!screen)
+       if (IS_ERR(screen))
                return;
        /* Switch to new output size */
        spin_lock_bh(&tp->view.lock);
index 9b3a24e..cf31d33 100644 (file)
@@ -313,7 +313,7 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp)
        int ret;
 
        dev_num = iminor(inode);
-       if (dev_num > MAXMINOR)
+       if (dev_num >= MAXMINOR)
                return -ENODEV;
        logptr = &sys_ser[dev_num];
 
index d7da67a..88e35d8 100644 (file)
@@ -878,9 +878,9 @@ static void css_reset(void)
                        atomic_inc(&chpid_reset_count);
        }
        /* Wait for machine check for all channel paths. */
-       timeout = get_tod_clock() + (RCHP_TIMEOUT << 12);
+       timeout = get_tod_clock_fast() + (RCHP_TIMEOUT << 12);
        while (atomic_read(&chpid_reset_count) != 0) {
-               if (get_tod_clock() > timeout)
+               if (get_tod_clock_fast() > timeout)
                        break;
                cpu_relax();
        }
index 8ed52aa..bbd3e51 100644 (file)
@@ -338,10 +338,10 @@ again:
                retries++;
 
                if (!start_time) {
-                       start_time = get_tod_clock();
+                       start_time = get_tod_clock_fast();
                        goto again;
                }
-               if ((get_tod_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE)
+               if (get_tod_clock_fast() - start_time < QDIO_BUSY_BIT_PATIENCE)
                        goto again;
        }
        if (retries) {
@@ -504,7 +504,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
        int count, stop;
        unsigned char state = 0;
 
-       q->timestamp = get_tod_clock();
+       q->timestamp = get_tod_clock_fast();
 
        /*
         * Don't check 128 buffers, as otherwise qdio_inbound_q_moved
@@ -595,7 +595,7 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
         * At this point we know, that inbound first_to_check
         * has (probably) not moved (see qdio_inbound_processing).
         */
-       if (get_tod_clock() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) {
+       if (get_tod_clock_fast() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) {
                DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x",
                              q->first_to_check);
                return 1;
@@ -728,7 +728,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
        int count, stop;
        unsigned char state = 0;
 
-       q->timestamp = get_tod_clock();
+       q->timestamp = get_tod_clock_fast();
 
        if (need_siga_sync(q))
                if (((queue_type(q) != QDIO_IQDIO_QFMT) &&
index feab3a5..757eb07 100644 (file)
@@ -696,7 +696,7 @@ static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter)
        while ((pci_device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC,
                                        PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
                                        pci_device)) != NULL) {
-               struct blogic_adapter *adapter = adapter;
+               struct blogic_adapter *host_adapter = adapter;
                struct blogic_adapter_info adapter_info;
                enum blogic_isa_ioport mod_ioaddr_req;
                unsigned char bus;
@@ -744,9 +744,9 @@ static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter)
                   known and enabled, note that the particular Standard ISA I/O
                   Address should not be probed.
                 */
-               adapter->io_addr = io_addr;
-               blogic_intreset(adapter);
-               if (blogic_cmd(adapter, BLOGIC_INQ_PCI_INFO, NULL, 0,
+               host_adapter->io_addr = io_addr;
+               blogic_intreset(host_adapter);
+               if (blogic_cmd(host_adapter, BLOGIC_INQ_PCI_INFO, NULL, 0,
                                &adapter_info, sizeof(adapter_info)) ==
                                sizeof(adapter_info)) {
                        if (adapter_info.isa_port < 6)
@@ -762,7 +762,7 @@ static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter)
                   I/O Address assigned at system initialization.
                 */
                mod_ioaddr_req = BLOGIC_IO_DISABLE;
-               blogic_cmd(adapter, BLOGIC_MOD_IOADDR, &mod_ioaddr_req,
+               blogic_cmd(host_adapter, BLOGIC_MOD_IOADDR, &mod_ioaddr_req,
                                sizeof(mod_ioaddr_req), NULL, 0);
                /*
                   For the first MultiMaster Host Adapter enumerated,
@@ -779,12 +779,12 @@ static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter)
 
                        fetch_localram.offset = BLOGIC_AUTOSCSI_BASE + 45;
                        fetch_localram.count = sizeof(autoscsi_byte45);
-                       blogic_cmd(adapter, BLOGIC_FETCH_LOCALRAM,
+                       blogic_cmd(host_adapter, BLOGIC_FETCH_LOCALRAM,
                                        &fetch_localram, sizeof(fetch_localram),
                                        &autoscsi_byte45,
                                        sizeof(autoscsi_byte45));
-                       blogic_cmd(adapter, BLOGIC_GET_BOARD_ID, NULL, 0, &id,
-                                       sizeof(id));
+                       blogic_cmd(host_adapter, BLOGIC_GET_BOARD_ID, NULL, 0,
+                                       &id, sizeof(id));
                        if (id.fw_ver_digit1 == '5')
                                force_scan_order =
                                        autoscsi_byte45.force_scan_order;
index 408a42e..f0d432c 100644 (file)
@@ -771,6 +771,8 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
 static int aac_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
 {
        struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
        return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg);
 }
 
index 2ef497e..ee5c183 100644 (file)
@@ -20,7 +20,7 @@
  * | Device Discovery             |       0x2095       | 0x2020-0x2022, |
  * |                              |                    | 0x2011-0x2012, |
  * |                              |                    | 0x2016         |
- * | Queue Command and IO tracing |       0x3058       | 0x3006-0x300b  |
+ * | Queue Command and IO tracing |       0x3059       | 0x3006-0x300b  |
  * |                              |                    | 0x3027-0x3028  |
  * |                              |                    | 0x303d-0x3041  |
  * |                              |                    | 0x302d,0x3033  |
index df1b30b..ff9c86b 100644 (file)
@@ -1957,6 +1957,15 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        que = MSW(sts->handle);
        req = ha->req_q_map[que];
 
+       /* Check for invalid queue pointer */
+       if (req == NULL ||
+           que >= find_first_zero_bit(ha->req_qid_map, ha->max_req_queues)) {
+               ql_dbg(ql_dbg_io, vha, 0x3059,
+                   "Invalid status handle (0x%x): Bad req pointer. req=%p, "
+                   "que=%u.\n", sts->handle, req, que);
+               return;
+       }
+
        /* Validate handle. */
        if (handle < req->num_outstanding_cmds)
                sp = req->outstanding_cmds[handle];
index e62d17d..5693f6d 100644 (file)
@@ -2854,6 +2854,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
                gd->events |= DISK_EVENT_MEDIA_CHANGE;
        }
 
+       blk_pm_runtime_init(sdp->request_queue, dev);
        add_disk(gd);
        if (sdkp->capacity)
                sd_dif_config_host(sdkp);
@@ -2862,7 +2863,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
 
        sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
                  sdp->removable ? "removable " : "");
-       blk_pm_runtime_init(sdp->request_queue, dev);
        scsi_autopm_put_device(sdp);
        put_device(&sdkp->dev);
 }
index 5cbc4bb..df5e961 100644 (file)
@@ -105,8 +105,11 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ;
 static int sg_add(struct device *, struct class_interface *);
 static void sg_remove(struct device *, struct class_interface *);
 
+static DEFINE_SPINLOCK(sg_open_exclusive_lock);
+
 static DEFINE_IDR(sg_index_idr);
-static DEFINE_RWLOCK(sg_index_lock);
+static DEFINE_RWLOCK(sg_index_lock);   /* Also used to lock
+                                                          file descriptor list for device */
 
 static struct class_interface sg_interface = {
        .add_dev        = sg_add,
@@ -143,7 +146,8 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
 } Sg_request;
 
 typedef struct sg_fd {         /* holds the state of a file descriptor */
-       struct list_head sfd_siblings; /* protected by sfd_lock of device */
+       /* sfd_siblings is protected by sg_index_lock */
+       struct list_head sfd_siblings;
        struct sg_device *parentdp;     /* owning device */
        wait_queue_head_t read_wait;    /* queue read until command done */
        rwlock_t rq_list_lock;  /* protect access to list in req_arr */
@@ -166,12 +170,13 @@ typedef struct sg_fd {            /* holds the state of a file descriptor */
 
 typedef struct sg_device { /* holds the state of each scsi generic device */
        struct scsi_device *device;
+       wait_queue_head_t o_excl_wait;  /* queue open() when O_EXCL in use */
        int sg_tablesize;       /* adapter's max scatter-gather table size */
        u32 index;              /* device index number */
-       spinlock_t sfd_lock;    /* protect file descriptor list for device */
+       /* sfds is protected by sg_index_lock */
        struct list_head sfds;
-       struct rw_semaphore o_sem;      /* exclude open should hold this rwsem */
        volatile char detached; /* 0->attached, 1->detached pending removal */
+       /* exclude protected by sg_open_exclusive_lock */
        char exclude;           /* opened for exclusive access */
        char sgdebug;           /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
        struct gendisk *disk;
@@ -220,14 +225,35 @@ static int sg_allow_access(struct file *filp, unsigned char *cmd)
        return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
 }
 
+static int get_exclude(Sg_device *sdp)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&sg_open_exclusive_lock, flags);
+       ret = sdp->exclude;
+       spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
+       return ret;
+}
+
+static int set_exclude(Sg_device *sdp, char val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sg_open_exclusive_lock, flags);
+       sdp->exclude = val;
+       spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
+       return val;
+}
+
 static int sfds_list_empty(Sg_device *sdp)
 {
        unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&sdp->sfd_lock, flags);
+       read_lock_irqsave(&sg_index_lock, flags);
        ret = list_empty(&sdp->sfds);
-       spin_unlock_irqrestore(&sdp->sfd_lock, flags);
+       read_unlock_irqrestore(&sg_index_lock, flags);
        return ret;
 }
 
@@ -239,6 +265,7 @@ sg_open(struct inode *inode, struct file *filp)
        struct request_queue *q;
        Sg_device *sdp;
        Sg_fd *sfp;
+       int res;
        int retval;
 
        nonseekable_open(inode, filp);
@@ -267,52 +294,54 @@ sg_open(struct inode *inode, struct file *filp)
                goto error_out;
        }
 
-       if ((flags & O_EXCL) && (O_RDONLY == (flags & O_ACCMODE))) {
-               retval = -EPERM; /* Can't lock it with read only access */
-               goto error_out;
-       }
-       if (flags & O_NONBLOCK) {
-               if (flags & O_EXCL) {
-                       if (!down_write_trylock(&sdp->o_sem)) {
-                               retval = -EBUSY;
-                               goto error_out;
-                       }
-               } else {
-                       if (!down_read_trylock(&sdp->o_sem)) {
-                               retval = -EBUSY;
-                               goto error_out;
-                       }
+       if (flags & O_EXCL) {
+               if (O_RDONLY == (flags & O_ACCMODE)) {
+                       retval = -EPERM; /* Can't lock it with read only access */
+                       goto error_out;
+               }
+               if (!sfds_list_empty(sdp) && (flags & O_NONBLOCK)) {
+                       retval = -EBUSY;
+                       goto error_out;
+               }
+               res = wait_event_interruptible(sdp->o_excl_wait,
+                                          ((!sfds_list_empty(sdp) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1)));
+               if (res) {
+                       retval = res;   /* -ERESTARTSYS because signal hit process */
+                       goto error_out;
+               }
+       } else if (get_exclude(sdp)) {  /* some other fd has an exclusive lock on dev */
+               if (flags & O_NONBLOCK) {
+                       retval = -EBUSY;
+                       goto error_out;
+               }
+               res = wait_event_interruptible(sdp->o_excl_wait, !get_exclude(sdp));
+               if (res) {
+                       retval = res;   /* -ERESTARTSYS because signal hit process */
+                       goto error_out;
                }
-       } else {
-               if (flags & O_EXCL)
-                       down_write(&sdp->o_sem);
-               else
-                       down_read(&sdp->o_sem);
        }
-       /* Since write lock is held, no need to check sfd_list */
-       if (flags & O_EXCL)
-               sdp->exclude = 1;       /* used by release lock */
-
+       if (sdp->detached) {
+               retval = -ENODEV;
+               goto error_out;
+       }
        if (sfds_list_empty(sdp)) {     /* no existing opens on this device */
                sdp->sgdebug = 0;
                q = sdp->device->request_queue;
                sdp->sg_tablesize = queue_max_segments(q);
        }
-       sfp = sg_add_sfp(sdp, dev);
-       if (!IS_ERR(sfp))
+       if ((sfp = sg_add_sfp(sdp, dev)))
                filp->private_data = sfp;
-               /* retval is already provably zero at this point because of the
-                * check after retval = scsi_autopm_get_device(sdp->device))
-                */
        else {
-               retval = PTR_ERR(sfp);
-
                if (flags & O_EXCL) {
-                       sdp->exclude = 0;       /* undo if error */
-                       up_write(&sdp->o_sem);
-               } else
-                       up_read(&sdp->o_sem);
+                       set_exclude(sdp, 0);    /* undo if error */
+                       wake_up_interruptible(&sdp->o_excl_wait);
+               }
+               retval = -ENOMEM;
+               goto error_out;
+       }
+       retval = 0;
 error_out:
+       if (retval) {
                scsi_autopm_put_device(sdp->device);
 sdp_put:
                scsi_device_put(sdp->device);
@@ -329,18 +358,13 @@ sg_release(struct inode *inode, struct file *filp)
 {
        Sg_device *sdp;
        Sg_fd *sfp;
-       int excl;
 
        if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
                return -ENXIO;
        SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
 
-       excl = sdp->exclude;
-       sdp->exclude = 0;
-       if (excl)
-               up_write(&sdp->o_sem);
-       else
-               up_read(&sdp->o_sem);
+       set_exclude(sdp, 0);
+       wake_up_interruptible(&sdp->o_excl_wait);
 
        scsi_autopm_put_device(sdp->device);
        kref_put(&sfp->f_ref, sg_remove_sfp);
@@ -1391,9 +1415,8 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
        disk->first_minor = k;
        sdp->disk = disk;
        sdp->device = scsidp;
-       spin_lock_init(&sdp->sfd_lock);
        INIT_LIST_HEAD(&sdp->sfds);
-       init_rwsem(&sdp->o_sem);
+       init_waitqueue_head(&sdp->o_excl_wait);
        sdp->sg_tablesize = queue_max_segments(q);
        sdp->index = k;
        kref_init(&sdp->d_ref);
@@ -1526,13 +1549,11 @@ static void sg_remove(struct device *cl_dev, struct class_interface *cl_intf)
 
        /* Need a write lock to set sdp->detached. */
        write_lock_irqsave(&sg_index_lock, iflags);
-       spin_lock(&sdp->sfd_lock);
        sdp->detached = 1;
        list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) {
                wake_up_interruptible(&sfp->read_wait);
                kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
        }
-       spin_unlock(&sdp->sfd_lock);
        write_unlock_irqrestore(&sg_index_lock, iflags);
 
        sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
@@ -2043,7 +2064,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
 
        sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN);
        if (!sfp)
-               return ERR_PTR(-ENOMEM);
+               return NULL;
 
        init_waitqueue_head(&sfp->read_wait);
        rwlock_init(&sfp->rq_list_lock);
@@ -2057,13 +2078,9 @@ sg_add_sfp(Sg_device * sdp, int dev)
        sfp->cmd_q = SG_DEF_COMMAND_Q;
        sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
        sfp->parentdp = sdp;
-       spin_lock_irqsave(&sdp->sfd_lock, iflags);
-       if (sdp->detached) {
-               spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
-               return ERR_PTR(-ENODEV);
-       }
+       write_lock_irqsave(&sg_index_lock, iflags);
        list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
-       spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
+       write_unlock_irqrestore(&sg_index_lock, iflags);
        SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
        if (unlikely(sg_big_buff != def_reserved_size))
                sg_big_buff = def_reserved_size;
@@ -2113,9 +2130,10 @@ static void sg_remove_sfp(struct kref *kref)
        struct sg_device *sdp = sfp->parentdp;
        unsigned long iflags;
 
-       spin_lock_irqsave(&sdp->sfd_lock, iflags);
+       write_lock_irqsave(&sg_index_lock, iflags);
        list_del(&sfp->sfd_siblings);
-       spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
+       write_unlock_irqrestore(&sg_index_lock, iflags);
+       wake_up_interruptible(&sdp->o_excl_wait);
 
        INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext);
        schedule_work(&sfp->ew.work);
@@ -2502,7 +2520,7 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
        return 0;
 }
 
-/* must be called while holding sg_index_lock and sfd_lock */
+/* must be called while holding sg_index_lock */
 static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
 {
        int k, m, new_interface, blen, usg;
@@ -2587,26 +2605,22 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
 
        read_lock_irqsave(&sg_index_lock, iflags);
        sdp = it ? sg_lookup_dev(it->index) : NULL;
-       if (sdp) {
-               spin_lock(&sdp->sfd_lock);
-               if (!list_empty(&sdp->sfds)) {
-                       struct scsi_device *scsidp = sdp->device;
+       if (sdp && !list_empty(&sdp->sfds)) {
+               struct scsi_device *scsidp = sdp->device;
 
-                       seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
-                       if (sdp->detached)
-                               seq_printf(s, "detached pending close ");
-                       else
-                               seq_printf
-                                   (s, "scsi%d chan=%d id=%d lun=%d   em=%d",
-                                    scsidp->host->host_no,
-                                    scsidp->channel, scsidp->id,
-                                    scsidp->lun,
-                                    scsidp->host->hostt->emulated);
-                       seq_printf(s, " sg_tablesize=%d excl=%d\n",
-                                  sdp->sg_tablesize, sdp->exclude);
-                       sg_proc_debug_helper(s, sdp);
-               }
-               spin_unlock(&sdp->sfd_lock);
+               seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
+               if (sdp->detached)
+                       seq_printf(s, "detached pending close ");
+               else
+                       seq_printf
+                           (s, "scsi%d chan=%d id=%d lun=%d   em=%d",
+                            scsidp->host->host_no,
+                            scsidp->channel, scsidp->id,
+                            scsidp->lun,
+                            scsidp->host->hostt->emulated);
+               seq_printf(s, " sg_tablesize=%d excl=%d\n",
+                          sdp->sg_tablesize, get_exclude(sdp));
+               sg_proc_debug_helper(s, sdp);
        }
        read_unlock_irqrestore(&sg_index_lock, iflags);
        return 0;
index fd7cc56..d4ac60b 100644 (file)
@@ -1583,7 +1583,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
        /* Initialize the hardware */
        ret = clk_prepare_enable(clk);
        if (ret)
-               goto out_unmap_regs;
+               goto out_free_irq;
        spi_writel(as, CR, SPI_BIT(SWRST));
        spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
        if (as->caps.has_wdrbt) {
@@ -1614,6 +1614,7 @@ out_free_dma:
        spi_writel(as, CR, SPI_BIT(SWRST));
        spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
        clk_disable_unprepare(clk);
+out_free_irq:
        free_irq(irq, master);
 out_unmap_regs:
        iounmap(as->regs);
index 5655acf..6416798 100644 (file)
@@ -226,7 +226,6 @@ static int spi_clps711x_probe(struct platform_device *pdev)
                               dev_name(&pdev->dev), hw);
        if (ret) {
                dev_err(&pdev->dev, "Can't request IRQ\n");
-               clk_put(hw->spi_clk);
                goto clk_out;
        }
 
@@ -247,7 +246,6 @@ err_out:
                        gpio_free(hw->chipselect[i]);
 
        spi_master_put(master);
-       kfree(master);
 
        return ret;
 }
@@ -263,7 +261,6 @@ static int spi_clps711x_remove(struct platform_device *pdev)
                        gpio_free(hw->chipselect[i]);
 
        spi_unregister_master(master);
-       kfree(master);
 
        return 0;
 }
index 6cd07d1..4e44575 100644 (file)
@@ -476,15 +476,9 @@ static int dspi_probe(struct platform_device *pdev)
        master->bus_num = bus_num;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "can't get platform resource\n");
-               ret = -EINVAL;
-               goto out_master_put;
-       }
-
        dspi->base = devm_ioremap_resource(&pdev->dev, res);
-       if (!dspi->base) {
-               ret = -EINVAL;
+       if (IS_ERR(dspi->base)) {
+               ret = PTR_ERR(dspi->base);
                goto out_master_put;
        }
 
index dbc5e99..6adf4e3 100644 (file)
@@ -522,8 +522,10 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
        psc_num = master->bus_num;
        snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
        clk = devm_clk_get(dev, clk_name);
-       if (IS_ERR(clk))
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
                goto free_irq;
+       }
        ret = clk_prepare_enable(clk);
        if (ret)
                goto free_irq;
index 2eb06ee..c1a5067 100644 (file)
@@ -546,8 +546,17 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
        if (pm_runtime_suspended(&drv_data->pdev->dev))
                return IRQ_NONE;
 
-       sccr1_reg = read_SSCR1(reg);
+       /*
+        * If the device is not yet in RPM suspended state and we get an
+        * interrupt that is meant for another device, check if status bits
+        * are all set to one. That means that the device is already
+        * powered off.
+        */
        status = read_SSSR(reg);
+       if (status == ~0)
+               return IRQ_NONE;
+
+       sccr1_reg = read_SSCR1(reg);
 
        /* Ignore possible writes if we don't need to write */
        if (!(sccr1_reg & SSCR1_TIE))
index 512b889..a80376d 100644 (file)
@@ -1428,6 +1428,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
               S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
               sdd->regs + S3C64XX_SPI_INT_EN);
 
+       pm_runtime_enable(&pdev->dev);
+
        if (spi_register_master(master)) {
                dev_err(&pdev->dev, "cannot register SPI master\n");
                ret = -EBUSY;
@@ -1440,8 +1442,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
                                        mem_res,
                                        sdd->rx_dma.dmach, sdd->tx_dma.dmach);
 
-       pm_runtime_enable(&pdev->dev);
-
        return 0;
 
 err3:
index 0b68cb5..e488a90 100644 (file)
@@ -296,6 +296,8 @@ static int hspi_probe(struct platform_device *pdev)
                goto error1;
        }
 
+       pm_runtime_enable(&pdev->dev);
+
        master->num_chipselect  = 1;
        master->bus_num         = pdev->id;
        master->setup           = hspi_setup;
@@ -309,8 +311,6 @@ static int hspi_probe(struct platform_device *pdev)
                goto error1;
        }
 
-       pm_runtime_enable(&pdev->dev);
-
        return 0;
 
  error1:
index f91bc1f..639ba96 100644 (file)
@@ -1960,6 +1960,7 @@ cntrlEnd:
 
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n");
 
+               memset(&DevInfo, 0, sizeof(DevInfo));
                DevInfo.MaxRDMBufferSize = BUFFER_4K;
                DevInfo.u32DSDStartOffset = EEPROM_CALPARAM_START;
                DevInfo.u32RxAlignmentCorrection = 0;
index 3ba4c57..853f62b 100644 (file)
@@ -369,28 +369,23 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
 {
        const struct ni_65xx_board *board = comedi_board(dev);
        struct ni_65xx_private *devpriv = dev->private;
-       unsigned base_bitfield_channel;
-       const unsigned max_ports_per_bitfield = 5;
+       int base_bitfield_channel;
        unsigned read_bits = 0;
-       unsigned j;
+       int last_port_offset = ni_65xx_port_by_channel(s->n_chan - 1);
+       int port_offset;
 
        base_bitfield_channel = CR_CHAN(insn->chanspec);
-       for (j = 0; j < max_ports_per_bitfield; ++j) {
-               const unsigned port_offset =
-                       ni_65xx_port_by_channel(base_bitfield_channel) + j;
-               const unsigned port =
-                       sprivate(s)->base_port + port_offset;
-               unsigned base_port_channel;
+       for (port_offset = ni_65xx_port_by_channel(base_bitfield_channel);
+            port_offset <= last_port_offset; port_offset++) {
+               unsigned port = sprivate(s)->base_port + port_offset;
+               int base_port_channel = port_offset * ni_65xx_channels_per_port;
                unsigned port_mask, port_data, port_read_bits;
-               int bitshift;
-               if (port >= ni_65xx_total_num_ports(board))
+               int bitshift = base_port_channel - base_bitfield_channel;
+
+               if (bitshift >= 32)
                        break;
-               base_port_channel = port_offset * ni_65xx_channels_per_port;
                port_mask = data[0];
                port_data = data[1];
-               bitshift = base_port_channel - base_bitfield_channel;
-               if (bitshift >= 32 || bitshift <= -32)
-                       break;
                if (bitshift > 0) {
                        port_mask >>= bitshift;
                        port_data >>= bitshift;
index b94a95a..76d5bbd 100644 (file)
@@ -1,3 +1,4 @@
 config USB_MSI3101
        tristate "Mirics MSi3101 SDR Dongle"
        depends on USB && VIDEO_DEV && VIDEO_V4L2
+        select VIDEOBUF2_VMALLOC
index 24c7b70..4c3bf77 100644 (file)
@@ -1131,7 +1131,13 @@ static int msi3101_queue_setup(struct vb2_queue *vq,
        /* Absolute min and max number of buffers available for mmap() */
        *nbuffers = 32;
        *nplanes = 1;
-       sizes[0] = PAGE_ALIGN(3 * 3072); /* 3 * 768 * 4 */
+       /*
+        *   3, wMaxPacketSize 3x 1024 bytes
+        * 504, max IQ sample pairs per 1024 frame
+        *   2, two samples, I and Q
+        *   4, 32-bit float
+        */
+       sizes[0] = PAGE_ALIGN(3 * 504 * 2 * 4); /* = 12096 */
        dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
                        __func__, *nbuffers, sizes[0]);
        return 0;
@@ -1657,7 +1663,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
                        f->frequency * 625UL / 10UL);
 }
 
-const struct v4l2_ioctl_ops msi3101_ioctl_ops = {
+static const struct v4l2_ioctl_ops msi3101_ioctl_ops = {
        .vidioc_querycap          = msi3101_querycap,
 
        .vidioc_enum_input        = msi3101_enum_input,
index 6ccb64f..6ce0af9 100644 (file)
@@ -155,6 +155,9 @@ static ssize_t oz_cdev_write(struct file *filp, const char __user *buf,
        struct oz_app_hdr *app_hdr;
        struct oz_serial_ctx *ctx;
 
+       if (count > sizeof(ei->data) - sizeof(*elt) - sizeof(*app_hdr))
+               return -EINVAL;
+
        spin_lock_bh(&g_cdev.lock);
        pd = g_cdev.active_pd;
        if (pd)
index 23db32f..a10cdb1 100644 (file)
@@ -1063,7 +1063,7 @@ static int mp_wait_modem_status(struct sb_uart_state *state, unsigned long arg)
 
 static int mp_get_count(struct sb_uart_state *state, struct serial_icounter_struct *icnt)
 {
-       struct serial_icounter_struct icount;
+       struct serial_icounter_struct icount = {};
        struct sb_uart_icount cnow;
        struct sb_uart_port *port = state->port;
 
index c97e0e1..7e10dcd 100644 (file)
@@ -570,6 +570,7 @@ int wvlan_uil_put_info(struct uilreq *urq, struct wl_private *lp)
        ltv_t                   *pLtv;
        bool_t                  ltvAllocated = FALSE;
        ENCSTRCT                sEncryption;
+       size_t                  len;
 
 #ifdef USE_WDS
        hcf_16                  hcfPort  = HCF_PORT_0;
@@ -686,7 +687,8 @@ int wvlan_uil_put_info(struct uilreq *urq, struct wl_private *lp)
                                        break;
                                case CFG_CNF_OWN_NAME:
                                        memset(lp->StationName, 0, sizeof(lp->StationName));
-                                       memcpy((void *)lp->StationName, (void *)&pLtv->u.u8[2], (size_t)pLtv->u.u16[0]);
+                                       len = min_t(size_t, pLtv->u.u16[0], sizeof(lp->StationName));
+                                       strlcpy(lp->StationName, &pLtv->u.u8[2], len);
                                        pLtv->u.u16[0] = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
                                        break;
                                case CFG_CNF_LOAD_BALANCING:
@@ -1783,6 +1785,7 @@ int wvlan_set_station_nickname(struct net_device *dev,
 {
        struct wl_private *lp = wl_priv(dev);
        unsigned long flags;
+       size_t len;
        int         ret = 0;
        /*------------------------------------------------------------------------*/
 
@@ -1793,8 +1796,8 @@ int wvlan_set_station_nickname(struct net_device *dev,
        wl_lock(lp, &flags);
 
        memset(lp->StationName, 0, sizeof(lp->StationName));
-
-       memcpy(lp->StationName, extra, wrqu->data.length);
+       len = min_t(size_t, wrqu->data.length, sizeof(lp->StationName));
+       strlcpy(lp->StationName, extra, len);
 
        /* Commit the adapter parameters */
        wl_apply(lp);
index 35b61f7..38e44b9 100644 (file)
@@ -753,7 +753,8 @@ static void iscsit_unmap_iovec(struct iscsi_cmd *cmd)
 
 static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
 {
-       struct iscsi_cmd *cmd;
+       LIST_HEAD(ack_list);
+       struct iscsi_cmd *cmd, *cmd_p;
 
        conn->exp_statsn = exp_statsn;
 
@@ -761,19 +762,23 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
                return;
 
        spin_lock_bh(&conn->cmd_lock);
-       list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
+       list_for_each_entry_safe(cmd, cmd_p, &conn->conn_cmd_list, i_conn_node) {
                spin_lock(&cmd->istate_lock);
                if ((cmd->i_state == ISTATE_SENT_STATUS) &&
                    iscsi_sna_lt(cmd->stat_sn, exp_statsn)) {
                        cmd->i_state = ISTATE_REMOVE;
                        spin_unlock(&cmd->istate_lock);
-                       iscsit_add_cmd_to_immediate_queue(cmd, conn,
-                                               cmd->i_state);
+                       list_move_tail(&cmd->i_conn_node, &ack_list);
                        continue;
                }
                spin_unlock(&cmd->istate_lock);
        }
        spin_unlock_bh(&conn->cmd_lock);
+
+       list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) {
+               list_del(&cmd->i_conn_node);
+               iscsit_free_cmd(cmd, false);
+       }
 }
 
 static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
index 14d1aed..ef6d836 100644 (file)
@@ -1192,7 +1192,7 @@ get_target:
         */
 alloc_tags:
        tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth);
-       tag_num += ISCSIT_EXTRA_TAGS;
+       tag_num += (tag_num / 2) + ISCSIT_EXTRA_TAGS;
        tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
 
        ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size);
index f2de28e..b0cac0c 100644 (file)
@@ -736,7 +736,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
                 * Fallthrough
                 */
        case ISCSI_OP_SCSI_TMFUNC:
-               rc = transport_generic_free_cmd(&cmd->se_cmd, 1);
+               rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
                if (!rc && shutdown && se_cmd && se_cmd->se_sess) {
                        __iscsit_free_cmd(cmd, true, shutdown);
                        target_put_sess_cmd(se_cmd->se_sess, se_cmd);
@@ -752,7 +752,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
                        se_cmd = &cmd->se_cmd;
                        __iscsit_free_cmd(cmd, true, shutdown);
 
-                       rc = transport_generic_free_cmd(&cmd->se_cmd, 1);
+                       rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
                        if (!rc && shutdown && se_cmd->se_sess) {
                                __iscsit_free_cmd(cmd, true, shutdown);
                                target_put_sess_cmd(se_cmd->se_sess, se_cmd);
index 551c96c..0f199f6 100644 (file)
@@ -134,10 +134,10 @@ static int pscsi_pmode_enable_hba(struct se_hba *hba, unsigned long mode_flag)
         * pSCSI Host ID and enable for phba mode
         */
        sh = scsi_host_lookup(phv->phv_host_id);
-       if (IS_ERR(sh)) {
+       if (!sh) {
                pr_err("pSCSI: Unable to locate SCSI Host for"
                        " phv_host_id: %d\n", phv->phv_host_id);
-               return PTR_ERR(sh);
+               return -EINVAL;
        }
 
        phv->phv_lld_host = sh;
@@ -515,10 +515,10 @@ static int pscsi_configure_device(struct se_device *dev)
                        sh = phv->phv_lld_host;
                } else {
                        sh = scsi_host_lookup(pdv->pdv_host_id);
-                       if (IS_ERR(sh)) {
+                       if (!sh) {
                                pr_err("pSCSI: Unable to locate"
                                        " pdv_host_id: %d\n", pdv->pdv_host_id);
-                               return PTR_ERR(sh);
+                               return -EINVAL;
                        }
                }
        } else {
index 6c17295..d9b92b2 100644 (file)
@@ -263,6 +263,11 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o
                        sectors, cmd->se_dev->dev_attrib.max_write_same_len);
                return TCM_INVALID_CDB_FIELD;
        }
+       /* We always have ANC_SUP == 0 so setting ANCHOR is always an error */
+       if (flags[0] & 0x10) {
+               pr_warn("WRITE SAME with ANCHOR not supported\n");
+               return TCM_INVALID_CDB_FIELD;
+       }
        /*
         * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting
         * translated into block discard requests within backend code.
@@ -349,7 +354,16 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
 
-       cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
+       /*
+        * Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through
+        * within target_complete_ok_work() if the command was successfully
+        * sent to the backend driver.
+        */
+       spin_lock_irq(&cmd->t_state_lock);
+       if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status)
+               cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
+       spin_unlock_irq(&cmd->t_state_lock);
+
        /*
         * Unlock ->caw_sem originally obtained during sbc_compare_and_write()
         * before the original READ I/O submission.
@@ -363,7 +377,7 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        struct scatterlist *write_sg = NULL, *sg;
-       unsigned char *buf, *addr;
+       unsigned char *buf = NULL, *addr;
        struct sg_mapping_iter m;
        unsigned int offset = 0, len;
        unsigned int nlbas = cmd->t_task_nolb;
@@ -378,6 +392,15 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
         */
        if (!cmd->t_data_sg || !cmd->t_bidi_data_sg)
                return TCM_NO_SENSE;
+       /*
+        * Immediately exit + release dev->caw_sem if command has already
+        * been failed with a non-zero SCSI status.
+        */
+       if (cmd->scsi_status) {
+               pr_err("compare_and_write_callback: non zero scsi_status:"
+                       " 0x%02x\n", cmd->scsi_status);
+               goto out;
+       }
 
        buf = kzalloc(cmd->data_length, GFP_KERNEL);
        if (!buf) {
@@ -508,6 +531,12 @@ sbc_compare_and_write(struct se_cmd *cmd)
                cmd->transport_complete_callback = NULL;
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
+       /*
+        * Reset cmd->data_length to individual block_size in order to not
+        * confuse backend drivers that depend on this value matching the
+        * size of the I/O being submitted.
+        */
+       cmd->data_length = cmd->t_task_nolb * dev->dev_attrib.block_size;
 
        ret = cmd->execute_rw(cmd, cmd->t_bidi_data_sg, cmd->t_bidi_data_nents,
                              DMA_FROM_DEVICE);
index 84747cc..81e945e 100644 (file)
@@ -236,17 +236,24 @@ int transport_alloc_session_tags(struct se_session *se_sess,
 {
        int rc;
 
-       se_sess->sess_cmd_map = kzalloc(tag_num * tag_size, GFP_KERNEL);
+       se_sess->sess_cmd_map = kzalloc(tag_num * tag_size,
+                                       GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
        if (!se_sess->sess_cmd_map) {
-               pr_err("Unable to allocate se_sess->sess_cmd_map\n");
-               return -ENOMEM;
+               se_sess->sess_cmd_map = vzalloc(tag_num * tag_size);
+               if (!se_sess->sess_cmd_map) {
+                       pr_err("Unable to allocate se_sess->sess_cmd_map\n");
+                       return -ENOMEM;
+               }
        }
 
        rc = percpu_ida_init(&se_sess->sess_tag_pool, tag_num);
        if (rc < 0) {
                pr_err("Unable to init se_sess->sess_tag_pool,"
                        " tag_num: %u\n", tag_num);
-               kfree(se_sess->sess_cmd_map);
+               if (is_vmalloc_addr(se_sess->sess_cmd_map))
+                       vfree(se_sess->sess_cmd_map);
+               else
+                       kfree(se_sess->sess_cmd_map);
                se_sess->sess_cmd_map = NULL;
                return -ENOMEM;
        }
@@ -412,7 +419,10 @@ void transport_free_session(struct se_session *se_sess)
 {
        if (se_sess->sess_cmd_map) {
                percpu_ida_destroy(&se_sess->sess_tag_pool);
-               kfree(se_sess->sess_cmd_map);
+               if (is_vmalloc_addr(se_sess->sess_cmd_map))
+                       vfree(se_sess->sess_cmd_map);
+               else
+                       kfree(se_sess->sess_cmd_map);
        }
        kmem_cache_free(se_sess_cache, se_sess);
 }
index 4d22e7d..474cd44 100644 (file)
@@ -82,6 +82,9 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
        mutex_lock(&g_device_mutex);
        list_for_each_entry(se_dev, &g_device_list, g_dev_node) {
 
+               if (!se_dev->dev_attrib.emulate_3pc)
+                       continue;
+
                memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
                target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
 
@@ -298,8 +301,8 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
                (unsigned long long)xop->dst_lba);
 
        if (dc != 0) {
-               xop->dbl = (desc[29] << 16) & 0xff;
-               xop->dbl |= (desc[30] << 8) & 0xff;
+               xop->dbl = (desc[29] & 0xff) << 16;
+               xop->dbl |= (desc[30] & 0xff) << 8;
                xop->dbl |= desc[31] & 0xff;
 
                pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl);
@@ -357,6 +360,7 @@ struct xcopy_pt_cmd {
        struct se_cmd se_cmd;
        struct xcopy_op *xcopy_op;
        struct completion xpt_passthrough_sem;
+       unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
 };
 
 static struct se_port xcopy_pt_port;
@@ -675,7 +679,8 @@ static int target_xcopy_issue_pt_cmd(struct xcopy_pt_cmd *xpt_cmd)
 
        pr_debug("target_xcopy_issue_pt_cmd(): SCSI status: 0x%02x\n",
                        se_cmd->scsi_status);
-       return 0;
+
+       return (se_cmd->scsi_status) ? -EINVAL : 0;
 }
 
 static int target_xcopy_read_source(
@@ -708,7 +713,7 @@ static int target_xcopy_read_source(
                (unsigned long long)src_lba, src_sectors, length);
 
        transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, NULL, length,
-                               DMA_FROM_DEVICE, 0, NULL);
+                             DMA_FROM_DEVICE, 0, &xpt_cmd->sense_buffer[0]);
        xop->src_pt_cmd = xpt_cmd;
 
        rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0],
@@ -768,7 +773,7 @@ static int target_xcopy_write_destination(
                (unsigned long long)dst_lba, dst_sectors, length);
 
        transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, NULL, length,
-                               DMA_TO_DEVICE, 0, NULL);
+                             DMA_TO_DEVICE, 0, &xpt_cmd->sense_buffer[0]);
        xop->dst_pt_cmd = xpt_cmd;
 
        rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, dst_dev, &cdb[0],
@@ -884,30 +889,42 @@ out:
 
 sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
 {
+       struct se_device *dev = se_cmd->se_dev;
        struct xcopy_op *xop = NULL;
        unsigned char *p = NULL, *seg_desc;
        unsigned int list_id, list_id_usage, sdll, inline_dl, sa;
+       sense_reason_t ret = TCM_INVALID_PARAMETER_LIST;
        int rc;
        unsigned short tdll;
 
+       if (!dev->dev_attrib.emulate_3pc) {
+               pr_err("EXTENDED_COPY operation explicitly disabled\n");
+               return TCM_UNSUPPORTED_SCSI_OPCODE;
+       }
+
        sa = se_cmd->t_task_cdb[1] & 0x1f;
        if (sa != 0x00) {
                pr_err("EXTENDED_COPY(LID4) not supported\n");
                return TCM_UNSUPPORTED_SCSI_OPCODE;
        }
 
+       xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
+       if (!xop) {
+               pr_err("Unable to allocate xcopy_op\n");
+               return TCM_OUT_OF_RESOURCES;
+       }
+       xop->xop_se_cmd = se_cmd;
+
        p = transport_kmap_data_sg(se_cmd);
        if (!p) {
                pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n");
+               kfree(xop);
                return TCM_OUT_OF_RESOURCES;
        }
 
        list_id = p[0];
-       if (list_id != 0x00) {
-               pr_err("XCOPY with non zero list_id: 0x%02x\n", list_id);
-               goto out;
-       }
-       list_id_usage = (p[1] & 0x18);
+       list_id_usage = (p[1] & 0x18) >> 3;
+
        /*
         * Determine TARGET DESCRIPTOR LIST LENGTH + SEGMENT DESCRIPTOR LIST LENGTH
         */
@@ -920,13 +937,6 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
                goto out;
        }
 
-       xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
-       if (!xop) {
-               pr_err("Unable to allocate xcopy_op\n");
-               goto out;
-       }
-       xop->xop_se_cmd = se_cmd;
-
        pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x"
                " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
                tdll, sdll, inline_dl);
@@ -935,6 +945,17 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
        if (rc <= 0)
                goto out;
 
+       if (xop->src_dev->dev_attrib.block_size !=
+           xop->dst_dev->dev_attrib.block_size) {
+               pr_err("XCOPY: Non matching src_dev block_size: %u + dst_dev"
+                      " block_size: %u currently unsupported\n",
+                       xop->src_dev->dev_attrib.block_size,
+                       xop->dst_dev->dev_attrib.block_size);
+               xcopy_pt_undepend_remotedev(xop);
+               ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+               goto out;
+       }
+
        pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
                                rc * XCOPY_TARGET_DESC_LEN);
        seg_desc = &p[16];
@@ -957,7 +978,7 @@ out:
        if (p)
                transport_kunmap_data_sg(se_cmd);
        kfree(xop);
-       return TCM_INVALID_CDB_FIELD;
+       return ret;
 }
 
 static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd)
index f10a6ad..c2301da 100644 (file)
@@ -310,8 +310,6 @@ void exynos_report_trigger(struct thermal_sensor_conf *conf)
        }
 
        th_zone = conf->pzone_data;
-       if (th_zone->therm_dev)
-               return;
 
        if (th_zone->bind == false) {
                for (i = 0; i < th_zone->cool_dev_size; i++) {
index b43afda..32f38b9 100644 (file)
@@ -317,6 +317,9 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
 
        con = readl(data->base + reg->tmu_ctrl);
 
+       if (pdata->test_mux)
+               con |= (pdata->test_mux << reg->test_mux_addr_shift);
+
        if (pdata->reference_voltage) {
                con &= ~(reg->buf_vref_sel_mask << reg->buf_vref_sel_shift);
                con |= pdata->reference_voltage << reg->buf_vref_sel_shift;
@@ -488,7 +491,7 @@ static const struct of_device_id exynos_tmu_match[] = {
        },
        {
                .compatible = "samsung,exynos4412-tmu",
-               .data = (void *)EXYNOS5250_TMU_DRV_DATA,
+               .data = (void *)EXYNOS4412_TMU_DRV_DATA,
        },
        {
                .compatible = "samsung,exynos5250-tmu",
@@ -629,9 +632,10 @@ static int exynos_tmu_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       if (pdata->type == SOC_ARCH_EXYNOS ||
-               pdata->type == SOC_ARCH_EXYNOS4210 ||
-                               pdata->type == SOC_ARCH_EXYNOS5440)
+       if (pdata->type == SOC_ARCH_EXYNOS4210 ||
+           pdata->type == SOC_ARCH_EXYNOS4412 ||
+           pdata->type == SOC_ARCH_EXYNOS5250 ||
+           pdata->type == SOC_ARCH_EXYNOS5440)
                data->soc = pdata->type;
        else {
                ret = -EINVAL;
index b364c9e..3fb6554 100644 (file)
@@ -41,7 +41,8 @@ enum calibration_mode {
 
 enum soc_type {
        SOC_ARCH_EXYNOS4210 = 1,
-       SOC_ARCH_EXYNOS,
+       SOC_ARCH_EXYNOS4412,
+       SOC_ARCH_EXYNOS5250,
        SOC_ARCH_EXYNOS5440,
 };
 
@@ -84,6 +85,7 @@ enum soc_type {
  * @triminfo_reload_shift: shift of triminfo reload enable bit in triminfo_ctrl
        reg.
  * @tmu_ctrl: TMU main controller register.
+ * @test_mux_addr_shift: shift bits of test mux address.
  * @buf_vref_sel_shift: shift bits of reference voltage in tmu_ctrl register.
  * @buf_vref_sel_mask: mask bits of reference voltage in tmu_ctrl register.
  * @therm_trip_mode_shift: shift bits of tripping mode in tmu_ctrl register.
@@ -150,6 +152,7 @@ struct exynos_tmu_registers {
        u32     triminfo_reload_shift;
 
        u32     tmu_ctrl;
+       u32     test_mux_addr_shift;
        u32     buf_vref_sel_shift;
        u32     buf_vref_sel_mask;
        u32     therm_trip_mode_shift;
@@ -257,6 +260,7 @@ struct exynos_tmu_registers {
  * @first_point_trim: temp value of the first point trimming
  * @second_point_trim: temp value of the second point trimming
  * @default_temp_offset: default temperature offset in case of no trimming
+ * @test_mux; information if SoC supports test MUX
  * @cal_type: calibration type for temperature
  * @cal_mode: calibration mode for temperature
  * @freq_clip_table: Table representing frequency reduction percentage.
@@ -286,6 +290,7 @@ struct exynos_tmu_platform_data {
        u8 first_point_trim;
        u8 second_point_trim;
        u8 default_temp_offset;
+       u8 test_mux;
 
        enum calibration_type cal_type;
        enum calibration_mode cal_mode;
index 9002499..073c292 100644 (file)
@@ -90,14 +90,15 @@ struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
 };
 #endif
 
-#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
-static const struct exynos_tmu_registers exynos5250_tmu_registers = {
+#if defined(CONFIG_SOC_EXYNOS4412) || defined(CONFIG_SOC_EXYNOS5250)
+static const struct exynos_tmu_registers exynos4412_tmu_registers = {
        .triminfo_data = EXYNOS_TMU_REG_TRIMINFO,
        .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
        .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
        .triminfo_ctrl = EXYNOS_TMU_TRIMINFO_CON,
        .triminfo_reload_shift = EXYNOS_TRIMINFO_RELOAD_SHIFT,
        .tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
+       .test_mux_addr_shift = EXYNOS4412_MUX_ADDR_SHIFT,
        .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
        .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
        .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
@@ -128,7 +129,7 @@ static const struct exynos_tmu_registers exynos5250_tmu_registers = {
        .emul_time_mask = EXYNOS_EMUL_TIME_MASK,
 };
 
-#define EXYNOS5250_TMU_DATA \
+#define EXYNOS4412_TMU_DATA \
        .threshold_falling = 10, \
        .trigger_levels[0] = 85, \
        .trigger_levels[1] = 103, \
@@ -162,15 +163,32 @@ static const struct exynos_tmu_registers exynos5250_tmu_registers = {
                .temp_level = 103, \
        }, \
        .freq_tab_count = 2, \
-       .type = SOC_ARCH_EXYNOS, \
-       .registers = &exynos5250_tmu_registers, \
+       .registers = &exynos4412_tmu_registers, \
        .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_TRIM_RELOAD | \
                        TMU_SUPPORT_FALLING_TRIP | TMU_SUPPORT_READY_STATUS | \
                        TMU_SUPPORT_EMUL_TIME)
+#endif
 
+#if defined(CONFIG_SOC_EXYNOS4412)
+struct exynos_tmu_init_data const exynos4412_default_tmu_data = {
+       .tmu_data = {
+               {
+                       EXYNOS4412_TMU_DATA,
+                       .type = SOC_ARCH_EXYNOS4412,
+                       .test_mux = EXYNOS4412_MUX_ADDR_VALUE,
+               },
+       },
+       .tmu_count = 1,
+};
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5250)
 struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
        .tmu_data = {
-               { EXYNOS5250_TMU_DATA },
+               {
+                       EXYNOS4412_TMU_DATA,
+                       .type = SOC_ARCH_EXYNOS5250,
+               },
        },
        .tmu_count = 1,
 };
index dc7feb5..a1ea19d 100644 (file)
 
 #define EXYNOS_MAX_TRIGGER_PER_REG     4
 
+/* Exynos4412 specific */
+#define EXYNOS4412_MUX_ADDR_VALUE          6
+#define EXYNOS4412_MUX_ADDR_SHIFT          20
+
 /*exynos5440 specific registers*/
 #define EXYNOS5440_TMU_S0_7_TRIM               0x000
 #define EXYNOS5440_TMU_S0_7_CTRL               0x020
@@ -138,7 +142,14 @@ extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
 #define EXYNOS4210_TMU_DRV_DATA (NULL)
 #endif
 
-#if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
+#if defined(CONFIG_SOC_EXYNOS4412)
+extern struct exynos_tmu_init_data const exynos4412_default_tmu_data;
+#define EXYNOS4412_TMU_DRV_DATA (&exynos4412_default_tmu_data)
+#else
+#define EXYNOS4412_TMU_DRV_DATA (NULL)
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5250)
 extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
 #define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
 #else
index eeef0e2..fdb0719 100644 (file)
@@ -159,7 +159,7 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
 
        INIT_LIST_HEAD(&hwmon->tz_list);
        strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
-       hwmon->device = hwmon_device_register(&tz->device);
+       hwmon->device = hwmon_device_register(NULL);
        if (IS_ERR(hwmon->device)) {
                result = PTR_ERR(hwmon->device);
                goto free_mem;
index 4f8b9af..5a47cc8 100644 (file)
@@ -110,6 +110,7 @@ static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
                } else {
                        dev_err(bgp->dev,
                                "Failed to read PCB state. Using defaults\n");
+                       ret = 0;
                }
        }
        *temp = ti_thermal_hotspot_temperature(tmp, slope, constant);
index f36950e..7722cb9 100644 (file)
@@ -316,18 +316,19 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
        int phy_id = topology_physical_package_id(cpu);
        struct phy_dev_entry *phdev = pkg_temp_thermal_get_phy_entry(cpu);
        bool notify = false;
+       unsigned long flags;
 
        if (!phdev)
                return;
 
-       spin_lock(&pkg_work_lock);
+       spin_lock_irqsave(&pkg_work_lock, flags);
        ++pkg_work_cnt;
        if (unlikely(phy_id > max_phy_id)) {
-               spin_unlock(&pkg_work_lock);
+               spin_unlock_irqrestore(&pkg_work_lock, flags);
                return;
        }
        pkg_work_scheduled[phy_id] = 0;
-       spin_unlock(&pkg_work_lock);
+       spin_unlock_irqrestore(&pkg_work_lock, flags);
 
        enable_pkg_thres_interrupt();
        rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
@@ -397,6 +398,7 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
        int thres_count;
        u32 eax, ebx, ecx, edx;
        u8 *temp;
+       unsigned long flags;
 
        cpuid(6, &eax, &ebx, &ecx, &edx);
        thres_count = ebx & 0x07;
@@ -420,19 +422,19 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
                goto err_ret_unlock;
        }
 
-       spin_lock(&pkg_work_lock);
+       spin_lock_irqsave(&pkg_work_lock, flags);
        if (topology_physical_package_id(cpu) > max_phy_id)
                max_phy_id = topology_physical_package_id(cpu);
        temp = krealloc(pkg_work_scheduled,
                        (max_phy_id+1) * sizeof(u8), GFP_ATOMIC);
        if (!temp) {
-               spin_unlock(&pkg_work_lock);
+               spin_unlock_irqrestore(&pkg_work_lock, flags);
                err = -ENOMEM;
                goto err_ret_free;
        }
        pkg_work_scheduled = temp;
        pkg_work_scheduled[topology_physical_package_id(cpu)] = 0;
-       spin_unlock(&pkg_work_lock);
+       spin_unlock_irqrestore(&pkg_work_lock, flags);
 
        phy_dev_entry->phys_proc_id = topology_physical_package_id(cpu);
        phy_dev_entry->first_cpu = cpu;
index e61c36c..c193af6 100644 (file)
@@ -636,6 +636,7 @@ struct console xenboot_console = {
        .name           = "xenboot",
        .write          = xenboot_write_console,
        .flags          = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
+       .index          = -1,
 };
 #endif /* CONFIG_EARLY_PRINTK */
 
index 01bf5eb..7a744b6 100644 (file)
@@ -2183,28 +2183,34 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
 
                if (!input_available_p(tty, 0)) {
                        if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-                               retval = -EIO;
-                               break;
-                       }
-                       if (tty_hung_up_p(file))
-                               break;
-                       if (!timeout)
-                               break;
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               retval = -ERESTARTSYS;
-                               break;
-                       }
-                       n_tty_set_room(tty);
-                       up_read(&tty->termios_rwsem);
+                               up_read(&tty->termios_rwsem);
+                               tty_flush_to_ldisc(tty);
+                               down_read(&tty->termios_rwsem);
+                               if (!input_available_p(tty, 0)) {
+                                       retval = -EIO;
+                                       break;
+                               }
+                       } else {
+                               if (tty_hung_up_p(file))
+                                       break;
+                               if (!timeout)
+                                       break;
+                               if (file->f_flags & O_NONBLOCK) {
+                                       retval = -EAGAIN;
+                                       break;
+                               }
+                               if (signal_pending(current)) {
+                                       retval = -ERESTARTSYS;
+                                       break;
+                               }
+                               n_tty_set_room(tty);
+                               up_read(&tty->termios_rwsem);
 
-                       timeout = schedule_timeout(timeout);
+                               timeout = schedule_timeout(timeout);
 
-                       down_read(&tty->termios_rwsem);
-                       continue;
+                               down_read(&tty->termios_rwsem);
+                               continue;
+                       }
                }
                __set_current_state(TASK_RUNNING);
 
index d067285..6b0f75e 100644 (file)
@@ -1499,7 +1499,7 @@ static void atmel_set_ops(struct uart_port *port)
 /*
  * Get ip name usart or uart
  */
-static int atmel_get_ip_name(struct uart_port *port)
+static void atmel_get_ip_name(struct uart_port *port)
 {
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
        int name = UART_GET_IP_NAME(port);
@@ -1518,10 +1518,7 @@ static int atmel_get_ip_name(struct uart_port *port)
                atmel_port->is_usart = false;
        } else {
                dev_err(port->dev, "Not supported ip name, set to uart\n");
-               return -EINVAL;
        }
-
-       return 0;
 }
 
 /*
@@ -2405,9 +2402,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
        /*
         * Get port name of usart or uart
         */
-       ret = atmel_get_ip_name(&port->uart);
-       if (ret < 0)
-               goto err_add_port;
+       atmel_get_ip_name(&port->uart);
 
        return 0;
 
index a0ebbc9..042aa07 100644 (file)
@@ -1912,9 +1912,6 @@ static int serial_imx_probe_dt(struct imx_port *sport,
 
        sport->devdata = of_id->data;
 
-       if (of_device_is_stdout_path(np))
-               add_preferred_console(imx_reg.cons->name, sport->port.line, 0);
-
        return 0;
 }
 #else
index 93b697a..15ad6fc 100644 (file)
@@ -561,12 +561,13 @@ static int vt8500_serial_probe(struct platform_device *pdev)
        if (!mmres || !irqres)
                return -ENODEV;
 
-       if (np)
+       if (np) {
                port = of_alias_get_id(np, "serial");
                if (port >= VT8500_MAX_PORTS)
                        port = -1;
-       else
+       } else {
                port = -1;
+       }
 
        if (port < 0) {
                /* calculate the port id */
index ba47563..0e808cf 100644 (file)
@@ -642,16 +642,29 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
 {
        struct uio_device *idev = vma->vm_private_data;
        int mi = uio_find_mem_index(vma);
+       struct uio_mem *mem;
        if (mi < 0)
                return -EINVAL;
+       mem = idev->info->mem + mi;
 
-       vma->vm_ops = &uio_physical_vm_ops;
+       if (vma->vm_end - vma->vm_start > mem->size)
+               return -EINVAL;
 
+       vma->vm_ops = &uio_physical_vm_ops;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
+       /*
+        * We cannot use the vm_iomap_memory() helper here,
+        * because vma->vm_pgoff is the map index we looked
+        * up above in uio_find_mem_index(), rather than an
+        * actual page offset into the mmap.
+        *
+        * So we just do the physical mmap without a page
+        * offset.
+        */
        return remap_pfn_range(vma,
                               vma->vm_start,
-                              idev->info->mem[mi].addr >> PAGE_SHIFT,
+                              mem->addr >> PAGE_SHIFT,
                               vma->vm_end - vma->vm_start,
                               vma->vm_page_prot);
 }
index 042320a..d514332 100644 (file)
@@ -129,7 +129,12 @@ static DEFINE_PCI_DEVICE_TABLE(ci_hdrc_pci_id_table) = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
                .driver_data = (kernel_ulong_t)&penwell_pci_platdata,
        },
-       { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
+       {
+               /* Intel Clovertrail */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006),
+               .driver_data = (kernel_ulong_t)&penwell_pci_platdata,
+       },
+       { 0 } /* end: all zeroes */
 };
 MODULE_DEVICE_TABLE(pci, ci_hdrc_pci_id_table);
 
index 6f96795..64d7a6d 100644 (file)
@@ -100,8 +100,10 @@ static void host_stop(struct ci_hdrc *ci)
 {
        struct usb_hcd *hcd = ci->hcd;
 
-       usb_remove_hcd(hcd);
-       usb_put_hcd(hcd);
+       if (hcd) {
+               usb_remove_hcd(hcd);
+               usb_put_hcd(hcd);
+       }
        if (ci->platdata->reg_vbus)
                regulator_disable(ci->platdata->reg_vbus);
 }
index 5b44cd4..01fe362 100644 (file)
@@ -97,6 +97,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Alcor Micro Corp. Hub */
        { USB_DEVICE(0x058f, 0x9254), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* MicroTouch Systems touchscreen */
+       { USB_DEVICE(0x0596, 0x051e), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* appletouch */
        { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
 
@@ -130,6 +133,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Broadcom BCM92035DGROM BT dongle */
        { USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* MAYA44USB sound device */
+       { USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* Action Semiconductor flash disk */
        { USB_DEVICE(0x10d6, 0x2200), .driver_info =
                        USB_QUIRK_STRING_FETCH_255 },
index 0658908..44cf775 100644 (file)
@@ -2256,6 +2256,8 @@ static int ffs_func_bind(struct usb_configuration *c,
                                   data->raw_descs + ret,
                                   (sizeof data->raw_descs) - ret,
                                   __ffs_func_bind_do_descs, func);
+               if (unlikely(ret < 0))
+                       goto error;
        }
 
        /*
index cc92074..0ac6064 100644 (file)
@@ -2054,7 +2054,7 @@ static struct pxa25x_udc memory = {
 /*
  *     probe - binds to the platform device
  */
-static int __init pxa25x_udc_probe(struct platform_device *pdev)
+static int pxa25x_udc_probe(struct platform_device *pdev)
 {
        struct pxa25x_udc *dev = &memory;
        int retval, irq;
@@ -2203,7 +2203,7 @@ static void pxa25x_udc_shutdown(struct platform_device *_dev)
        pullup_off();
 }
 
-static int __exit pxa25x_udc_remove(struct platform_device *pdev)
+static int pxa25x_udc_remove(struct platform_device *pdev)
 {
        struct pxa25x_udc *dev = platform_get_drvdata(pdev);
 
@@ -2294,7 +2294,8 @@ static int pxa25x_udc_resume(struct platform_device *dev)
 
 static struct platform_driver udc_driver = {
        .shutdown       = pxa25x_udc_shutdown,
-       .remove         = __exit_p(pxa25x_udc_remove),
+       .probe          = pxa25x_udc_probe,
+       .remove         = pxa25x_udc_remove,
        .suspend        = pxa25x_udc_suspend,
        .resume         = pxa25x_udc_resume,
        .driver         = {
@@ -2303,7 +2304,7 @@ static struct platform_driver udc_driver = {
        },
 };
 
-module_platform_driver_probe(udc_driver, pxa25x_udc_probe);
+module_platform_driver(udc_driver);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell");
index 6bddf1a..a8a99e4 100644 (file)
@@ -543,7 +543,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
         * FIFO, requests of >512 cause the endpoint to get stuck with a
         * fragment of the end of the transfer in it.
         */
-       if (can_write > 512)
+       if (can_write > 512 && !periodic)
                can_write = 512;
 
        /*
index 2c76ef1..08ef282 100644 (file)
@@ -799,7 +799,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
         * switchable ports.
         */
        pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
-                       cpu_to_le32(ports_available));
+                       ports_available);
 
        pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
                        &ports_available);
@@ -821,7 +821,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
         * host.
         */
        pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
-                       cpu_to_le32(ports_available));
+                       ports_available);
 
        pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
                        &ports_available);
index 773a6b2..e8b4c56 100644 (file)
@@ -1157,18 +1157,6 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                t1 = xhci_port_state_to_neutral(t1);
                if (t1 != t2)
                        xhci_writel(xhci, t2, port_array[port_index]);
-
-               if (hcd->speed != HCD_USB3) {
-                       /* enable remote wake up for USB 2.0 */
-                       __le32 __iomem *addr;
-                       u32 tmp;
-
-                       /* Get the port power control register address. */
-                       addr = port_array[port_index] + PORTPMSC;
-                       tmp = xhci_readl(xhci, addr);
-                       tmp |= PORT_RWE;
-                       xhci_writel(xhci, tmp, addr);
-               }
        }
        hcd->state = HC_STATE_SUSPENDED;
        bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
@@ -1247,20 +1235,6 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                                xhci_ring_device(xhci, slot_id);
                } else
                        xhci_writel(xhci, temp, port_array[port_index]);
-
-               if (hcd->speed != HCD_USB3) {
-                       /* disable remote wake up for USB 2.0 */
-                       __le32 __iomem *addr;
-                       u32 tmp;
-
-                       /* Add one to the port status register address to get
-                        * the port power control register address.
-                        */
-                       addr = port_array[port_index] + PORTPMSC;
-                       tmp = xhci_readl(xhci, addr);
-                       tmp &= ~PORT_RWE;
-                       xhci_writel(xhci, tmp, addr);
-               }
        }
 
        (void) xhci_readl(xhci, &xhci->op_regs->command);
index 236c3aa..b8dffd5 100644 (file)
@@ -35,6 +35,9 @@
 #define PCI_VENDOR_ID_ETRON            0x1b6f
 #define PCI_DEVICE_ID_ASROCK_P67       0x7023
 
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI     0x8c31
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI  0x9c31
+
 static const char hcd_name[] = "xhci_hcd";
 
 /* called after powerup, by probe or system-pm "wakeup" */
@@ -69,6 +72,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                                "QUIRK: Fresco Logic xHC needs configure"
                                " endpoint cmd after reset endpoint");
                }
+               if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
+                               pdev->revision == 0x4) {
+                       xhci->quirks |= XHCI_SLOW_SUSPEND;
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "QUIRK: Fresco Logic xHC revision %u"
+                               "must be suspended extra slowly",
+                               pdev->revision);
+               }
                /* Fresco Logic confirms: all revisions of this chip do not
                 * support MSI, even though some of them claim to in their PCI
                 * capabilities.
@@ -110,6 +121,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                xhci->quirks |= XHCI_SPURIOUS_REBOOT;
                xhci->quirks |= XHCI_AVOID_BEI;
        }
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+           (pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI ||
+            pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI)) {
+               /* Workaround for occasional spurious wakeups from S5 (or
+                * any other sleep) on Haswell machines with LPT and LPT-LP
+                * with the new Intel BIOS
+                */
+               xhci->quirks |= XHCI_SPURIOUS_WAKEUP;
+       }
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
                        pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
                xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -217,6 +237,11 @@ static void xhci_pci_remove(struct pci_dev *dev)
                usb_put_hcd(xhci->shared_hcd);
        }
        usb_hcd_pci_remove(dev);
+
+       /* Workaround for spurious wakeups at shutdown with HSW */
+       if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
+               pci_set_power_state(dev, PCI_D3hot);
+
        kfree(xhci);
 }
 
index 1e36dbb..6e0d886 100644 (file)
@@ -730,6 +730,9 @@ void xhci_shutdown(struct usb_hcd *hcd)
 
        spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
+       /* Workaround for spurious wakeups at shutdown with HSW */
+       if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
+               xhci_reset(xhci);
        spin_unlock_irq(&xhci->lock);
 
        xhci_cleanup_msix(xhci);
@@ -737,6 +740,10 @@ void xhci_shutdown(struct usb_hcd *hcd)
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "xhci_shutdown completed - status = %x",
                        xhci_readl(xhci, &xhci->op_regs->status));
+
+       /* Yet another workaround for spurious wakeups at shutdown with HSW */
+       if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
+               pci_set_power_state(to_pci_dev(hcd->self.controller), PCI_D3hot);
 }
 
 #ifdef CONFIG_PM
@@ -839,6 +846,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
 int xhci_suspend(struct xhci_hcd *xhci)
 {
        int                     rc = 0;
+       unsigned int            delay = XHCI_MAX_HALT_USEC;
        struct usb_hcd          *hcd = xhci_to_hcd(xhci);
        u32                     command;
 
@@ -861,8 +869,12 @@ int xhci_suspend(struct xhci_hcd *xhci)
        command = xhci_readl(xhci, &xhci->op_regs->command);
        command &= ~CMD_RUN;
        xhci_writel(xhci, command, &xhci->op_regs->command);
+
+       /* Some chips from Fresco Logic need an extraordinary delay */
+       delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1;
+
        if (xhci_handshake(xhci, &xhci->op_regs->status,
-                     STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) {
+                     STS_HALT, STS_HALT, delay)) {
                xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
                spin_unlock_irq(&xhci->lock);
                return -ETIMEDOUT;
index 289fbfb..941d5f5 100644 (file)
@@ -1548,6 +1548,8 @@ struct xhci_hcd {
 #define XHCI_COMP_MODE_QUIRK   (1 << 14)
 #define XHCI_AVOID_BEI         (1 << 15)
 #define XHCI_PLAT              (1 << 16)
+#define XHCI_SLOW_SUSPEND      (1 << 17)
+#define XHCI_SPURIOUS_WAKEUP   (1 << 18)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
index e2b21c1..ba5f70f 100644 (file)
@@ -246,6 +246,6 @@ config USB_EZUSB_FX2
 config USB_HSIC_USB3503
        tristate "USB3503 HSIC to USB20 Driver"
        depends on I2C
-       select REGMAP
+       select REGMAP_I2C
        help
          This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver.
index 18e877f..cd70cc8 100644 (file)
@@ -921,6 +921,52 @@ static void musb_generic_disable(struct musb *musb)
 
 }
 
+/*
+ * Program the HDRC to start (enable interrupts, dma, etc.).
+ */
+void musb_start(struct musb *musb)
+{
+       void __iomem    *regs = musb->mregs;
+       u8              devctl = musb_readb(regs, MUSB_DEVCTL);
+
+       dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
+
+       /*  Set INT enable registers, enable interrupts */
+       musb->intrtxe = musb->epmask;
+       musb_writew(regs, MUSB_INTRTXE, musb->intrtxe);
+       musb->intrrxe = musb->epmask & 0xfffe;
+       musb_writew(regs, MUSB_INTRRXE, musb->intrrxe);
+       musb_writeb(regs, MUSB_INTRUSBE, 0xf7);
+
+       musb_writeb(regs, MUSB_TESTMODE, 0);
+
+       /* put into basic highspeed mode and start session */
+       musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE
+                       | MUSB_POWER_HSENAB
+                       /* ENSUSPEND wedges tusb */
+                       /* | MUSB_POWER_ENSUSPEND */
+                  );
+
+       musb->is_active = 0;
+       devctl = musb_readb(regs, MUSB_DEVCTL);
+       devctl &= ~MUSB_DEVCTL_SESSION;
+
+       /* session started after:
+        * (a) ID-grounded irq, host mode;
+        * (b) vbus present/connect IRQ, peripheral mode;
+        * (c) peripheral initiates, using SRP
+        */
+       if (musb->port_mode != MUSB_PORT_MODE_HOST &&
+                       (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
+               musb->is_active = 1;
+       } else {
+               devctl |= MUSB_DEVCTL_SESSION;
+       }
+
+       musb_platform_enable(musb);
+       musb_writeb(regs, MUSB_DEVCTL, devctl);
+}
+
 /*
  * Make the HDRC stop (disable interrupts, etc.);
  * reversible by musb_start
index 65f3917..1c5bf75 100644 (file)
@@ -503,6 +503,7 @@ static inline void musb_configure_ep0(struct musb *musb)
 extern const char musb_driver_name[];
 
 extern void musb_stop(struct musb *musb);
+extern void musb_start(struct musb *musb);
 
 extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);
 extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst);
index 4047cbb..bd4138d 100644 (file)
@@ -535,6 +535,9 @@ static int dsps_probe(struct platform_device *pdev)
        struct dsps_glue *glue;
        int ret;
 
+       if (!strcmp(pdev->name, "musb-hdrc"))
+               return -ENODEV;
+
        match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
        if (!match) {
                dev_err(&pdev->dev, "fail to get matching of_match struct\n");
index 9a08679..3671898 100644 (file)
@@ -1790,6 +1790,10 @@ int musb_gadget_setup(struct musb *musb)
        musb->g.max_speed = USB_SPEED_HIGH;
        musb->g.speed = USB_SPEED_UNKNOWN;
 
+       MUSB_DEV_MODE(musb);
+       musb->xceiv->otg->default_a = 0;
+       musb->xceiv->state = OTG_STATE_B_IDLE;
+
        /* this "gadget" abstracts/virtualizes the controller */
        musb->g.name = musb_driver_name;
        musb->g.is_otg = 1;
@@ -1855,6 +1859,8 @@ static int musb_gadget_start(struct usb_gadget *g,
        musb->xceiv->state = OTG_STATE_B_IDLE;
        spin_unlock_irqrestore(&musb->lock, flags);
 
+       musb_start(musb);
+
        /* REVISIT:  funcall to other code, which also
         * handles power budgeting ... this way also
         * ensures HdrcStart is indirectly called.
index a523950..d1d6b83 100644 (file)
 
 #include "musb_core.h"
 
-/*
-* Program the HDRC to start (enable interrupts, dma, etc.).
-*/
-static void musb_start(struct musb *musb)
-{
-       void __iomem    *regs = musb->mregs;
-       u8              devctl = musb_readb(regs, MUSB_DEVCTL);
-
-       dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
-
-       /*  Set INT enable registers, enable interrupts */
-       musb->intrtxe = musb->epmask;
-       musb_writew(regs, MUSB_INTRTXE, musb->intrtxe);
-       musb->intrrxe = musb->epmask & 0xfffe;
-       musb_writew(regs, MUSB_INTRRXE, musb->intrrxe);
-       musb_writeb(regs, MUSB_INTRUSBE, 0xf7);
-
-       musb_writeb(regs, MUSB_TESTMODE, 0);
-
-       /* put into basic highspeed mode and start session */
-       musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE
-                                               | MUSB_POWER_HSENAB
-                                               /* ENSUSPEND wedges tusb */
-                                               /* | MUSB_POWER_ENSUSPEND */
-                                               );
-
-       musb->is_active = 0;
-       devctl = musb_readb(regs, MUSB_DEVCTL);
-       devctl &= ~MUSB_DEVCTL_SESSION;
-
-       /* session started after:
-        * (a) ID-grounded irq, host mode;
-        * (b) vbus present/connect IRQ, peripheral mode;
-        * (c) peripheral initiates, using SRP
-        */
-       if (musb->port_mode != MUSB_PORT_MODE_HOST &&
-           (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
-               musb->is_active = 1;
-       } else {
-               devctl |= MUSB_DEVCTL_SESSION;
-       }
-
-       musb_platform_enable(musb);
-       musb_writeb(regs, MUSB_DEVCTL, devctl);
-}
-
 static void musb_port_suspend(struct musb *musb, bool do_suspend)
 {
        struct usb_otg  *otg = musb->xceiv->otg;
index b2f29c9..02799a5 100644 (file)
@@ -241,7 +241,7 @@ static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend)
 
 /* platform driver interface */
 
-static int __init gpio_vbus_probe(struct platform_device *pdev)
+static int gpio_vbus_probe(struct platform_device *pdev)
 {
        struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
        struct gpio_vbus_data *gpio_vbus;
@@ -349,7 +349,7 @@ err_gpio:
        return err;
 }
 
-static int __exit gpio_vbus_remove(struct platform_device *pdev)
+static int gpio_vbus_remove(struct platform_device *pdev)
 {
        struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
        struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
@@ -398,8 +398,6 @@ static const struct dev_pm_ops gpio_vbus_dev_pm_ops = {
 };
 #endif
 
-/* NOTE:  the gpio-vbus device may *NOT* be hotplugged */
-
 MODULE_ALIAS("platform:gpio-vbus");
 
 static struct platform_driver gpio_vbus_driver = {
@@ -410,10 +408,11 @@ static struct platform_driver gpio_vbus_driver = {
                .pm = &gpio_vbus_dev_pm_ops,
 #endif
        },
-       .remove  = __exit_p(gpio_vbus_remove),
+       .probe          = gpio_vbus_probe,
+       .remove         = gpio_vbus_remove,
 };
 
-module_platform_driver_probe(gpio_vbus_driver, gpio_vbus_probe);
+module_platform_driver(gpio_vbus_driver);
 
 MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver");
 MODULE_AUTHOR("Philipp Zabel");
index c45f9c0..b21d553 100644 (file)
@@ -904,6 +904,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
        /* Crucible Devices */
        { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) },
        { }                                     /* Terminating entry */
 };
 
index 1b8af46..a7019d1 100644 (file)
  * Manufacturer: Crucible Technologies
  */
 #define FTDI_CT_COMET_PID      0x8e08
+
+/*
+ * Product: Z3X Box
+ * Manufacturer: Smart GSM Team
+ */
+#define FTDI_Z3X_PID           0x0011
index 1cf6f12..acaee06 100644 (file)
@@ -81,6 +81,7 @@ static void option_instat_callback(struct urb *urb);
 
 #define HUAWEI_VENDOR_ID                       0x12D1
 #define HUAWEI_PRODUCT_E173                    0x140C
+#define HUAWEI_PRODUCT_E1750                   0x1406
 #define HUAWEI_PRODUCT_K4505                   0x1464
 #define HUAWEI_PRODUCT_K3765                   0x1465
 #define HUAWEI_PRODUCT_K4605                   0x14C6
@@ -450,6 +451,10 @@ static void option_instat_callback(struct urb *urb);
 #define CHANGHONG_VENDOR_ID                    0x2077
 #define CHANGHONG_PRODUCT_CH690                        0x7001
 
+/* Inovia */
+#define INOVIA_VENDOR_ID                       0x20a6
+#define INOVIA_SEW858                          0x1105
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
                OPTION_BLACKLIST_NONE = 0,
@@ -567,6 +572,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t) &net_intf1_blacklist },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff),
+               .driver_info = (kernel_ulong_t) &net_intf2_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1442, USB_CLASS_COMM, 0x02, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
@@ -686,6 +693,222 @@ static const struct usb_device_id option_ids[] = {
        { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) },
        { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7B) },
        { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7C) },
 
 
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
@@ -1254,7 +1477,9 @@ static const struct usb_device_id option_ids[] = {
 
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) },
-       { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200) },
+       { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200),
+               .driver_info = (kernel_ulong_t)&net_intf6_blacklist
+       },
        { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
        { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
        { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
@@ -1342,6 +1567,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
+       { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index bedf8e4..1e6de4c 100644 (file)
@@ -4,11 +4,6 @@
  * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2003 IBM Corp.
  *
- * Copyright (C) 2009, 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
- *  - fixes, improvements and documentation for the baud rate encoding methods
- * Copyright (C) 2013 Reinhard Max <max@suse.de>
- *  - fixes and improvements for the divisor based baud rate encoding method
- *
  * Original driver for 2.2.x by anonymous
  *
  *     This program is free software; you can redistribute it and/or
@@ -134,18 +129,10 @@ MODULE_DEVICE_TABLE(usb, id_table);
 
 
 enum pl2303_type {
-       type_0,         /* H version ? */
-       type_1,         /* H version ? */
-       HX_TA,          /* HX(A) / X(A) / TA version  */ /* TODO: improve */
-       HXD_EA_RA_SA,   /* HXD / EA / RA / SA version */ /* TODO: improve */
-       TB,             /* TB version */
-       HX_CLONE,       /* Cheap and less functional clone of the HX chip */
+       type_0,         /* don't know the difference between type 0 and */
+       type_1,         /* type 1, until someone from prolific tells us... */
+       HX,             /* HX version of the pl2303 chip */
 };
-/*
- * NOTE: don't know the difference between type 0 and type 1,
- * until someone from Prolific tells us...
- * TODO: distinguish between X/HX, TA and HXD, EA, RA, SA variants
- */
 
 struct pl2303_serial_private {
        enum pl2303_type type;
@@ -185,7 +172,6 @@ static int pl2303_startup(struct usb_serial *serial)
 {
        struct pl2303_serial_private *spriv;
        enum pl2303_type type = type_0;
-       char *type_str = "unknown (treating as type_0)";
        unsigned char *buf;
 
        spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
@@ -198,53 +184,15 @@ static int pl2303_startup(struct usb_serial *serial)
                return -ENOMEM;
        }
 
-       if (serial->dev->descriptor.bDeviceClass == 0x02) {
+       if (serial->dev->descriptor.bDeviceClass == 0x02)
                type = type_0;
-               type_str = "type_0";
-       } else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) {
-               /*
-                * NOTE: The bcdDevice version is the only difference between
-                * the device descriptors of the X/HX, HXD, EA, RA, SA, TA, TB
-                */
-               if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x300) {
-                       /* Check if the device is a clone */
-                       pl2303_vendor_read(0x9494, 0, serial, buf);
-                       /*
-                        * NOTE: Not sure if this read is really needed.
-                        * The HX returns 0x00, the clone 0x02, but the Windows
-                        * driver seems to ignore the value and continues.
-                        */
-                       pl2303_vendor_write(0x0606, 0xaa, serial);
-                       pl2303_vendor_read(0x8686, 0, serial, buf);
-                       if (buf[0] != 0xaa) {
-                               type = HX_CLONE;
-                               type_str = "X/HX clone (limited functionality)";
-                       } else {
-                               type = HX_TA;
-                               type_str = "X/HX/TA";
-                       }
-                       pl2303_vendor_write(0x0606, 0x00, serial);
-               } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice)
-                                                                    == 0x400) {
-                       type = HXD_EA_RA_SA;
-                       type_str = "HXD/EA/RA/SA";
-               } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice)
-                                                                    == 0x500) {
-                       type = TB;
-                       type_str = "TB";
-               } else {
-                       dev_info(&serial->interface->dev,
-                                          "unknown/unsupported device type\n");
-                       kfree(spriv);
-                       kfree(buf);
-                       return -ENODEV;
-               }
-       } else if (serial->dev->descriptor.bDeviceClass == 0x00
-                  || serial->dev->descriptor.bDeviceClass == 0xFF) {
+       else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
+               type = HX;
+       else if (serial->dev->descriptor.bDeviceClass == 0x00)
                type = type_1;
-               type_str = "type_1";
-       }
-       dev_dbg(&serial->interface->dev, "device type: %s\n", type_str);
+       else if (serial->dev->descriptor.bDeviceClass == 0xFF)
+               type = type_1;
+       dev_dbg(&serial->interface->dev, "device type: %d\n", type);
 
        spriv->type = type;
        usb_set_serial_data(serial, spriv);
@@ -259,10 +207,10 @@ static int pl2303_startup(struct usb_serial *serial)
        pl2303_vendor_read(0x8383, 0, serial, buf);
        pl2303_vendor_write(0, 1, serial);
        pl2303_vendor_write(1, 0, serial);
-       if (type == type_0 || type == type_1)
-               pl2303_vendor_write(2, 0x24, serial);
-       else
+       if (type == HX)
                pl2303_vendor_write(2, 0x44, serial);
+       else
+               pl2303_vendor_write(2, 0x24, serial);
 
        kfree(buf);
        return 0;
@@ -316,174 +264,65 @@ static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
        return retval;
 }
 
-static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
-                                                                     u8 buf[4])
+static void pl2303_encode_baudrate(struct tty_struct *tty,
+                                       struct usb_serial_port *port,
+                                       u8 buf[4])
 {
-       /*
-        * NOTE: Only the values defined in baud_sup are supported !
-        * => if unsupported values are set, the PL2303 uses 9600 baud instead
-        * => HX clones just don't work at unsupported baud rates < 115200 baud,
-        *    for baud rates > 115200 they run at 115200 baud
-        */
        const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
-                                4800, 7200, 9600, 14400, 19200, 28800, 38400,
-                                57600, 115200, 230400, 460800, 614400, 921600,
-                                1228800, 2457600, 3000000, 6000000, 12000000 };
+                                4800, 7200, 9600, 14400, 19200, 28800, 38400,
+                                57600, 115200, 230400, 460800, 500000, 614400,
+                                921600, 1228800, 2457600, 3000000, 6000000 };
+
+       struct usb_serial *serial = port->serial;
+       struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
+       int baud;
+       int i;
+
        /*
-        * NOTE: With the exception of type_0/1 devices, the following
-        * additional baud rates are supported (tested with HX rev. 3A only):
-        * 110*, 56000*, 128000, 134400, 161280, 201600, 256000*, 268800,
-        * 403200, 806400.      (*: not HX and HX clones)
-        *
-        * Maximum values: HXD, TB: 12000000; HX, TA: 6000000;
-        *                 type_0+1: 1228800; RA: 921600; HX clones, SA: 115200
-        *
-        * As long as we are not using this encoding method for anything else
-        * than the type_0+1, HX and HX clone chips, there is no point in
-        * complicating the code to support them.
+        * NOTE: Only the values defined in baud_sup are supported!
+        *       => if unsupported values are set, the PL2303 seems to use
+        *          9600 baud (at least my PL2303X always does)
         */
-       int i;
+       baud = tty_get_baud_rate(tty);
+       dev_dbg(&port->dev, "baud requested = %d\n", baud);
+       if (!baud)
+               return;
 
        /* Set baudrate to nearest supported value */
        for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
                if (baud_sup[i] > baud)
                        break;
        }
+
        if (i == ARRAY_SIZE(baud_sup))
                baud = baud_sup[i - 1];
        else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
                baud = baud_sup[i - 1];
        else
                baud = baud_sup[i];
-       /* Respect the chip type specific baud rate limits */
-       /*
-        * FIXME: as long as we don't know how to distinguish between the
-        * HXD, EA, RA, and SA chip variants, allow the max. value of 12M.
-        */
-       if (type == HX_TA)
-               baud = min_t(int, baud, 6000000);
-       else if (type == type_0 || type == type_1)
-               baud = min_t(int, baud, 1228800);
-       else if (type == HX_CLONE)
-               baud = min_t(int, baud, 115200);
-       /* Direct (standard) baud rate encoding method */
-       put_unaligned_le32(baud, buf);
-
-       return baud;
-}
 
-static int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type,
-                                                                     u8 buf[4])
-{
-       /*
-        * Divisor based baud rate encoding method
-        *
-        * NOTE: HX clones do NOT support this method.
-        * It's not clear if the type_0/1 chips support it.
-        *
-        * divisor = 12MHz * 32 / baudrate = 2^A * B
-        *
-        * with
-        *
-        * A = buf[1] & 0x0e
-        * B = buf[0]  +  (buf[1] & 0x01) << 8
-        *
-        * Special cases:
-        * => 8 < B < 16: device seems to work not properly
-        * => B <= 8: device uses the max. value B = 512 instead
-        */
-       unsigned int A, B;
+       /* type_0, type_1 only support up to 1228800 baud */
+       if (spriv->type != HX)
+               baud = min_t(int, baud, 1228800);
 
-       /*
-        * NOTE: The Windows driver allows maximum baud rates of 110% of the
-        * specified maximium value.
-        * Quick tests with early (2004) HX (rev. A) chips suggest, that even
-        * higher baud rates (up to the maximum of 24M baud !) are working fine,
-        * but that should really be tested carefully in "real life" scenarios
-        * before removing the upper limit completely.
-        * Baud rates smaller than the specified 75 baud are definitely working
-        * fine.
-        */
-       if (type == type_0 || type == type_1)
-               baud = min_t(int, baud, 1228800 * 1.1);
-       else if (type == HX_TA)
-               baud = min_t(int, baud, 6000000 * 1.1);
-       else if (type == HXD_EA_RA_SA)
-               /* HXD, EA: 12Mbps; RA: 1Mbps; SA: 115200 bps */
-               /*
-                * FIXME: as long as we don't know how to distinguish between
-                * these chip variants, allow the max. of these values
-                */
-               baud = min_t(int, baud, 12000000 * 1.1);
-       else if (type == TB)
-               baud = min_t(int, baud, 12000000 * 1.1);
-       /* Determine factors A and B */
-       A = 0;
-       B = 12000000 * 32 / baud;  /* 12MHz */
-       B <<= 1; /* Add one bit for rounding */
-       while (B > (512 << 1) && A <= 14) {
-               A += 2;
-               B >>= 2;
-       }
-       if (A > 14) { /* max. divisor = min. baudrate reached */
-               A = 14;
-               B = 512;
-               /* => ~45.78 baud */
+       if (baud <= 115200) {
+               put_unaligned_le32(baud, buf);
        } else {
-               B = (B + 1) >> 1; /* Round the last bit */
-       }
-       /* Handle special cases */
-       if (B == 512)
-               B = 0; /* also: 1 to 8 */
-       else if (B < 16)
                /*
-                * NOTE: With the current algorithm this happens
-                * only for A=0 and means that the min. divisor
-                * (respectively: the max. baudrate) is reached.
+                * Apparently the formula for higher speeds is:
+                * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
                 */
-               B = 16;         /* => 24 MBaud */
-       /* Encode the baud rate */
-       buf[3] = 0x80;     /* Select divisor encoding method */
-       buf[2] = 0;
-       buf[1] = (A & 0x0e);            /* A */
-       buf[1] |= ((B & 0x100) >> 8);   /* MSB of B */
-       buf[0] = B & 0xff;              /* 8 LSBs of B */
-       /* Calculate the actual/resulting baud rate */
-       if (B <= 8)
-               B = 512;
-       baud = 12000000 * 32 / ((1 << A) * B);
-
-       return baud;
-}
-
-static void pl2303_encode_baudrate(struct tty_struct *tty,
-                                       struct usb_serial_port *port,
-                                       enum pl2303_type type,
-                                       u8 buf[4])
-{
-       int baud;
+               unsigned tmp = 12000000 * 32 / baud;
+               buf[3] = 0x80;
+               buf[2] = 0;
+               buf[1] = (tmp >= 256);
+               while (tmp >= 256) {
+                       tmp >>= 2;
+                       buf[1] <<= 1;
+               }
+               buf[0] = tmp;
+       }
 
-       baud = tty_get_baud_rate(tty);
-       dev_dbg(&port->dev, "baud requested = %d\n", baud);
-       if (!baud)
-               return;
-       /*
-        * There are two methods for setting/encoding the baud rate
-        * 1) Direct method: encodes the baud rate value directly
-        *    => supported by all chip types
-        * 2) Divisor based method: encodes a divisor to a base value (12MHz*32)
-        *    => not supported by HX clones (and likely type_0/1 chips)
-        *
-        * NOTE: Although the divisor based baud rate encoding method is much
-        * more flexible, some of the standard baud rate values can not be
-        * realized exactly. But the difference is very small (max. 0.2%) and
-        * the device likely uses the same baud rate generator for both methods
-        * so that there is likley no difference.
-        */
-       if (type == type_0 || type == type_1 || type == HX_CLONE)
-               baud = pl2303_baudrate_encode_direct(baud, type, buf);
-       else
-               baud = pl2303_baudrate_encode_divisor(baud, type, buf);
        /* Save resulting baud rate */
        tty_encode_baud_rate(tty, baud, baud);
        dev_dbg(&port->dev, "baud set = %d\n", baud);
@@ -540,8 +379,8 @@ static void pl2303_set_termios(struct tty_struct *tty,
                dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
        }
 
-       /* For reference:   buf[0]:buf[3] baud rate value */
-       pl2303_encode_baudrate(tty, port, spriv->type, buf);
+       /* For reference buf[0]:buf[3] baud rate value */
+       pl2303_encode_baudrate(tty, port, &buf[0]);
 
        /* For reference buf[4]=0 is 1 stop bits */
        /* For reference buf[4]=1 is 1.5 stop bits */
@@ -618,10 +457,10 @@ static void pl2303_set_termios(struct tty_struct *tty,
        dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf);
 
        if (C_CRTSCTS(tty)) {
-               if (spriv->type == type_0 || spriv->type == type_1)
-                       pl2303_vendor_write(0x0, 0x41, serial);
-               else
+               if (spriv->type == HX)
                        pl2303_vendor_write(0x0, 0x61, serial);
+               else
+                       pl2303_vendor_write(0x0, 0x41, serial);
        } else {
                pl2303_vendor_write(0x0, 0x0, serial);
        }
@@ -658,7 +497,7 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
        int result;
 
-       if (spriv->type == type_0 || spriv->type == type_1) {
+       if (spriv->type != HX) {
                usb_clear_halt(serial->dev, port->write_urb->pipe);
                usb_clear_halt(serial->dev, port->read_urb->pipe);
        } else {
@@ -833,7 +672,6 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
        result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                                 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
                                 0, NULL, 0, 100);
-       /* NOTE: HX clones don't support sending breaks, -EPIPE is returned */
        if (result)
                dev_err(&port->dev, "error sending break = %d\n", result);
 }
index 760b785..c9a3569 100644 (file)
@@ -190,6 +190,7 @@ static struct usb_device_id ti_id_table_combined[] = {
        { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
        { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
        { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
+       { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
        { }     /* terminator */
 };
index 94d75ed..18509e6 100644 (file)
@@ -211,8 +211,11 @@ static int slave_configure(struct scsi_device *sdev)
                /*
                 * Many devices do not respond properly to READ_CAPACITY_16.
                 * Tell the SCSI layer to try READ_CAPACITY_10 first.
+                * However some USB 3.0 drive enclosures return capacity
+                * modulo 2TB. Those must use READ_CAPACITY_16
                 */
-               sdev->try_rc_10_first = 1;
+               if (!(us->fflags & US_FL_NEEDS_CAP16))
+                       sdev->try_rc_10_first = 1;
 
                /* assume SPC3 or latter devices support sense size > 18 */
                if (sdev->scsi_level > SCSI_SPC_2)
index c015f2c..de32cfa 100644 (file)
@@ -1925,6 +1925,13 @@ UNUSUAL_DEV(  0x1652, 0x6600, 0x0201, 0x0201,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Oliver Neukum <oneukum@suse.com> */
+UNUSUAL_DEV(  0x174c, 0x55aa, 0x0100, 0x0100,
+               "ASMedia",
+               "AS2105",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NEEDS_CAP16),
+
 /* Reported by Jesse Feddema <jdfeddema@gmail.com> */
 UNUSUAL_DEV(  0x177f, 0x0400, 0x0000, 0x0000,
                "Yarvik",
index a9807de..4fb7a8f 100644 (file)
@@ -545,6 +545,8 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
        long npage;
        int ret = 0, prot = 0;
        uint64_t mask;
+       struct vfio_dma *dma = NULL;
+       unsigned long pfn;
 
        end = map->iova + map->size;
 
@@ -587,8 +589,6 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
        }
 
        for (iova = map->iova; iova < end; iova += size, vaddr += size) {
-               struct vfio_dma *dma = NULL;
-               unsigned long pfn;
                long i;
 
                /* Pin a contiguous chunk of memory */
@@ -597,16 +597,15 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
                if (npage <= 0) {
                        WARN_ON(!npage);
                        ret = (int)npage;
-                       break;
+                       goto out;
                }
 
                /* Verify pages are not already mapped */
                for (i = 0; i < npage; i++) {
                        if (iommu_iova_to_phys(iommu->domain,
                                               iova + (i << PAGE_SHIFT))) {
-                               vfio_unpin_pages(pfn, npage, prot, true);
                                ret = -EBUSY;
-                               break;
+                               goto out_unpin;
                        }
                }
 
@@ -616,8 +615,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
                if (ret) {
                        if (ret != -EBUSY ||
                            map_try_harder(iommu, iova, pfn, npage, prot)) {
-                               vfio_unpin_pages(pfn, npage, prot, true);
-                               break;
+                               goto out_unpin;
                        }
                }
 
@@ -672,9 +670,8 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
                        dma = kzalloc(sizeof(*dma), GFP_KERNEL);
                        if (!dma) {
                                iommu_unmap(iommu->domain, iova, size);
-                               vfio_unpin_pages(pfn, npage, prot, true);
                                ret = -ENOMEM;
-                               break;
+                               goto out_unpin;
                        }
 
                        dma->size = size;
@@ -685,16 +682,21 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
                }
        }
 
-       if (ret) {
-               struct vfio_dma *tmp;
-               iova = map->iova;
-               size = map->size;
-               while ((tmp = vfio_find_dma(iommu, iova, size))) {
-                       int r = vfio_remove_dma_overlap(iommu, iova,
-                                                       &size, tmp);
-                       if (WARN_ON(r || !size))
-                               break;
-               }
+       WARN_ON(ret);
+       mutex_unlock(&iommu->lock);
+       return ret;
+
+out_unpin:
+       vfio_unpin_pages(pfn, npage, prot, true);
+
+out:
+       iova = map->iova;
+       size = map->size;
+       while ((dma = vfio_find_dma(iommu, iova, size))) {
+               int r = vfio_remove_dma_overlap(iommu, iova,
+                                               &size, dma);
+               if (WARN_ON(r || !size))
+                       break;
        }
 
        mutex_unlock(&iommu->lock);
index 592b316..e663921 100644 (file)
@@ -728,7 +728,12 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq,
        }
        se_sess = tv_nexus->tvn_se_sess;
 
-       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_KERNEL);
+       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
+       if (tag < 0) {
+               pr_err("Unable to obtain tag for tcm_vhost_cmd\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
        cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag];
        sg = cmd->tvc_sgl;
        pages = cmd->tvc_upages;
@@ -1051,7 +1056,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                if (data_direction != DMA_NONE) {
                        ret = vhost_scsi_map_iov_to_sgl(cmd,
                                        &vq->iov[data_first], data_num,
-                                       data_direction == DMA_TO_DEVICE);
+                                       data_direction == DMA_FROM_DEVICE);
                        if (unlikely(ret)) {
                                vq_err(vq, "Failed to map iov to sgl\n");
                                goto err_free;
index a54ccdc..22ad852 100644 (file)
@@ -361,37 +361,13 @@ void au1100fb_fb_rotate(struct fb_info *fbi, int angle)
 int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 {
        struct au1100fb_device *fbdev;
-       unsigned int len;
-       unsigned long start=0, off;
 
        fbdev = to_au1100fb_device(fbi);
 
-       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
-               return -EINVAL;
-       }
-
-       start = fbdev->fb_phys & PAGE_MASK;
-       len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
-
-       off = vma->vm_pgoff << PAGE_SHIFT;
-
-       if ((vma->vm_end - vma->vm_start + off) > len) {
-               return -EINVAL;
-       }
-
-       off += start;
-       vma->vm_pgoff = off >> PAGE_SHIFT;
-
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
 
-       if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-                               vma->vm_end - vma->vm_start,
-                               vma->vm_page_prot)) {
-               return -EAGAIN;
-       }
-
-       return 0;
+       return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len);
 }
 
 static struct fb_ops au1100fb_ops =
index 301224e..1d02897 100644 (file)
@@ -1233,34 +1233,13 @@ static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
  * method mainly to allow the use of the TLB streaming flag (CCA=6)
  */
 static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-
 {
-       unsigned int len;
-       unsigned long start=0, off;
        struct au1200fb_device *fbdev = info->par;
 
-       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
-               return -EINVAL;
-       }
-
-       start = fbdev->fb_phys & PAGE_MASK;
-       len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
-
-       off = vma->vm_pgoff << PAGE_SHIFT;
-
-       if ((vma->vm_end - vma->vm_start + off) > len) {
-               return -EINVAL;
-       }
-
-       off += start;
-       vma->vm_pgoff = off >> PAGE_SHIFT;
-
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
 
-       return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-                                 vma->vm_end - vma->vm_start,
-                                 vma->vm_page_prot);
+       return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len);
 }
 
 static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
index c7c64f1..fa932c2 100644 (file)
@@ -613,6 +613,9 @@ static int w1_bus_notify(struct notifier_block *nb, unsigned long action,
        sl = dev_to_w1_slave(dev);
        fops = sl->family->fops;
 
+       if (!fops)
+               return 0;
+
        switch (action) {
        case BUS_NOTIFY_ADD_DEVICE:
                /* if the family driver needs to initialize something... */
@@ -713,7 +716,10 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
        atomic_set(&sl->refcnt, 0);
        init_completion(&sl->released);
 
+       /* slave modules need to be loaded in a context with unlocked mutex */
+       mutex_unlock(&dev->mutex);
        request_module("w1-family-0x%0x", rn->family);
+       mutex_lock(&dev->mutex);
 
        spin_lock(&w1_flock);
        f = w1_family_registered(rn->family);
index 5be5e3d..19f3c3f 100644 (file)
@@ -802,6 +802,12 @@ static int hpwdt_init_one(struct pci_dev *dev,
                return -ENODEV;
        }
 
+       /*
+        * Ignore all auxilary iLO devices with the following PCI ID
+        */
+       if (dev->subsystem_device == 0x1979)
+               return -ENODEV;
+
        if (pci_enable_device(dev)) {
                dev_warn(&dev->dev,
                        "Not possible to enable PCI Device: 0x%x:0x%x.\n",
index 491419e..5c3d4df 100644 (file)
@@ -35,7 +35,7 @@
 #define KEMPLD_WDT_STAGE_TIMEOUT(x)    (0x1b + (x) * 4)
 #define KEMPLD_WDT_STAGE_CFG(x)                (0x18 + (x))
 #define STAGE_CFG_GET_PRESCALER(x)     (((x) & 0x30) >> 4)
-#define STAGE_CFG_SET_PRESCALER(x)     (((x) & 0x30) << 4)
+#define STAGE_CFG_SET_PRESCALER(x)     (((x) & 0x3) << 4)
 #define STAGE_CFG_PRESCALER_MASK       0x30
 #define STAGE_CFG_ACTION_MASK          0x7
 #define STAGE_CFG_ASSERT               (1 << 3)
index 1f94b42..f6caa77 100644 (file)
@@ -146,7 +146,7 @@ static const struct watchdog_ops sunxi_wdt_ops = {
        .set_timeout    = sunxi_wdt_set_timeout,
 };
 
-static int __init sunxi_wdt_probe(struct platform_device *pdev)
+static int sunxi_wdt_probe(struct platform_device *pdev)
 {
        struct sunxi_wdt_dev *sunxi_wdt;
        struct resource *res;
@@ -187,7 +187,7 @@ static int __init sunxi_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit sunxi_wdt_remove(struct platform_device *pdev)
+static int sunxi_wdt_remove(struct platform_device *pdev)
 {
        struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
 
index 42913f1..c9b0c62 100644 (file)
@@ -310,7 +310,8 @@ static long ts72xx_wdt_ioctl(struct file *file, unsigned int cmd,
 
        case WDIOC_GETSTATUS:
        case WDIOC_GETBOOTSTATUS:
-               return put_user(0, p);
+               error = put_user(0, p);
+               break;
 
        case WDIOC_KEEPALIVE:
                ts72xx_wdt_kick(wdt);
index 646337d..5293003 100644 (file)
@@ -600,9 +600,6 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
 
        /* lock down the parent dentry so we can peer at it */
        parent = dget_parent(dentry);
-       if (!parent->d_inode)
-               goto out_bad;
-
        dir = AFS_FS_I(parent->d_inode);
 
        /* validate the parent directory */
index 6b868f0..067e3d3 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -167,10 +167,25 @@ static int __init aio_setup(void)
 }
 __initcall(aio_setup);
 
+static void put_aio_ring_file(struct kioctx *ctx)
+{
+       struct file *aio_ring_file = ctx->aio_ring_file;
+       if (aio_ring_file) {
+               truncate_setsize(aio_ring_file->f_inode, 0);
+
+               /* Prevent further access to the kioctx from migratepages */
+               spin_lock(&aio_ring_file->f_inode->i_mapping->private_lock);
+               aio_ring_file->f_inode->i_mapping->private_data = NULL;
+               ctx->aio_ring_file = NULL;
+               spin_unlock(&aio_ring_file->f_inode->i_mapping->private_lock);
+
+               fput(aio_ring_file);
+       }
+}
+
 static void aio_free_ring(struct kioctx *ctx)
 {
        int i;
-       struct file *aio_ring_file = ctx->aio_ring_file;
 
        for (i = 0; i < ctx->nr_pages; i++) {
                pr_debug("pid(%d) [%d] page->count=%d\n", current->pid, i,
@@ -178,14 +193,10 @@ static void aio_free_ring(struct kioctx *ctx)
                put_page(ctx->ring_pages[i]);
        }
 
+       put_aio_ring_file(ctx);
+
        if (ctx->ring_pages && ctx->ring_pages != ctx->internal_pages)
                kfree(ctx->ring_pages);
-
-       if (aio_ring_file) {
-               truncate_setsize(aio_ring_file->f_inode, 0);
-               fput(aio_ring_file);
-               ctx->aio_ring_file = NULL;
-       }
 }
 
 static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
@@ -207,9 +218,8 @@ static int aio_set_page_dirty(struct page *page)
 static int aio_migratepage(struct address_space *mapping, struct page *new,
                        struct page *old, enum migrate_mode mode)
 {
-       struct kioctx *ctx = mapping->private_data;
+       struct kioctx *ctx;
        unsigned long flags;
-       unsigned idx = old->index;
        int rc;
 
        /* Writeback must be complete */
@@ -224,10 +234,23 @@ static int aio_migratepage(struct address_space *mapping, struct page *new,
 
        get_page(new);
 
-       spin_lock_irqsave(&ctx->completion_lock, flags);
-       migrate_page_copy(new, old);
-       ctx->ring_pages[idx] = new;
-       spin_unlock_irqrestore(&ctx->completion_lock, flags);
+       /* We can potentially race against kioctx teardown here.  Use the
+        * address_space's private data lock to protect the mapping's
+        * private_data.
+        */
+       spin_lock(&mapping->private_lock);
+       ctx = mapping->private_data;
+       if (ctx) {
+               pgoff_t idx;
+               spin_lock_irqsave(&ctx->completion_lock, flags);
+               migrate_page_copy(new, old);
+               idx = old->index;
+               if (idx < (pgoff_t)ctx->nr_pages)
+                       ctx->ring_pages[idx] = new;
+               spin_unlock_irqrestore(&ctx->completion_lock, flags);
+       } else
+               rc = -EBUSY;
+       spin_unlock(&mapping->private_lock);
 
        return rc;
 }
@@ -617,8 +640,7 @@ out_freepcpu:
 out_freeref:
        free_percpu(ctx->users.pcpu_count);
 out_freectx:
-       if (ctx->aio_ring_file)
-               fput(ctx->aio_ring_file);
+       put_aio_ring_file(ctx);
        kmem_cache_free(kioctx_cachep, ctx);
        pr_debug("error allocating ioctx %d\n", err);
        return ERR_PTR(err);
index 100edcc..4c94a79 100644 (file)
@@ -1413,7 +1413,7 @@ static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
  *   long file_ofs
  * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
  */
-static void fill_files_note(struct memelfnote *note)
+static int fill_files_note(struct memelfnote *note)
 {
        struct vm_area_struct *vma;
        unsigned count, size, names_ofs, remaining, n;
@@ -1428,11 +1428,11 @@ static void fill_files_note(struct memelfnote *note)
        names_ofs = (2 + 3 * count) * sizeof(data[0]);
  alloc:
        if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */
-               goto err;
+               return -EINVAL;
        size = round_up(size, PAGE_SIZE);
        data = vmalloc(size);
        if (!data)
-               goto err;
+               return -ENOMEM;
 
        start_end_ofs = data + 2;
        name_base = name_curpos = ((char *)data) + names_ofs;
@@ -1485,7 +1485,7 @@ static void fill_files_note(struct memelfnote *note)
 
        size = name_curpos - (char *)data;
        fill_note(note, "CORE", NT_FILE, size, data);
err: ;
      return 0;
 }
 
 #ifdef CORE_DUMP_USE_REGSET
@@ -1686,8 +1686,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
        fill_auxv_note(&info->auxv, current->mm);
        info->size += notesize(&info->auxv);
 
-       fill_files_note(&info->files);
-       info->size += notesize(&info->files);
+       if (fill_files_note(&info->files) == 0)
+               info->size += notesize(&info->files);
 
        return 1;
 }
@@ -1719,7 +1719,8 @@ static int write_note_info(struct elf_note_info *info,
                        return 0;
                if (first && !writenote(&info->auxv, file, foffset))
                        return 0;
-               if (first && !writenote(&info->files, file, foffset))
+               if (first && info->files.data &&
+                               !writenote(&info->files, file, foffset))
                        return 0;
 
                for (i = 1; i < info->thread_notes; ++i)
@@ -1806,6 +1807,7 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
 
 struct elf_note_info {
        struct memelfnote *notes;
+       struct memelfnote *notes_files;
        struct elf_prstatus *prstatus;  /* NT_PRSTATUS */
        struct elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
        struct list_head thread_list;
@@ -1896,9 +1898,12 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
 
        fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo);
        fill_auxv_note(info->notes + 3, current->mm);
-       fill_files_note(info->notes + 4);
+       info->numnote = 4;
 
-       info->numnote = 5;
+       if (fill_files_note(info->notes + info->numnote) == 0) {
+               info->notes_files = info->notes + info->numnote;
+               info->numnote++;
+       }
 
        /* Try to dump the FPU. */
        info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs,
@@ -1960,8 +1965,9 @@ static void free_note_info(struct elf_note_info *info)
                kfree(list_entry(tmp, struct elf_thread_status, list));
        }
 
-       /* Free data allocated by fill_files_note(): */
-       vfree(info->notes[4].data);
+       /* Free data possibly allocated by fill_files_note(): */
+       if (info->notes_files)
+               vfree(info->notes_files->data);
 
        kfree(info->prstatus);
        kfree(info->psinfo);
@@ -2044,7 +2050,7 @@ static int elf_core_dump(struct coredump_params *cprm)
        struct vm_area_struct *vma, *gate_vma;
        struct elfhdr *elf = NULL;
        loff_t offset = 0, dataoff, foffset;
-       struct elf_note_info info;
+       struct elf_note_info info = { };
        struct elf_phdr *phdr4note = NULL;
        struct elf_shdr *shdr4extnum = NULL;
        Elf_Half e_phnum;
index 58b7d14..08cc08f 100644 (file)
@@ -107,7 +107,8 @@ static void check_idle_worker(struct btrfs_worker_thread *worker)
                worker->idle = 1;
 
                /* the list may be empty if the worker is just starting */
-               if (!list_empty(&worker->worker_list)) {
+               if (!list_empty(&worker->worker_list) &&
+                   !worker->workers->stopping) {
                        list_move(&worker->worker_list,
                                 &worker->workers->idle_list);
                }
@@ -127,7 +128,8 @@ static void check_busy_worker(struct btrfs_worker_thread *worker)
                spin_lock_irqsave(&worker->workers->lock, flags);
                worker->idle = 0;
 
-               if (!list_empty(&worker->worker_list)) {
+               if (!list_empty(&worker->worker_list) &&
+                   !worker->workers->stopping) {
                        list_move_tail(&worker->worker_list,
                                      &worker->workers->worker_list);
                }
@@ -412,6 +414,7 @@ void btrfs_stop_workers(struct btrfs_workers *workers)
        int can_stop;
 
        spin_lock_irq(&workers->lock);
+       workers->stopping = 1;
        list_splice_init(&workers->idle_list, &workers->worker_list);
        while (!list_empty(&workers->worker_list)) {
                cur = workers->worker_list.next;
@@ -455,6 +458,7 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max,
        workers->ordered = 0;
        workers->atomic_start_pending = 0;
        workers->atomic_worker_start = async_helper;
+       workers->stopping = 0;
 }
 
 /*
@@ -480,15 +484,19 @@ static int __btrfs_start_workers(struct btrfs_workers *workers)
        atomic_set(&worker->num_pending, 0);
        atomic_set(&worker->refs, 1);
        worker->workers = workers;
-       worker->task = kthread_run(worker_loop, worker,
-                                  "btrfs-%s-%d", workers->name,
-                                  workers->num_workers + 1);
+       worker->task = kthread_create(worker_loop, worker,
+                                     "btrfs-%s-%d", workers->name,
+                                     workers->num_workers + 1);
        if (IS_ERR(worker->task)) {
                ret = PTR_ERR(worker->task);
-               kfree(worker);
                goto fail;
        }
+
        spin_lock_irq(&workers->lock);
+       if (workers->stopping) {
+               spin_unlock_irq(&workers->lock);
+               goto fail_kthread;
+       }
        list_add_tail(&worker->worker_list, &workers->idle_list);
        worker->idle = 1;
        workers->num_workers++;
@@ -496,8 +504,13 @@ static int __btrfs_start_workers(struct btrfs_workers *workers)
        WARN_ON(workers->num_workers_starting < 0);
        spin_unlock_irq(&workers->lock);
 
+       wake_up_process(worker->task);
        return 0;
+
+fail_kthread:
+       kthread_stop(worker->task);
 fail:
+       kfree(worker);
        spin_lock_irq(&workers->lock);
        workers->num_workers_starting--;
        spin_unlock_irq(&workers->lock);
index 063698b..1f26792 100644 (file)
@@ -107,6 +107,8 @@ struct btrfs_workers {
 
        /* extra name for this worker, used for current->name */
        char *name;
+
+       int stopping;
 };
 
 void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work);
index 7068168..9efb94e 100644 (file)
@@ -535,10 +535,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
        list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
 
        btrfs_rm_dev_replace_srcdev(fs_info, src_device);
-       if (src_device->bdev) {
-               /* zero out the old super */
-               btrfs_scratch_superblock(src_device);
-       }
+
        /*
         * this is again a consistent state where no dev_replace procedure
         * is running, the target device is part of the filesystem, the
index 4ae17ed..62176ad 100644 (file)
@@ -1561,8 +1561,9 @@ int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
        return ret;
 }
 
-struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
-                                             struct btrfs_key *location)
+struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
+                                    struct btrfs_key *location,
+                                    bool check_ref)
 {
        struct btrfs_root *root;
        int ret;
@@ -1586,7 +1587,7 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
 again:
        root = btrfs_lookup_fs_root(fs_info, location->objectid);
        if (root) {
-               if (btrfs_root_refs(&root->root_item) == 0)
+               if (check_ref && btrfs_root_refs(&root->root_item) == 0)
                        return ERR_PTR(-ENOENT);
                return root;
        }
@@ -1595,7 +1596,7 @@ again:
        if (IS_ERR(root))
                return root;
 
-       if (btrfs_root_refs(&root->root_item) == 0) {
+       if (check_ref && btrfs_root_refs(&root->root_item) == 0) {
                ret = -ENOENT;
                goto fail;
        }
index b71acd6..5ce2a7d 100644 (file)
@@ -68,8 +68,17 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
 int btrfs_init_fs_root(struct btrfs_root *root);
 int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
                         struct btrfs_root *root);
-struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
-                                             struct btrfs_key *location);
+
+struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
+                                    struct btrfs_key *key,
+                                    bool check_ref);
+static inline struct btrfs_root *
+btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
+                          struct btrfs_key *location)
+{
+       return btrfs_get_fs_root(fs_info, location, true);
+}
+
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
 void btrfs_btree_balance_dirty(struct btrfs_root *root);
 void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root);
index c09a40d..51731b7 100644 (file)
@@ -145,8 +145,16 @@ int __init extent_io_init(void)
                                     offsetof(struct btrfs_io_bio, bio));
        if (!btrfs_bioset)
                goto free_buffer_cache;
+
+       if (bioset_integrity_create(btrfs_bioset, BIO_POOL_SIZE))
+               goto free_bioset;
+
        return 0;
 
+free_bioset:
+       bioset_free(btrfs_bioset);
+       btrfs_bioset = NULL;
+
 free_buffer_cache:
        kmem_cache_destroy(extent_buffer_cache);
        extent_buffer_cache = NULL;
@@ -1482,10 +1490,8 @@ static noinline u64 find_delalloc_range(struct extent_io_tree *tree,
                cur_start = state->end + 1;
                node = rb_next(node);
                total_bytes += state->end - state->start + 1;
-               if (total_bytes >= max_bytes) {
-                       *end = *start + max_bytes - 1;
+               if (total_bytes >= max_bytes)
                        break;
-               }
                if (!node)
                        break;
        }
@@ -1614,7 +1620,7 @@ again:
                *start = delalloc_start;
                *end = delalloc_end;
                free_extent_state(cached_state);
-               return found;
+               return 0;
        }
 
        /*
@@ -1627,10 +1633,9 @@ again:
 
        /*
         * make sure to limit the number of pages we try to lock down
-        * if we're looping.
         */
-       if (delalloc_end + 1 - delalloc_start > max_bytes && loops)
-               delalloc_end = delalloc_start + PAGE_CACHE_SIZE - 1;
+       if (delalloc_end + 1 - delalloc_start > max_bytes)
+               delalloc_end = delalloc_start + max_bytes - 1;
 
        /* step two, lock all the pages after the page that has start */
        ret = lock_delalloc_pages(inode, locked_page,
@@ -1641,8 +1646,7 @@ again:
                 */
                free_extent_state(cached_state);
                if (!loops) {
-                       unsigned long offset = (*start) & (PAGE_CACHE_SIZE - 1);
-                       max_bytes = PAGE_CACHE_SIZE - offset;
+                       max_bytes = PAGE_CACHE_SIZE;
                        loops = 1;
                        goto again;
                } else {
index 22ebc13..51e3afa 100644 (file)
@@ -6437,6 +6437,7 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
 
        if (btrfs_extent_readonly(root, disk_bytenr))
                goto out;
+       btrfs_release_path(path);
 
        /*
         * look for other files referencing this extent, if we
@@ -7986,7 +7987,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 
        /* check for collisions, even if the  name isn't there */
-       ret = btrfs_check_dir_item_collision(root, new_dir->i_ino,
+       ret = btrfs_check_dir_item_collision(dest, new_dir->i_ino,
                             new_dentry->d_name.name,
                             new_dentry->d_name.len);
 
index a5a2632..4a35572 100644 (file)
@@ -588,7 +588,7 @@ static struct btrfs_root *read_fs_root(struct btrfs_fs_info *fs_info,
        else
                key.offset = (u64)-1;
 
-       return btrfs_read_fs_root_no_name(fs_info, &key);
+       return btrfs_get_fs_root(fs_info, &key, false);
 }
 
 #ifdef BTRFS_COMPAT_EXTENT_TREE_V0
index 0b1f4ef..ec71ea4 100644 (file)
@@ -299,11 +299,6 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
                        continue;
                }
 
-               if (btrfs_root_refs(&root->root_item) == 0) {
-                       btrfs_add_dead_root(root);
-                       continue;
-               }
-
                err = btrfs_init_fs_root(root);
                if (err) {
                        btrfs_free_fs_root(root);
@@ -318,6 +313,9 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
                        btrfs_free_fs_root(root);
                        break;
                }
+
+               if (btrfs_root_refs(&root->root_item) == 0)
+                       btrfs_add_dead_root(root);
        }
 
        btrfs_free_path(path);
index e7a9535..8c81bdc 100644 (file)
@@ -1838,11 +1838,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        assert_qgroups_uptodate(trans);
        update_super_roots(root);
 
-       if (!root->fs_info->log_root_recovering) {
-               btrfs_set_super_log_root(root->fs_info->super_copy, 0);
-               btrfs_set_super_log_root_level(root->fs_info->super_copy, 0);
-       }
-
+       btrfs_set_super_log_root(root->fs_info->super_copy, 0);
+       btrfs_set_super_log_root_level(root->fs_info->super_copy, 0);
        memcpy(root->fs_info->super_for_commit, root->fs_info->super_copy,
               sizeof(*root->fs_info->super_copy));
 
index a106458..043b215 100644 (file)
@@ -1716,6 +1716,7 @@ void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
                                 struct btrfs_device *srcdev)
 {
        WARN_ON(!mutex_is_locked(&fs_info->fs_devices->device_list_mutex));
+
        list_del_rcu(&srcdev->dev_list);
        list_del_rcu(&srcdev->dev_alloc_list);
        fs_info->fs_devices->num_devices--;
@@ -1725,9 +1726,13 @@ void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
        }
        if (srcdev->can_discard)
                fs_info->fs_devices->num_can_discard--;
-       if (srcdev->bdev)
+       if (srcdev->bdev) {
                fs_info->fs_devices->open_devices--;
 
+               /* zero out the old super */
+               btrfs_scratch_superblock(srcdev);
+       }
+
        call_rcu(&srcdev->rcu, free_device);
 }
 
index 4d74335..6024877 100644 (file)
@@ -1005,9 +1005,19 @@ grow_dev_page(struct block_device *bdev, sector_t block,
        struct buffer_head *bh;
        sector_t end_block;
        int ret = 0;            /* Will call free_more_memory() */
+       gfp_t gfp_mask;
 
-       page = find_or_create_page(inode->i_mapping, index,
-               (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE);
+       gfp_mask = mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS;
+       gfp_mask |= __GFP_MOVABLE;
+       /*
+        * XXX: __getblk_slow() can not really deal with failure and
+        * will endlessly loop on improvised global reclaim.  Prefer
+        * looping in the allocator rather than here, at least that
+        * code knows what it's doing.
+        */
+       gfp_mask |= __GFP_NOFAIL;
+
+       page = find_or_create_page(inode->i_mapping, index, gfp_mask);
        if (!page)
                return ret;
 
index a16b4e5..77fc5e1 100644 (file)
@@ -120,14 +120,16 @@ cifs_read_super(struct super_block *sb)
 {
        struct inode *inode;
        struct cifs_sb_info *cifs_sb;
+       struct cifs_tcon *tcon;
        int rc = 0;
 
        cifs_sb = CIFS_SB(sb);
+       tcon = cifs_sb_master_tcon(cifs_sb);
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
                sb->s_flags |= MS_POSIXACL;
 
-       if (cifs_sb_master_tcon(cifs_sb)->ses->capabilities & CAP_LARGE_FILES)
+       if (tcon->ses->capabilities & tcon->ses->server->vals->cap_large_files)
                sb->s_maxbytes = MAX_LFS_FILESIZE;
        else
                sb->s_maxbytes = MAX_NON_LFS;
@@ -147,7 +149,7 @@ cifs_read_super(struct super_block *sb)
                goto out_no_root;
        }
 
-       if (cifs_sb_master_tcon(cifs_sb)->nocase)
+       if (tcon->nocase)
                sb->s_d_op = &cifs_ci_dentry_ops;
        else
                sb->s_d_op = &cifs_dentry_ops;
index ea723a5..6d0b072 100644 (file)
@@ -132,5 +132,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "2.01"
+#define CIFS_VERSION   "2.02"
 #endif                         /* _CIFSFS_H */
index cfa14c8..52b6f6c 100644 (file)
@@ -547,9 +547,6 @@ struct TCP_Server_Info {
        unsigned int max_rw;    /* maxRw specifies the maximum */
        /* message size the server can send or receive for */
        /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
-       unsigned int max_vcs;   /* maximum number of smb sessions, at least
-                                  those that can be specified uniquely with
-                                  vcnumbers */
        unsigned int capabilities; /* selective disabling of caps by smb sess */
        int timeAdj;  /* Adjust for difference in server time zone in sec */
        __u64 CurrentMid;         /* multiplex id - rotating counter */
@@ -715,7 +712,6 @@ struct cifs_ses {
        enum statusEnum status;
        unsigned overrideSecFlg;  /* if non-zero override global sec flags */
        __u16 ipc_tid;          /* special tid for connection to IPC share */
-       __u16 vcnum;
        char *serverOS;         /* name of operating system underlying server */
        char *serverNOS;        /* name of network operating system of server */
        char *serverDomain;     /* security realm of server */
@@ -1272,6 +1268,7 @@ struct dfs_info3_param {
 #define CIFS_FATTR_DELETE_PENDING      0x2
 #define CIFS_FATTR_NEED_REVAL          0x4
 #define CIFS_FATTR_INO_COLLISION       0x8
+#define CIFS_FATTR_UNKNOWN_NLINK       0x10
 
 struct cifs_fattr {
        u32             cf_flags;
index 948676d..08f9dfb 100644 (file)
@@ -1491,15 +1491,30 @@ struct file_notify_information {
        __u8  FileName[0];
 } __attribute__((packed));
 
-struct reparse_data {
-       __u32   ReparseTag;
-       __u16   ReparseDataLength;
+/* For IO_REPARSE_TAG_SYMLINK */
+struct reparse_symlink_data {
+       __le32  ReparseTag;
+       __le16  ReparseDataLength;
        __u16   Reserved;
-       __u16   SubstituteNameOffset;
-       __u16   SubstituteNameLength;
-       __u16   PrintNameOffset;
-       __u16   PrintNameLength;
-       __u32   Flags;
+       __le16  SubstituteNameOffset;
+       __le16  SubstituteNameLength;
+       __le16  PrintNameOffset;
+       __le16  PrintNameLength;
+       __le32  Flags;
+       char    PathBuffer[0];
+} __attribute__((packed));
+
+/* For IO_REPARSE_TAG_NFS */
+#define NFS_SPECFILE_LNK       0x00000000014B4E4C
+#define NFS_SPECFILE_CHR       0x0000000000524843
+#define NFS_SPECFILE_BLK       0x00000000004B4C42
+#define NFS_SPECFILE_FIFO      0x000000004F464946
+#define NFS_SPECFILE_SOCK      0x000000004B434F53
+struct reparse_posix_data {
+       __le32  ReparseTag;
+       __le16  ReparseDataLength;
+       __u16   Reserved;
+       __le64  InodeType; /* LNK, FIFO, CHR etc. */
        char    PathBuffer[0];
 } __attribute__((packed));
 
@@ -2652,26 +2667,7 @@ typedef struct file_xattr_info {
 } __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info
                                              level 0x205 */
 
-
-/* flags for chattr command */
-#define EXT_SECURE_DELETE              0x00000001 /* EXT3_SECRM_FL */
-#define EXT_ENABLE_UNDELETE            0x00000002 /* EXT3_UNRM_FL */
-/* Reserved for compress file 0x4 */
-#define EXT_SYNCHRONOUS                        0x00000008 /* EXT3_SYNC_FL */
-#define EXT_IMMUTABLE_FL               0x00000010 /* EXT3_IMMUTABLE_FL */
-#define EXT_OPEN_APPEND_ONLY           0x00000020 /* EXT3_APPEND_FL */
-#define EXT_DO_NOT_BACKUP              0x00000040 /* EXT3_NODUMP_FL */
-#define EXT_NO_UPDATE_ATIME            0x00000080 /* EXT3_NOATIME_FL */
-/* 0x100 through 0x800 reserved for compression flags and are GET-ONLY */
-#define EXT_HASH_TREE_INDEXED_DIR      0x00001000 /* GET-ONLY EXT3_INDEX_FL */
-/* 0x2000 reserved for IMAGIC_FL */
-#define EXT_JOURNAL_THIS_FILE  0x00004000 /* GET-ONLY EXT3_JOURNAL_DATA_FL */
-/* 0x8000 reserved for EXT3_NOTAIL_FL */
-#define EXT_SYNCHRONOUS_DIR            0x00010000 /* EXT3_DIRSYNC_FL */
-#define EXT_TOPDIR                     0x00020000 /* EXT3_TOPDIR_FL */
-
-#define EXT_SET_MASK                   0x000300FF
-#define EXT_GET_MASK                   0x0003DFFF
+/* flags for lsattr and chflags commands removed arein uapi/linux/fs.h */
 
 typedef struct file_chattr_info {
        __le64  mask; /* list of all possible attribute bits */
index a3d74fe..ccd31ab 100644 (file)
@@ -463,7 +463,6 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
                               cifs_max_pending);
        set_credits(server, server->maxReq);
        server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
-       server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
        /* even though we do not use raw we might as well set this
        accurately, in case we ever find a need for it */
        if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
@@ -3089,7 +3088,8 @@ CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
        bool is_unicode;
        unsigned int sub_len;
        char *sub_start;
-       struct reparse_data *reparse_buf;
+       struct reparse_symlink_data *reparse_buf;
+       struct reparse_posix_data *posix_buf;
        __u32 data_offset, data_count;
        char *end_of_smb;
 
@@ -3138,20 +3138,47 @@ CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
                goto qreparse_out;
        }
        end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
-       reparse_buf = (struct reparse_data *)
+       reparse_buf = (struct reparse_symlink_data *)
                                ((char *)&pSMBr->hdr.Protocol + data_offset);
        if ((char *)reparse_buf >= end_of_smb) {
                rc = -EIO;
                goto qreparse_out;
        }
-       if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset +
-                               reparse_buf->PrintNameLength) > end_of_smb) {
+       if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
+               cifs_dbg(FYI, "NFS style reparse tag\n");
+               posix_buf =  (struct reparse_posix_data *)reparse_buf;
+
+               if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
+                       cifs_dbg(FYI, "unsupported file type 0x%llx\n",
+                                le64_to_cpu(posix_buf->InodeType));
+                       rc = -EOPNOTSUPP;
+                       goto qreparse_out;
+               }
+               is_unicode = true;
+               sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
+               if (posix_buf->PathBuffer + sub_len > end_of_smb) {
+                       cifs_dbg(FYI, "reparse buf beyond SMB\n");
+                       rc = -EIO;
+                       goto qreparse_out;
+               }
+               *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
+                               sub_len, is_unicode, nls_codepage);
+               goto qreparse_out;
+       } else if (reparse_buf->ReparseTag !=
+                       cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
+               rc = -EOPNOTSUPP;
+               goto qreparse_out;
+       }
+
+       /* Reparse tag is NTFS symlink */
+       sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
+                               reparse_buf->PathBuffer;
+       sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
+       if (sub_start + sub_len > end_of_smb) {
                cifs_dbg(FYI, "reparse buf beyond SMB\n");
                rc = -EIO;
                goto qreparse_out;
        }
-       sub_start = reparse_buf->SubstituteNameOffset + reparse_buf->PathBuffer;
-       sub_len = reparse_buf->SubstituteNameLength;
        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
                is_unicode = true;
        else
index eb955b5..7ddddf2 100644 (file)
@@ -3254,6 +3254,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
        /*
         * Reads as many pages as possible from fscache. Returns -ENOBUFS
         * immediately if the cookie is negative
+        *
+        * After this point, every page in the list might have PG_fscache set,
+        * so we will need to clean that up off of every page we don't use.
         */
        rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
                                         &num_pages);
@@ -3376,6 +3379,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                kref_put(&rdata->refcount, cifs_readdata_release);
        }
 
+       /* Any pages that have been shown to fscache but didn't get added to
+        * the pagecache must be uncached before they get returned to the
+        * allocator.
+        */
+       cifs_fscache_readpages_cancel(mapping->host, page_list);
        return rc;
 }
 
index 2f4bc5a..b3258f3 100644 (file)
@@ -223,6 +223,13 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
                fscache_uncache_page(CIFS_I(inode)->fscache, page);
 }
 
+void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages)
+{
+       cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n",
+                __func__, CIFS_I(inode)->fscache, inode);
+       fscache_readpages_cancel(CIFS_I(inode)->fscache, pages);
+}
+
 void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
 {
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
index 6353932..24794b6 100644 (file)
@@ -54,6 +54,7 @@ extern int __cifs_readpages_from_fscache(struct inode *,
                                         struct address_space *,
                                         struct list_head *,
                                         unsigned *);
+extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *);
 
 extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
 
@@ -91,6 +92,13 @@ static inline void cifs_readpage_to_fscache(struct inode *inode,
                __cifs_readpage_to_fscache(inode, page);
 }
 
+static inline void cifs_fscache_readpages_cancel(struct inode *inode,
+                                                struct list_head *pages)
+{
+       if (CIFS_I(inode)->fscache)
+               return __cifs_fscache_readpages_cancel(inode, pages);
+}
+
 #else /* CONFIG_CIFS_FSCACHE */
 static inline int cifs_fscache_register(void) { return 0; }
 static inline void cifs_fscache_unregister(void) {}
@@ -131,6 +139,11 @@ static inline int cifs_readpages_from_fscache(struct inode *inode,
 static inline void cifs_readpage_to_fscache(struct inode *inode,
                        struct page *page) {}
 
+static inline void cifs_fscache_readpages_cancel(struct inode *inode,
+                                                struct list_head *pages)
+{
+}
+
 #endif /* CONFIG_CIFS_FSCACHE */
 
 #endif /* _CIFS_FSCACHE_H */
index f9ff9c1..867b7cd 100644 (file)
@@ -120,6 +120,33 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
        cifs_i->invalid_mapping = true;
 }
 
+/*
+ * copy nlink to the inode, unless it wasn't provided.  Provide
+ * sane values if we don't have an existing one and none was provided
+ */
+static void
+cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
+{
+       /*
+        * if we're in a situation where we can't trust what we
+        * got from the server (readdir, some non-unix cases)
+        * fake reasonable values
+        */
+       if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) {
+               /* only provide fake values on a new inode */
+               if (inode->i_state & I_NEW) {
+                       if (fattr->cf_cifsattrs & ATTR_DIRECTORY)
+                               set_nlink(inode, 2);
+                       else
+                               set_nlink(inode, 1);
+               }
+               return;
+       }
+
+       /* we trust the server, so update it */
+       set_nlink(inode, fattr->cf_nlink);
+}
+
 /* populate an inode with info from a cifs_fattr struct */
 void
 cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
@@ -134,7 +161,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
        inode->i_mtime = fattr->cf_mtime;
        inode->i_ctime = fattr->cf_ctime;
        inode->i_rdev = fattr->cf_rdev;
-       set_nlink(inode, fattr->cf_nlink);
+       cifs_nlink_fattr_to_inode(inode, fattr);
        inode->i_uid = fattr->cf_uid;
        inode->i_gid = fattr->cf_gid;
 
@@ -541,6 +568,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
        fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
        fattr->cf_createtime = le64_to_cpu(info->CreationTime);
 
+       fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
        if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
                fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
                fattr->cf_dtype = DT_DIR;
@@ -548,7 +576,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                 * Server can return wrong NumberOfLinks value for directories
                 * when Unix extensions are disabled - fake it.
                 */
-               fattr->cf_nlink = 2;
+               if (!tcon->unix_ext)
+                       fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
        } else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
                fattr->cf_mode = S_IFLNK;
                fattr->cf_dtype = DT_LNK;
@@ -561,11 +590,15 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                if (fattr->cf_cifsattrs & ATTR_READONLY)
                        fattr->cf_mode &= ~(S_IWUGO);
 
-               fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
-               if (fattr->cf_nlink < 1) {
-                       cifs_dbg(1, "replacing bogus file nlink value %u\n",
+               /*
+                * Don't accept zero nlink from non-unix servers unless
+                * delete is pending.  Instead mark it as unknown.
+                */
+               if ((fattr->cf_nlink < 1) && !tcon->unix_ext &&
+                   !info->DeletePending) {
+                       cifs_dbg(1, "bogus file nlink value %u\n",
                                fattr->cf_nlink);
-                       fattr->cf_nlink = 1;
+                       fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
                }
        }
 
index af847e1..651a527 100644 (file)
@@ -780,7 +780,9 @@ static const struct {
        ERRDOS, ERRnoaccess, 0xc0000290}, {
        ERRDOS, ERRbadfunc, 0xc000029c}, {
        ERRDOS, ERRsymlink, NT_STATUS_STOPPED_ON_SYMLINK}, {
-       ERRDOS, ERRinvlevel, 0x007c0001}, };
+       ERRDOS, ERRinvlevel, 0x007c0001}, {
+       0, 0, 0 }
+};
 
 /*****************************************************************************
  Print an error message from the status code
index 42ef03b..53a75f3 100644 (file)
@@ -180,6 +180,9 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
                fattr->cf_dtype = DT_REG;
        }
 
+       /* non-unix readdir doesn't provide nlink */
+       fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
+
        if (fattr->cf_cifsattrs & ATTR_READONLY)
                fattr->cf_mode &= ~S_IWUGO;
 
index 5f99b7f..e87387d 100644 (file)
 #include <linux/slab.h>
 #include "cifs_spnego.h"
 
-/*
- * Checks if this is the first smb session to be reconnected after
- * the socket has been reestablished (so we know whether to use vc 0).
- * Called while holding the cifs_tcp_ses_lock, so do not block
- */
-static bool is_first_ses_reconnect(struct cifs_ses *ses)
-{
-       struct list_head *tmp;
-       struct cifs_ses *tmp_ses;
-
-       list_for_each(tmp, &ses->server->smb_ses_list) {
-               tmp_ses = list_entry(tmp, struct cifs_ses,
-                                    smb_ses_list);
-               if (tmp_ses->need_reconnect == false)
-                       return false;
-       }
-       /* could not find a session that was already connected,
-          this must be the first one we are reconnecting */
-       return true;
-}
-
-/*
- *     vc number 0 is treated specially by some servers, and should be the
- *      first one we request.  After that we can use vcnumbers up to maxvcs,
- *     one for each smb session (some Windows versions set maxvcs incorrectly
- *     so maxvc=1 can be ignored).  If we have too many vcs, we can reuse
- *     any vc but zero (some servers reset the connection on vcnum zero)
- *
- */
-static __le16 get_next_vcnum(struct cifs_ses *ses)
-{
-       __u16 vcnum = 0;
-       struct list_head *tmp;
-       struct cifs_ses *tmp_ses;
-       __u16 max_vcs = ses->server->max_vcs;
-       __u16 i;
-       int free_vc_found = 0;
-
-       /* Quoting the MS-SMB specification: "Windows-based SMB servers set this
-       field to one but do not enforce this limit, which allows an SMB client
-       to establish more virtual circuits than allowed by this value ... but
-       other server implementations can enforce this limit." */
-       if (max_vcs < 2)
-               max_vcs = 0xFFFF;
-
-       spin_lock(&cifs_tcp_ses_lock);
-       if ((ses->need_reconnect) && is_first_ses_reconnect(ses))
-                       goto get_vc_num_exit;  /* vcnum will be zero */
-       for (i = ses->server->srv_count - 1; i < max_vcs; i++) {
-               if (i == 0) /* this is the only connection, use vc 0 */
-                       break;
-
-               free_vc_found = 1;
-
-               list_for_each(tmp, &ses->server->smb_ses_list) {
-                       tmp_ses = list_entry(tmp, struct cifs_ses,
-                                            smb_ses_list);
-                       if (tmp_ses->vcnum == i) {
-                               free_vc_found = 0;
-                               break; /* found duplicate, try next vcnum */
-                       }
-               }
-               if (free_vc_found)
-                       break; /* we found a vcnumber that will work - use it */
-       }
-
-       if (i == 0)
-               vcnum = 0; /* for most common case, ie if one smb session, use
-                             vc zero.  Also for case when no free vcnum, zero
-                             is safest to send (some clients only send zero) */
-       else if (free_vc_found == 0)
-               vcnum = 1;  /* we can not reuse vc=0 safely, since some servers
-                               reset all uids on that, but 1 is ok. */
-       else
-               vcnum = i;
-       ses->vcnum = vcnum;
-get_vc_num_exit:
-       spin_unlock(&cifs_tcp_ses_lock);
-
-       return cpu_to_le16(vcnum);
-}
-
 static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
 {
        __u32 capabilities = 0;
@@ -128,7 +46,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
                                        CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4,
                                        USHRT_MAX));
        pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
-       pSMB->req.VcNumber = get_next_vcnum(ses);
+       pSMB->req.VcNumber = __constant_cpu_to_le16(1);
 
        /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
 
@@ -582,9 +500,9 @@ select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
                                return NTLMv2;
                        if (global_secflags & CIFSSEC_MAY_NTLM)
                                return NTLM;
-                       /* Fallthrough */
                default:
-                       return Unspecified;
+                       /* Fallthrough to attempt LANMAN authentication next */
+                       break;
                }
        case CIFS_NEGFLAVOR_LANMAN:
                switch (requested) {
index eba0efd..edccb52 100644 (file)
@@ -687,6 +687,10 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
        else
                return -EIO;
 
+       /* no need to send SMB logoff if uid already closed due to reconnect */
+       if (ses->need_reconnect)
+               goto smb2_session_already_dead;
+
        rc = small_smb2_init(SMB2_LOGOFF, NULL, (void **) &req);
        if (rc)
                return rc;
@@ -701,6 +705,8 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
         * No tcon so can't do
         * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
         */
+
+smb2_session_already_dead:
        return rc;
 }
 
index d952ee4..a4b2391 100644 (file)
 #define FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC /* BB add struct */
 #define FSCTL_SRV_READ_HASH          0x001441BB /* BB add struct */
 
+/* See FSCC 2.1.2.5 */
 #define IO_REPARSE_TAG_MOUNT_POINT   0xA0000003
 #define IO_REPARSE_TAG_HSM           0xC0000004
 #define IO_REPARSE_TAG_SIS           0x80000007
+#define IO_REPARSE_TAG_HSM2          0x80000006
+#define IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005
+/* Used by the DFS filter. See MS-DFSC */
+#define IO_REPARSE_TAG_DFS           0x8000000A
+/* Used by the DFS filter See MS-DFSC */
+#define IO_REPARSE_TAG_DFSR          0x80000012
+#define IO_REPARSE_TAG_FILTER_MANAGER 0x8000000B
+/* See section MS-FSCC 2.1.2.4 */
+#define IO_REPARSE_TAG_SYMLINK       0xA000000C
+#define IO_REPARSE_TAG_DEDUP         0x80000013
+#define IO_REPARSE_APPXSTREAM       0xC0000014
+/* NFS symlinks, Win 8/SMB3 and later */
+#define IO_REPARSE_TAG_NFS           0x80000014
 
 /* fsctl flags */
 /* If Flags is set to this value, the request is an FSCTL not ioctl request */
index 6fdcb1b..800b938 100644 (file)
@@ -410,8 +410,13 @@ static int
 wait_for_free_request(struct TCP_Server_Info *server, const int timeout,
                      const int optype)
 {
-       return wait_for_free_credits(server, timeout,
-                               server->ops->get_credits_field(server, optype));
+       int *val;
+
+       val = server->ops->get_credits_field(server, optype);
+       /* Since an echo is already inflight, no need to wait to send another */
+       if (*val <= 0 && optype == CIFS_ECHO_OP)
+               return -EAGAIN;
+       return wait_for_free_credits(server, timeout, val);
 }
 
 static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
index 4100030..ae6ebb8 100644 (file)
@@ -542,7 +542,7 @@ EXPORT_SYMBOL(d_drop);
  * If ref is non-zero, then decrement the refcount too.
  * Returns dentry requiring refcount drop, or NULL if we're done.
  */
-static inline struct dentry *
+static struct dentry *
 dentry_kill(struct dentry *dentry, int unlock_on_failure)
        __releases(dentry->d_lock)
 {
@@ -630,7 +630,8 @@ repeat:
                        goto kill_it;
        }
 
-       dentry->d_flags |= DCACHE_REFERENCED;
+       if (!(dentry->d_flags & DCACHE_REFERENCED))
+               dentry->d_flags |= DCACHE_REFERENCED;
        dentry_lru_add(dentry);
 
        dentry->d_lockref.count--;
@@ -1331,14 +1332,6 @@ rename_retry:
  * list is non-empty and continue searching.
  */
 
-/**
- * have_submounts - check for mounts over a dentry
- * @parent: dentry to check.
- *
- * Return true if the parent or its subdirectories contain
- * a mount point
- */
-
 static enum d_walk_ret check_mount(void *data, struct dentry *dentry)
 {
        int *ret = data;
@@ -1349,6 +1342,13 @@ static enum d_walk_ret check_mount(void *data, struct dentry *dentry)
        return D_WALK_CONTINUE;
 }
 
+/**
+ * have_submounts - check for mounts over a dentry
+ * @parent: dentry to check.
+ *
+ * Return true if the parent or its subdirectories contain
+ * a mount point
+ */
 int have_submounts(struct dentry *parent)
 {
        int ret = 0;
index c88e355..000eae2 100644 (file)
@@ -408,7 +408,7 @@ static loff_t lower_offset_for_page(struct ecryptfs_crypt_stat *crypt_stat,
                                    struct page *page)
 {
        return ecryptfs_lower_header_size(crypt_stat) +
-              (page->index << PAGE_CACHE_SHIFT);
+              ((loff_t)page->index << PAGE_CACHE_SHIFT);
 }
 
 /**
index 7d52806..4725a07 100644 (file)
@@ -1149,7 +1149,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
        struct ecryptfs_msg_ctx *msg_ctx;
        struct ecryptfs_message *msg = NULL;
        char *auth_tok_sig;
-       char *payload;
+       char *payload = NULL;
        size_t payload_len = 0;
        int rc;
 
@@ -1203,6 +1203,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
        }
 out:
        kfree(msg);
+       kfree(payload);
        return rc;
 }
 
index 473e09d..810c28f 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/mutex.h>
 #include <linux/anon_inodes.h>
 #include <linux/device.h>
-#include <linux/freezer.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/mman.h>
@@ -1605,8 +1604,7 @@ fetch_events:
                        }
 
                        spin_unlock_irqrestore(&ep->lock, flags);
-                       if (!freezable_schedule_hrtimeout_range(to, slack,
-                                                               HRTIMER_MODE_ABS))
+                       if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
                                timed_out = 1;
 
                        spin_lock_irqsave(&ep->lock, flags);
index 1194b1f..f8cde46 100644 (file)
@@ -1783,7 +1783,7 @@ retry:
                d_tmpfile(dentry, inode);
                err = ext3_orphan_add(handle, inode);
                if (err)
-                       goto err_drop_inode;
+                       goto err_unlock_inode;
                mark_inode_dirty(inode);
                unlock_new_inode(inode);
        }
@@ -1791,10 +1791,9 @@ retry:
        if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
        return err;
-err_drop_inode:
+err_unlock_inode:
        ext3_journal_stop(handle);
        unlock_new_inode(inode);
-       iput(inode);
        return err;
 }
 
index 0d424d7..e274e9c 100644 (file)
@@ -2563,7 +2563,7 @@ retry:
                        break;
        }
        blk_finish_plug(&plug);
-       if (!ret && !cycled) {
+       if (!ret && !cycled && wbc->nr_to_write > 0) {
                cycled = 1;
                mpd.last_page = writeback_index - 1;
                mpd.first_page = 0;
index 1bec5a5..5a0408d 100644 (file)
@@ -2319,7 +2319,7 @@ retry:
                d_tmpfile(dentry, inode);
                err = ext4_orphan_add(handle, inode);
                if (err)
-                       goto err_drop_inode;
+                       goto err_unlock_inode;
                mark_inode_dirty(inode);
                unlock_new_inode(inode);
        }
@@ -2328,10 +2328,9 @@ retry:
        if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
        return err;
-err_drop_inode:
+err_unlock_inode:
        ext4_journal_stop(handle);
        unlock_new_inode(inode);
-       iput(inode);
        return err;
 }
 
index c081e34..03e9beb 100644 (file)
@@ -1350,6 +1350,8 @@ retry:
                                    s_min_extra_isize) {
                                        tried_min_extra_isize++;
                                        new_extra_isize = s_min_extra_isize;
+                                       kfree(is); is = NULL;
+                                       kfree(bs); bs = NULL;
                                        goto retry;
                                }
                                error = -1;
index abdd15a..e900ca5 100644 (file)
@@ -297,7 +297,7 @@ void flush_delayed_fput(void)
        delayed_fput(NULL);
 }
 
-static DECLARE_WORK(delayed_fput_work, delayed_fput);
+static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput);
 
 void fput(struct file *file)
 {
@@ -317,7 +317,7 @@ void fput(struct file *file)
                }
 
                if (llist_add(&file->f_u.fu_llist, &delayed_fput_list))
-                       schedule_work(&delayed_fput_work);
+                       schedule_delayed_work(&delayed_fput_work, 1);
        }
 }
 
index 62b43b5..b7989f2 100644 (file)
@@ -182,6 +182,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
        struct inode *inode;
        struct dentry *parent;
        struct fuse_conn *fc;
+       struct fuse_inode *fi;
        int ret;
 
        inode = ACCESS_ONCE(entry->d_inode);
@@ -228,7 +229,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
                if (!err && !outarg.nodeid)
                        err = -ENOENT;
                if (!err) {
-                       struct fuse_inode *fi = get_fuse_inode(inode);
+                       fi = get_fuse_inode(inode);
                        if (outarg.nodeid != get_node_id(inode)) {
                                fuse_queue_forget(fc, forget, outarg.nodeid, 1);
                                goto invalid;
@@ -246,8 +247,11 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
                                       attr_version);
                fuse_change_entry_timeout(entry, &outarg);
        } else if (inode) {
-               fc = get_fuse_conn(inode);
-               if (fc->readdirplus_auto) {
+               fi = get_fuse_inode(inode);
+               if (flags & LOOKUP_RCU) {
+                       if (test_bit(FUSE_I_INIT_RDPLUS, &fi->state))
+                               return -ECHILD;
+               } else if (test_and_clear_bit(FUSE_I_INIT_RDPLUS, &fi->state)) {
                        parent = dget_parent(entry);
                        fuse_advise_use_readdirplus(parent->d_inode);
                        dput(parent);
@@ -259,7 +263,8 @@ out:
 
 invalid:
        ret = 0;
-       if (check_submounts_and_drop(entry) != 0)
+
+       if (!(flags & LOOKUP_RCU) && check_submounts_and_drop(entry) != 0)
                ret = 1;
        goto out;
 }
@@ -1063,6 +1068,8 @@ static int fuse_access(struct inode *inode, int mask)
        struct fuse_access_in inarg;
        int err;
 
+       BUG_ON(mask & MAY_NOT_BLOCK);
+
        if (fc->no_access)
                return 0;
 
@@ -1150,9 +1157,6 @@ static int fuse_permission(struct inode *inode, int mask)
                   noticed immediately, only after the attribute
                   timeout has expired */
        } else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
-               if (mask & MAY_NOT_BLOCK)
-                       return -ECHILD;
-
                err = fuse_access(inode, mask);
        } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
                if (!(inode->i_mode & S_IXUGO)) {
@@ -1291,6 +1295,8 @@ static int fuse_direntplus_link(struct file *file,
        }
 
 found:
+       if (fc->readdirplus_auto)
+               set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state);
        fuse_change_entry_timeout(dentry, o);
 
        err = 0;
index d409dea..4598345 100644 (file)
@@ -2467,6 +2467,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
 {
        struct fuse_file *ff = file->private_data;
        struct inode *inode = file->f_inode;
+       struct fuse_inode *fi = get_fuse_inode(inode);
        struct fuse_conn *fc = ff->fc;
        struct fuse_req *req;
        struct fuse_fallocate_in inarg = {
@@ -2484,10 +2485,20 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
 
        if (lock_inode) {
                mutex_lock(&inode->i_mutex);
-               if (mode & FALLOC_FL_PUNCH_HOLE)
-                       fuse_set_nowrite(inode);
+               if (mode & FALLOC_FL_PUNCH_HOLE) {
+                       loff_t endbyte = offset + length - 1;
+                       err = filemap_write_and_wait_range(inode->i_mapping,
+                                                          offset, endbyte);
+                       if (err)
+                               goto out;
+
+                       fuse_sync_writes(inode);
+               }
        }
 
+       if (!(mode & FALLOC_FL_KEEP_SIZE))
+               set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
+
        req = fuse_get_req_nopages(fc);
        if (IS_ERR(req)) {
                err = PTR_ERR(req);
@@ -2520,11 +2531,11 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
        fuse_invalidate_attr(inode);
 
 out:
-       if (lock_inode) {
-               if (mode & FALLOC_FL_PUNCH_HOLE)
-                       fuse_release_nowrite(inode);
+       if (!(mode & FALLOC_FL_KEEP_SIZE))
+               clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
+
+       if (lock_inode)
                mutex_unlock(&inode->i_mutex);
-       }
 
        return err;
 }
index 5ced199..5b9e6f3 100644 (file)
@@ -115,6 +115,8 @@ struct fuse_inode {
 enum {
        /** Advise readdirplus  */
        FUSE_I_ADVISE_RDPLUS,
+       /** Initialized with readdirplus */
+       FUSE_I_INIT_RDPLUS,
        /** An operation changing file size is in progress  */
        FUSE_I_SIZE_UNSTABLE,
 };
index c1a3e60..7f464c5 100644 (file)
@@ -95,7 +95,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
 
        if (insert_inode_locked(inode) < 0) {
                rc = -EINVAL;
-               goto fail_unlock;
+               goto fail_put;
        }
 
        inode_init_owner(inode, parent, mode);
@@ -156,7 +156,6 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
 fail_drop:
        dquot_drop(inode);
        inode->i_flags |= S_NOQUOTA;
-fail_unlock:
        clear_nlink(inode);
        unlock_new_inode(inode);
 fail_put:
index 645268f..caa2805 100644 (file)
@@ -2294,10 +2294,11 @@ out:
  * path_mountpoint - look up a path to be umounted
  * @dfd:       directory file descriptor to start walk from
  * @name:      full pathname to walk
+ * @path:      pointer to container for result
  * @flags:     lookup flags
  *
  * Look up the given name, but don't attempt to revalidate the last component.
- * Returns 0 and "path" will be valid on success; Retuns error otherwise.
+ * Returns 0 and "path" will be valid on success; Returns error otherwise.
  */
 static int
 path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags)
index 854a8f0..02b0df7 100644 (file)
@@ -1458,7 +1458,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
 
        trace_nfs_atomic_open_enter(dir, ctx, open_flags);
        nfs_block_sillyrename(dentry->d_parent);
-       inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
+       inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr, opened);
        nfs_unblock_sillyrename(dentry->d_parent);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
index e5b804d..77efaf1 100644 (file)
@@ -19,6 +19,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
        struct inode *dir;
        unsigned openflags = filp->f_flags;
        struct iattr attr;
+       int opened = 0;
        int err;
 
        /*
@@ -55,7 +56,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
                nfs_wb_all(inode);
        }
 
-       inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
+       inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, &opened);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                switch (err) {
index 95604f6..c7c295e 100644 (file)
@@ -185,6 +185,7 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
        if (status)
                goto out_put;
 
+       smp_wmb();
        ds->ds_clp = clp;
        dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
 out:
@@ -801,34 +802,35 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
        struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
        struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
        struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
-
-       if (filelayout_test_devid_unavailable(devid))
-               return NULL;
+       struct nfs4_pnfs_ds *ret = ds;
 
        if (ds == NULL) {
                printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
                        __func__, ds_idx);
                filelayout_mark_devid_invalid(devid);
-               return NULL;
+               goto out;
        }
+       smp_rmb();
        if (ds->ds_clp)
-               return ds;
+               goto out_test_devid;
 
        if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) {
                struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
                int err;
 
                err = nfs4_ds_connect(s, ds);
-               if (err) {
+               if (err)
                        nfs4_mark_deviceid_unavailable(devid);
-                       ds = NULL;
-               }
                nfs4_clear_ds_conn_bit(ds);
        } else {
                /* Either ds is connected, or ds is NULL */
                nfs4_wait_ds_connect(ds);
        }
-       return ds;
+out_test_devid:
+       if (filelayout_test_devid_unavailable(devid))
+               ret = NULL;
+out:
+       return ret;
 }
 
 module_param(dataserver_retrans, uint, 0644);
index 989bb9d..d53d678 100644 (file)
@@ -912,6 +912,7 @@ struct nfs4_opendata {
        struct iattr attrs;
        unsigned long timestamp;
        unsigned int rpc_done : 1;
+       unsigned int file_created : 1;
        unsigned int is_recover : 1;
        int rpc_status;
        int cancelled;
@@ -1946,8 +1947,13 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
 
        nfs_fattr_map_and_free_names(server, &data->f_attr);
 
-       if (o_arg->open_flags & O_CREAT)
+       if (o_arg->open_flags & O_CREAT) {
                update_changeattr(dir, &o_res->cinfo);
+               if (o_arg->open_flags & O_EXCL)
+                       data->file_created = 1;
+               else if (o_res->cinfo.before != o_res->cinfo.after)
+                       data->file_created = 1;
+       }
        if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
                server->caps &= ~NFS_CAP_POSIX_LOCK;
        if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
@@ -2191,7 +2197,8 @@ static int _nfs4_do_open(struct inode *dir,
                        struct nfs_open_context *ctx,
                        int flags,
                        struct iattr *sattr,
-                       struct nfs4_label *label)
+                       struct nfs4_label *label,
+                       int *opened)
 {
        struct nfs4_state_owner  *sp;
        struct nfs4_state     *state = NULL;
@@ -2261,6 +2268,8 @@ static int _nfs4_do_open(struct inode *dir,
                        nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
                }
        }
+       if (opendata->file_created)
+               *opened |= FILE_CREATED;
 
        if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
                *ctx_th = opendata->f_attr.mdsthreshold;
@@ -2289,7 +2298,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
                                        struct nfs_open_context *ctx,
                                        int flags,
                                        struct iattr *sattr,
-                                       struct nfs4_label *label)
+                                       struct nfs4_label *label,
+                                       int *opened)
 {
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs4_exception exception = { };
@@ -2297,7 +2307,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
        int status;
 
        do {
-               status = _nfs4_do_open(dir, ctx, flags, sattr, label);
+               status = _nfs4_do_open(dir, ctx, flags, sattr, label, opened);
                res = ctx->state;
                trace_nfs4_open_file(ctx, flags, status);
                if (status == 0)
@@ -2659,7 +2669,8 @@ out:
 }
 
 static struct inode *
-nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
+nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
+               int open_flags, struct iattr *attr, int *opened)
 {
        struct nfs4_state *state;
        struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL;
@@ -2667,7 +2678,7 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags
        label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
 
        /* Protect against concurrent sillydeletes */
-       state = nfs4_do_open(dir, ctx, open_flags, attr, label);
+       state = nfs4_do_open(dir, ctx, open_flags, attr, label, opened);
 
        nfs4_label_release_security(label);
 
@@ -3332,6 +3343,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        struct nfs4_label l, *ilabel = NULL;
        struct nfs_open_context *ctx;
        struct nfs4_state *state;
+       int opened = 0;
        int status = 0;
 
        ctx = alloc_nfs_open_context(dentry, FMODE_READ);
@@ -3341,7 +3353,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
 
        sattr->ia_mode &= ~current_umask();
-       state = nfs4_do_open(dir, ctx, flags, sattr, ilabel);
+       state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, &opened);
        if (IS_ERR(state)) {
                status = PTR_ERR(state);
                goto out;
@@ -7564,8 +7576,10 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 {
        int err;
        struct page *page;
-       rpc_authflavor_t flavor;
+       rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
        struct nfs4_secinfo_flavors *flavors;
+       struct nfs4_secinfo4 *secinfo;
+       int i;
 
        page = alloc_page(GFP_KERNEL);
        if (!page) {
@@ -7587,9 +7601,31 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        if (err)
                goto out_freepage;
 
-       flavor = nfs_find_best_sec(flavors);
-       if (err == 0)
-               err = nfs4_lookup_root_sec(server, fhandle, info, flavor);
+       for (i = 0; i < flavors->num_flavors; i++) {
+               secinfo = &flavors->flavors[i];
+
+               switch (secinfo->flavor) {
+               case RPC_AUTH_NULL:
+               case RPC_AUTH_UNIX:
+               case RPC_AUTH_GSS:
+                       flavor = rpcauth_get_pseudoflavor(secinfo->flavor,
+                                       &secinfo->flavor_info);
+                       break;
+               default:
+                       flavor = RPC_AUTH_MAXFLAVOR;
+                       break;
+               }
+
+               if (flavor != RPC_AUTH_MAXFLAVOR) {
+                       err = nfs4_lookup_root_sec(server, fhandle,
+                                                  info, flavor);
+                       if (!err)
+                               break;
+               }
+       }
+
+       if (flavor == RPC_AUTH_MAXFLAVOR)
+               err = -EPERM;
 
 out_freepage:
        put_page(page);
index 0ba6798..da27664 100644 (file)
@@ -94,6 +94,7 @@ void nilfs_forget_buffer(struct buffer_head *bh)
        clear_buffer_nilfs_volatile(bh);
        clear_buffer_nilfs_checked(bh);
        clear_buffer_nilfs_redirected(bh);
+       clear_buffer_async_write(bh);
        clear_buffer_dirty(bh);
        if (nilfs_page_buffers_clean(page))
                __nilfs_clear_page_dirty(page);
@@ -429,6 +430,7 @@ void nilfs_clear_dirty_page(struct page *page, bool silent)
                                        "discard block %llu, size %zu",
                                        (u64)bh->b_blocknr, bh->b_size);
                        }
+                       clear_buffer_async_write(bh);
                        clear_buffer_dirty(bh);
                        clear_buffer_nilfs_volatile(bh);
                        clear_buffer_nilfs_checked(bh);
index bd88a74..9f6b486 100644 (file)
@@ -665,7 +665,7 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode,
 
                bh = head = page_buffers(page);
                do {
-                       if (!buffer_dirty(bh))
+                       if (!buffer_dirty(bh) || buffer_async_write(bh))
                                continue;
                        get_bh(bh);
                        list_add_tail(&bh->b_assoc_buffers, listp);
@@ -699,7 +699,8 @@ static void nilfs_lookup_dirty_node_buffers(struct inode *inode,
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        bh = head = page_buffers(pvec.pages[i]);
                        do {
-                               if (buffer_dirty(bh)) {
+                               if (buffer_dirty(bh) &&
+                                               !buffer_async_write(bh)) {
                                        get_bh(bh);
                                        list_add_tail(&bh->b_assoc_buffers,
                                                      listp);
@@ -1579,6 +1580,7 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci)
 
                list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
                                    b_assoc_buffers) {
+                       set_buffer_async_write(bh);
                        if (bh->b_page != bd_page) {
                                if (bd_page) {
                                        lock_page(bd_page);
@@ -1592,6 +1594,7 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci)
 
                list_for_each_entry(bh, &segbuf->sb_payload_buffers,
                                    b_assoc_buffers) {
+                       set_buffer_async_write(bh);
                        if (bh == segbuf->sb_super_root) {
                                if (bh->b_page != bd_page) {
                                        lock_page(bd_page);
@@ -1677,6 +1680,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err)
        list_for_each_entry(segbuf, logs, sb_list) {
                list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
                                    b_assoc_buffers) {
+                       clear_buffer_async_write(bh);
                        if (bh->b_page != bd_page) {
                                if (bd_page)
                                        end_page_writeback(bd_page);
@@ -1686,6 +1690,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err)
 
                list_for_each_entry(bh, &segbuf->sb_payload_buffers,
                                    b_assoc_buffers) {
+                       clear_buffer_async_write(bh);
                        if (bh == segbuf->sb_super_root) {
                                if (bh->b_page != bd_page) {
                                        end_page_writeback(bd_page);
@@ -1755,6 +1760,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
                                    b_assoc_buffers) {
                        set_buffer_uptodate(bh);
                        clear_buffer_dirty(bh);
+                       clear_buffer_async_write(bh);
                        if (bh->b_page != bd_page) {
                                if (bd_page)
                                        end_page_writeback(bd_page);
@@ -1776,6 +1782,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
                                    b_assoc_buffers) {
                        set_buffer_uptodate(bh);
                        clear_buffer_dirty(bh);
+                       clear_buffer_async_write(bh);
                        clear_buffer_delay(bh);
                        clear_buffer_nilfs_volatile(bh);
                        clear_buffer_nilfs_redirected(bh);
index ef99972..0d3a97d 100644 (file)
@@ -70,9 +70,10 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry, unsigned int flags)
         */
        if (inode == NULL) {
                unsigned long gen = (unsigned long) dentry->d_fsdata;
-               unsigned long pgen =
-                       OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen;
-
+               unsigned long pgen;
+               spin_lock(&dentry->d_lock);
+               pgen = OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen;
+               spin_unlock(&dentry->d_lock);
                trace_ocfs2_dentry_revalidate_negative(dentry->d_name.len,
                                                       dentry->d_name.name,
                                                       pgen, gen);
index 9f8ef9b..8eaa1ba 100644 (file)
@@ -288,10 +288,14 @@ static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
 static unsigned long proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
        struct proc_dir_entry *pde = PDE(file_inode(file));
-       int rv = -EIO;
-       unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+       unsigned long rv = -EIO;
+       unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long) = NULL;
        if (use_pde(pde)) {
-               get_unmapped_area = pde->proc_fops->get_unmapped_area;
+#ifdef CONFIG_MMU
+               get_unmapped_area = current->mm->get_unmapped_area;
+#endif
+               if (pde->proc_fops->get_unmapped_area)
+                       get_unmapped_area = pde->proc_fops->get_unmapped_area;
                if (get_unmapped_area)
                        rv = get_unmapped_area(file, orig_addr, len, pgoff, flags);
                unuse_pde(pde);
index 7366e9d..390bdab 100644 (file)
@@ -941,6 +941,8 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
                frame = pte_pfn(pte);
                flags = PM_PRESENT;
                page = vm_normal_page(vma, addr, pte);
+               if (pte_soft_dirty(pte))
+                       flags2 |= __PM_SOFT_DIRTY;
        } else if (is_swap_pte(pte)) {
                swp_entry_t entry;
                if (pte_swp_soft_dirty(pte))
@@ -960,7 +962,7 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
 
        if (page && !PageAnon(page))
                flags |= PM_FILE;
-       if ((vma->vm_flags & VM_SOFTDIRTY) || pte_soft_dirty(pte))
+       if ((vma->vm_flags & VM_SOFTDIRTY))
                flags2 |= __PM_SOFT_DIRTY;
 
        *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, flags2) | flags);
index 35d4adc..dfd5cb1 100644 (file)
@@ -238,8 +238,7 @@ int poll_schedule_timeout(struct poll_wqueues *pwq, int state,
 
        set_current_state(state);
        if (!pwq->triggered)
-               rc = freezable_schedule_hrtimeout_range(expires, slack,
-                                                       HRTIMER_MODE_ABS);
+               rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS);
        __set_current_state(TASK_RUNNING);
 
        /*
index 3135c25..a290157 100644 (file)
@@ -328,6 +328,8 @@ loff_t seq_lseek(struct file *file, loff_t offset, int whence)
                                m->read_pos = offset;
                                retval = file->f_pos = offset;
                        }
+               } else {
+                       file->f_pos = offset;
                }
        }
        file->f_version = m->version;
index c219e73..083dc0a 100644 (file)
@@ -94,7 +94,7 @@ retry:
 
 int fd_statfs(int fd, struct kstatfs *st)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_raw(fd);
        int error = -EBADF;
        if (f.file) {
                error = vfs_statfs(&f.file->f_path, st);
index 3a96c97..0225c20 100644 (file)
@@ -264,6 +264,8 @@ out_free_sb:
  */
 static inline void destroy_super(struct super_block *s)
 {
+       list_lru_destroy(&s->s_dentry_lru);
+       list_lru_destroy(&s->s_inode_lru);
 #ifdef CONFIG_SMP
        free_percpu(s->s_files);
 #endif
@@ -323,8 +325,6 @@ void deactivate_locked_super(struct super_block *s)
 
                /* caches are now gone, we can safely kill the shrinker now */
                unregister_shrinker(&s->s_shrink);
-               list_lru_destroy(&s->s_dentry_lru);
-               list_lru_destroy(&s->s_inode_lru);
 
                put_filesystem(fs);
                put_super(s);
index d0c6a00..eda1095 100644 (file)
@@ -487,6 +487,7 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_sb = sb;
        sbi->s_block_base = 0;
        sbi->s_type = FSTYPE_V7;
+       mutex_init(&sbi->s_lock);
        sb->s_fs_info = sbi;
        
        sb_set_blocksize(sb, 512);
index 0957aa9..12dad18 100644 (file)
@@ -1158,7 +1158,7 @@ xfs_dir2_sf_to_block(
        /*
         * Create entry for .
         */
-       dep = xfs_dir3_data_dot_entry_p(hdr);
+       dep = xfs_dir3_data_dot_entry_p(mp, hdr);
        dep->inumber = cpu_to_be64(dp->i_ino);
        dep->namelen = 1;
        dep->name[0] = '.';
@@ -1172,7 +1172,7 @@ xfs_dir2_sf_to_block(
        /*
         * Create entry for ..
         */
-       dep = xfs_dir3_data_dotdot_entry_p(hdr);
+       dep = xfs_dir3_data_dotdot_entry_p(mp, hdr);
        dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp));
        dep->namelen = 2;
        dep->name[0] = dep->name[1] = '.';
@@ -1183,7 +1183,7 @@ xfs_dir2_sf_to_block(
        blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
        blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
                                (char *)dep - (char *)hdr));
-       offset = xfs_dir3_data_first_offset(hdr);
+       offset = xfs_dir3_data_first_offset(mp);
        /*
         * Loop over existing entries, stuff them in.
         */
index a0961a6..9cf6738 100644 (file)
@@ -497,69 +497,58 @@ xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr)
 /*
  * Offsets of . and .. in data space (always block 0)
  *
- * The macros are used for shortform directories as they have no headers to read
- * the magic number out of. Shortform directories need to know the size of the
- * data block header because the sfe embeds the block offset of the entry into
- * it so that it doesn't change when format conversion occurs. Bad Things Happen
- * if we don't follow this rule.
- *
  * XXX: there is scope for significant optimisation of the logic here. Right
  * now we are checking for "dir3 format" over and over again. Ideally we should
  * only do it once for each operation.
  */
-#define        XFS_DIR3_DATA_DOT_OFFSET(mp)    \
-       xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&(mp)->m_sb))
-#define        XFS_DIR3_DATA_DOTDOT_OFFSET(mp) \
-       (XFS_DIR3_DATA_DOT_OFFSET(mp) + xfs_dir3_data_entsize(mp, 1))
-#define        XFS_DIR3_DATA_FIRST_OFFSET(mp)          \
-       (XFS_DIR3_DATA_DOTDOT_OFFSET(mp) + xfs_dir3_data_entsize(mp, 2))
-
 static inline xfs_dir2_data_aoff_t
-xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_dot_offset(struct xfs_mount *mp)
 {
-       return xfs_dir3_data_entry_offset(hdr);
+       return xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&mp->m_sb));
 }
 
 static inline xfs_dir2_data_aoff_t
-xfs_dir3_data_dotdot_offset(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_dotdot_offset(struct xfs_mount *mp)
 {
-       bool dir3 = hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
-                   hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
-       return xfs_dir3_data_dot_offset(hdr) +
-               __xfs_dir3_data_entsize(dir3, 1);
+       return xfs_dir3_data_dot_offset(mp) +
+               xfs_dir3_data_entsize(mp, 1);
 }
 
 static inline xfs_dir2_data_aoff_t
-xfs_dir3_data_first_offset(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_first_offset(struct xfs_mount *mp)
 {
-       bool dir3 = hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
-                   hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
-       return xfs_dir3_data_dotdot_offset(hdr) +
-               __xfs_dir3_data_entsize(dir3, 2);
+       return xfs_dir3_data_dotdot_offset(mp) +
+               xfs_dir3_data_entsize(mp, 2);
 }
 
 /*
  * location of . and .. in data space (always block 0)
  */
 static inline struct xfs_dir2_data_entry *
-xfs_dir3_data_dot_entry_p(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_dot_entry_p(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_data_hdr *hdr)
 {
        return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + xfs_dir3_data_dot_offset(hdr));
+               ((char *)hdr + xfs_dir3_data_dot_offset(mp));
 }
 
 static inline struct xfs_dir2_data_entry *
-xfs_dir3_data_dotdot_entry_p(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_dotdot_entry_p(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_data_hdr *hdr)
 {
        return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + xfs_dir3_data_dotdot_offset(hdr));
+               ((char *)hdr + xfs_dir3_data_dotdot_offset(mp));
 }
 
 static inline struct xfs_dir2_data_entry *
-xfs_dir3_data_first_entry_p(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_first_entry_p(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_data_hdr *hdr)
 {
        return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + xfs_dir3_data_first_offset(hdr));
+               ((char *)hdr + xfs_dir3_data_first_offset(mp));
 }
 
 /*
index 8993ec1..8f84153 100644 (file)
@@ -119,9 +119,9 @@ xfs_dir2_sf_getdents(
         * mp->m_dirdatablk.
         */
        dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
-                                            XFS_DIR3_DATA_DOT_OFFSET(mp));
+                                            xfs_dir3_data_dot_offset(mp));
        dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
-                                               XFS_DIR3_DATA_DOTDOT_OFFSET(mp));
+                                               xfs_dir3_data_dotdot_offset(mp));
 
        /*
         * Put . entry unless we're starting past it.
index bb6e284..3ef6d40 100644 (file)
@@ -557,7 +557,7 @@ xfs_dir2_sf_addname_hard(
         * to insert the new entry.
         * If it's going to end up at the end then oldsfep will point there.
         */
-       for (offset = XFS_DIR3_DATA_FIRST_OFFSET(mp),
+       for (offset = xfs_dir3_data_first_offset(mp),
              oldsfep = xfs_dir2_sf_firstentry(oldsfp),
              add_datasize = xfs_dir3_data_entsize(mp, args->namelen),
              eof = (char *)oldsfep == &buf[old_isize];
@@ -640,7 +640,7 @@ xfs_dir2_sf_addname_pick(
 
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
        size = xfs_dir3_data_entsize(mp, args->namelen);
-       offset = XFS_DIR3_DATA_FIRST_OFFSET(mp);
+       offset = xfs_dir3_data_first_offset(mp);
        sfep = xfs_dir2_sf_firstentry(sfp);
        holefit = 0;
        /*
@@ -713,7 +713,7 @@ xfs_dir2_sf_check(
        mp = dp->i_mount;
 
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
-       offset = XFS_DIR3_DATA_FIRST_OFFSET(mp);
+       offset = xfs_dir3_data_first_offset(mp);
        ino = xfs_dir2_sf_get_parent_ino(sfp);
        i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
 
index 71520e6..1ee776d 100644 (file)
@@ -64,7 +64,8 @@ int xfs_dqerror_mod = 33;
 struct kmem_zone               *xfs_qm_dqtrxzone;
 static struct kmem_zone                *xfs_qm_dqzone;
 
-static struct lock_class_key xfs_dquot_other_class;
+static struct lock_class_key xfs_dquot_group_class;
+static struct lock_class_key xfs_dquot_project_class;
 
 /*
  * This is called to free all the memory associated with a dquot
@@ -703,8 +704,20 @@ xfs_qm_dqread(
         * Make sure group quotas have a different lock class than user
         * quotas.
         */
-       if (!(type & XFS_DQ_USER))
-               lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);
+       switch (type) {
+       case XFS_DQ_USER:
+               /* uses the default lock class */
+               break;
+       case XFS_DQ_GROUP:
+               lockdep_set_class(&dqp->q_qlock, &xfs_dquot_group_class);
+               break;
+       case XFS_DQ_PROJ:
+               lockdep_set_class(&dqp->q_qlock, &xfs_dquot_project_class);
+               break;
+       default:
+               ASSERT(0);
+               break;
+       }
 
        XFS_STATS_INC(xs_qm_dquot);
 
index cc17987..3979749 100644 (file)
@@ -1585,6 +1585,7 @@ xlog_recover_add_to_trans(
                "bad number of regions (%d) in inode log format",
                                  in_f->ilf_size);
                        ASSERT(0);
+                       kmem_free(ptr);
                        return XFS_ERROR(EIO);
                }
 
index 02e113b..d901982 100644 (file)
@@ -311,7 +311,6 @@ struct acpi_device {
        unsigned int physical_node_count;
        struct list_head physical_node_list;
        struct mutex physical_node_lock;
-       struct list_head power_dependent;
        void (*remove)(struct acpi_device *);
 };
 
@@ -456,8 +455,6 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
 acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
                                    acpi_notify_handler handler);
 int acpi_pm_device_sleep_state(struct device *, int *, int);
-void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev);
-void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev);
 #else
 static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
                                               acpi_notify_handler handler,
@@ -478,10 +475,6 @@ static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m)
        return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3_COLD) ?
                m : ACPI_STATE_D0;
 }
-static inline void acpi_dev_pm_add_dependent(acpi_handle handle,
-                                            struct device *depdev) {}
-static inline void acpi_dev_pm_remove_dependent(acpi_handle handle,
-                                               struct device *depdev) {}
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
index d06079c..99b490b 100644 (file)
@@ -6,12 +6,12 @@ static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot)
        return mk_pte(page, pgprot);
 }
 
-static inline int huge_pte_write(pte_t pte)
+static inline unsigned long huge_pte_write(pte_t pte)
 {
        return pte_write(pte);
 }
 
-static inline int huge_pte_dirty(pte_t pte)
+static inline unsigned long huge_pte_dirty(pte_t pte)
 {
        return pte_dirty(pte);
 }
index e69de29..b1a4967 100644 (file)
@@ -0,0 +1 @@
+/* no content, but patch(1) dislikes empty files */
index 3d79e51..87578c1 100644 (file)
        {0x1002, 0x679B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x679E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x679F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67A8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67A9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67AA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67B0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67B8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67B9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67BA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x67BE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
index 3abfa6e..97d5497 100644 (file)
@@ -49,6 +49,10 @@ extern bool i915_gpu_turbo_disable(void);
 #define    SNB_GMCH_GGMS_MASK  0x3
 #define    SNB_GMCH_GMS_SHIFT   3 /* Graphics Mode Select */
 #define    SNB_GMCH_GMS_MASK    0x1f
+#define    BDW_GMCH_GGMS_SHIFT 6
+#define    BDW_GMCH_GGMS_MASK  0x3
+#define    BDW_GMCH_GMS_SHIFT   8
+#define    BDW_GMCH_GMS_MASK    0xff
 
 #define I830_GMCH_CTRL                 0x52
 
index 8a10f5c..940ece4 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_M_IDS(info) \
+       _INTEL_BDW_M_IDS(1, info), \
+       _INTEL_BDW_M_IDS(2, info), \
+       _INTEL_BDW_M_IDS(3, info)
+
+#define INTEL_BDW_D_IDS(info) \
+       _INTEL_BDW_D_IDS(1, info), \
+       _INTEL_BDW_D_IDS(2, info), \
+       _INTEL_BDW_D_IDS(3, info)
+
 #endif /* _I915_PCIIDS_H */
index 706b962..d1f61bf 100644 (file)
@@ -62,7 +62,7 @@ extern void ttm_pool_unpopulate(struct ttm_tt *ttm);
 extern int ttm_page_alloc_debugfs(struct seq_file *m, void *data);
 
 
-#ifdef CONFIG_SWIOTLB
+#if defined(CONFIG_SWIOTLB) || defined(CONFIG_INTEL_IOMMU)
 /**
  * Initialize pool allocator.
  */
@@ -94,6 +94,15 @@ static inline int ttm_dma_page_alloc_debugfs(struct seq_file *m, void *data)
 {
        return 0;
 }
+static inline int ttm_dma_populate(struct ttm_dma_tt *ttm_dma,
+                                  struct device *dev)
+{
+       return -ENOMEM;
+}
+static inline void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma,
+                                     struct device *dev)
+{
+}
 #endif
 
 #endif
index edbd250..bed35e3 100644 (file)
@@ -23,7 +23,7 @@
 #define PULL_UP                        (1 << 4)
 #define ALTELECTRICALSEL       (1 << 5)
 
-/* 34xx specific mux bit defines */
+/* omap3/4/5 specific mux bit defines */
 #define INPUT_EN               (1 << 8)
 #define OFF_EN                 (1 << 9)
 #define OFFOUT_EN              (1 << 10)
@@ -31,8 +31,6 @@
 #define OFF_PULL_EN            (1 << 12)
 #define OFF_PULL_UP            (1 << 13)
 #define WAKEUP_EN              (1 << 14)
-
-/* 44xx specific mux bit defines */
 #define WAKEUP_EVENT           (1 << 15)
 
 /* Active pin states */
index f7f1d71..089743a 100644 (file)
@@ -158,6 +158,26 @@ static inline bool balloon_page_movable(struct page *page)
        return false;
 }
 
+/*
+ * isolated_balloon_page - identify an isolated balloon page on private
+ *                        compaction/migration page lists.
+ *
+ * After a compaction thread isolates a balloon page for migration, it raises
+ * the page refcount to prevent concurrent compaction threads from re-isolating
+ * the same page. For that reason putback_movable_pages(), or other routines
+ * that need to identify isolated balloon pages on private pagelists, cannot
+ * rely on balloon_page_movable() to accomplish the task.
+ */
+static inline bool isolated_balloon_page(struct page *page)
+{
+       /* Already isolated balloon pages, by default, have a raised refcount */
+       if (page_flags_cleared(page) && !page_mapped(page) &&
+           page_count(page) >= 2)
+               return __is_movable_balloon_page(page);
+
+       return false;
+}
+
 /*
  * balloon_page_insert - insert a page into the balloon's page list and make
  *                      the page->mapping assignment accordingly.
@@ -243,6 +263,11 @@ static inline bool balloon_page_movable(struct page *page)
        return false;
 }
 
+static inline bool isolated_balloon_page(struct page *page)
+{
+       return false;
+}
+
 static inline bool balloon_page_isolate(struct page *page)
 {
        return false;
index d66033f..0333e60 100644 (file)
@@ -242,6 +242,7 @@ extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
                                 struct bcma_device *core, bool enable);
 extern void bcma_core_pci_up(struct bcma_bus *bus);
 extern void bcma_core_pci_down(struct bcma_bus *bus);
+extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up);
 
 extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
 extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
index 842de22..ded4299 100644 (file)
 #define __visible __attribute__((externally_visible))
 #endif
 
+/*
+ * GCC 'asm goto' miscompiles certain code sequences:
+ *
+ *   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
+ *
+ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
+ * Fixed in GCC 4.8.2 and later versions.
+ *
+ * (asm goto is automatically volatile - the naming reflects this.)
+ */
+#if GCC_VERSION <= 40801
+# define asm_volatile_goto(x...)       do { asm goto(x); asm (""); } while (0)
+#else
+# define asm_volatile_goto(x...)       do { asm goto(x); } while (0)
+#endif
 
 #ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
 #if GCC_VERSION >= 40400
index a6ac848..ff4e40c 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/atomic.h>
 #include <linux/compat.h>
+#include <linux/workqueue.h>
 #include <uapi/linux/filter.h>
 
 #ifdef CONFIG_COMPAT
@@ -25,15 +26,19 @@ struct sk_filter
 {
        atomic_t                refcnt;
        unsigned int            len;    /* Number of filter blocks */
+       struct rcu_head         rcu;
        unsigned int            (*bpf_func)(const struct sk_buff *skb,
                                            const struct sock_filter *filter);
-       struct rcu_head         rcu;
-       struct sock_filter      insns[0];
+       union {
+               struct sock_filter      insns[0];
+               struct work_struct      work;
+       };
 };
 
-static inline unsigned int sk_filter_len(const struct sk_filter *fp)
+static inline unsigned int sk_filter_size(unsigned int proglen)
 {
-       return fp->len * sizeof(struct sock_filter) + sizeof(*fp);
+       return max(sizeof(struct sk_filter),
+                  offsetof(struct sk_filter, insns[proglen]));
 }
 
 extern int sk_filter(struct sock *sk, struct sk_buff *skb);
@@ -67,11 +72,13 @@ static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen,
 }
 #define SK_RUN_FILTER(FILTER, SKB) (*FILTER->bpf_func)(SKB, FILTER->insns)
 #else
+#include <linux/slab.h>
 static inline void bpf_jit_compile(struct sk_filter *fp)
 {
 }
 static inline void bpf_jit_free(struct sk_filter *fp)
 {
+       kfree(fp);
 }
 #define SK_RUN_FILTER(FILTER, SKB) sk_run_filter(SKB, FILTER->insns)
 #endif
index 78e2ada..d380c5e 100644 (file)
@@ -55,7 +55,7 @@
 #define DMAR_IQT_REG   0x88    /* Invalidation queue tail register */
 #define DMAR_IQ_SHIFT  4       /* Invalidation queue head/tail shift */
 #define DMAR_IQA_REG   0x90    /* Invalidation queue addr register */
-#define DMAR_ICS_REG   0x98    /* Invalidation complete status register */
+#define DMAR_ICS_REG   0x9c    /* Invalidation complete status register */
 #define DMAR_IRTA_REG  0xb8    /* Interrupt remapping table addr register */
 
 #define OFFSET_STRIDE          (9)
index 19c19a5..f6c82de 100644 (file)
@@ -34,9 +34,9 @@ struct ipc_namespace {
        int             sem_ctls[4];
        int             used_sems;
 
-       int             msg_ctlmax;
-       int             msg_ctlmnb;
-       int             msg_ctlmni;
+       unsigned int    msg_ctlmax;
+       unsigned int    msg_ctlmnb;
+       unsigned int    msg_ctlmni;
        atomic_t        msg_bytes;
        atomic_t        msg_hdrs;
        int             auto_msgmni;
index 482ad2d..672ddc4 100644 (file)
@@ -439,6 +439,17 @@ static inline char *hex_byte_pack(char *buf, u8 byte)
        return buf;
 }
 
+extern const char hex_asc_upper[];
+#define hex_asc_upper_lo(x)    hex_asc_upper[((x) & 0x0f)]
+#define hex_asc_upper_hi(x)    hex_asc_upper[((x) & 0xf0) >> 4]
+
+static inline char *hex_byte_pack_upper(char *buf, u8 byte)
+{
+       *buf++ = hex_asc_upper_hi(byte);
+       *buf++ = hex_asc_upper_lo(byte);
+       return buf;
+}
+
 static inline char * __deprecated pack_hex_byte(char *buf, u8 byte)
 {
        return hex_byte_pack(buf, byte);
index ecc82b3..b3e7a66 100644 (file)
@@ -137,47 +137,24 @@ extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
 extern void mem_cgroup_replace_page_cache(struct page *oldpage,
                                        struct page *newpage);
 
-/**
- * mem_cgroup_toggle_oom - toggle the memcg OOM killer for the current task
- * @new: true to enable, false to disable
- *
- * Toggle whether a failed memcg charge should invoke the OOM killer
- * or just return -ENOMEM.  Returns the previous toggle state.
- *
- * NOTE: Any path that enables the OOM killer before charging must
- *       call mem_cgroup_oom_synchronize() afterward to finalize the
- *       OOM handling and clean up.
- */
-static inline bool mem_cgroup_toggle_oom(bool new)
+static inline void mem_cgroup_oom_enable(void)
 {
-       bool old;
-
-       old = current->memcg_oom.may_oom;
-       current->memcg_oom.may_oom = new;
-
-       return old;
+       WARN_ON(current->memcg_oom.may_oom);
+       current->memcg_oom.may_oom = 1;
 }
 
-static inline void mem_cgroup_enable_oom(void)
+static inline void mem_cgroup_oom_disable(void)
 {
-       bool old = mem_cgroup_toggle_oom(true);
-
-       WARN_ON(old == true);
-}
-
-static inline void mem_cgroup_disable_oom(void)
-{
-       bool old = mem_cgroup_toggle_oom(false);
-
-       WARN_ON(old == false);
+       WARN_ON(!current->memcg_oom.may_oom);
+       current->memcg_oom.may_oom = 0;
 }
 
 static inline bool task_in_memcg_oom(struct task_struct *p)
 {
-       return p->memcg_oom.in_memcg_oom;
+       return p->memcg_oom.memcg;
 }
 
-bool mem_cgroup_oom_synchronize(void);
+bool mem_cgroup_oom_synchronize(bool wait);
 
 #ifdef CONFIG_MEMCG_SWAP
 extern int do_swap_account;
@@ -402,16 +379,11 @@ static inline void mem_cgroup_end_update_page_stat(struct page *page,
 {
 }
 
-static inline bool mem_cgroup_toggle_oom(bool new)
-{
-       return false;
-}
-
-static inline void mem_cgroup_enable_oom(void)
+static inline void mem_cgroup_oom_enable(void)
 {
 }
 
-static inline void mem_cgroup_disable_oom(void)
+static inline void mem_cgroup_oom_disable(void)
 {
 }
 
@@ -420,7 +392,7 @@ static inline bool task_in_memcg_oom(struct task_struct *p)
        return false;
 }
 
-static inline bool mem_cgroup_oom_synchronize(void)
+static inline bool mem_cgroup_oom_synchronize(bool wait)
 {
        return false;
 }
index 09c2300..cb35835 100644 (file)
@@ -45,6 +45,7 @@
 #define MAPPER_CTRL_MINOR      236
 #define LOOP_CTRL_MINOR                237
 #define VHOST_NET_MINOR                238
+#define UHID_MINOR             239
 #define MISC_DYNAMIC_MINOR     255
 
 struct device;
index 68029b3..5eb4e31 100644 (file)
@@ -181,7 +181,7 @@ enum {
        MLX5_DEV_CAP_FLAG_TLP_HINTS     = 1LL << 39,
        MLX5_DEV_CAP_FLAG_SIG_HAND_OVER = 1LL << 40,
        MLX5_DEV_CAP_FLAG_DCT           = 1LL << 41,
-       MLX5_DEV_CAP_FLAG_CMDIF_CSUM    = 1LL << 46,
+       MLX5_DEV_CAP_FLAG_CMDIF_CSUM    = 3LL << 46,
 };
 
 enum {
@@ -417,7 +417,7 @@ struct mlx5_init_seg {
        struct health_buffer    health;
        __be32                  rsvd2[884];
        __be32                  health_counter;
-       __be32                  rsvd3[1023];
+       __be32                  rsvd3[1019];
        __be64                  ieee1588_clk;
        __be32                  ieee1588_clk_type;
        __be32                  clr_intx;
index 8888381..6b8c496 100644 (file)
@@ -82,7 +82,7 @@ enum {
 };
 
 enum {
-       MLX5_MAX_EQ_NAME        = 20
+       MLX5_MAX_EQ_NAME        = 32
 };
 
 enum {
@@ -747,8 +747,7 @@ static inline u32 mlx5_idx_to_mkey(u32 mkey_idx)
 
 enum {
        MLX5_PROF_MASK_QP_SIZE          = (u64)1 << 0,
-       MLX5_PROF_MASK_CMDIF_CSUM       = (u64)1 << 1,
-       MLX5_PROF_MASK_MR_CACHE         = (u64)1 << 2,
+       MLX5_PROF_MASK_MR_CACHE         = (u64)1 << 1,
 };
 
 enum {
@@ -758,7 +757,6 @@ enum {
 struct mlx5_profile {
        u64     mask;
        u32     log_max_qp;
-       int     cmdif_csum;
        struct {
                int     size;
                int     limit;
index 3de49ac..25f5d2d 100644 (file)
@@ -2264,11 +2264,12 @@ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index)
 }
 
 #ifdef CONFIG_XPS
-extern int netif_set_xps_queue(struct net_device *dev, struct cpumask *mask,
+extern int netif_set_xps_queue(struct net_device *dev,
+                              const struct cpumask *mask,
                               u16 index);
 #else
 static inline int netif_set_xps_queue(struct net_device *dev,
-                                     struct cpumask *mask,
+                                     const struct cpumask *mask,
                                      u16 index)
 {
        return 0;
index 01fd84b..49f52c8 100644 (file)
@@ -1455,7 +1455,8 @@ struct nfs_rpc_ops {
        struct inode * (*open_context) (struct inode *dir,
                                struct nfs_open_context *ctx,
                                int open_flags,
-                               struct iattr *iattr);
+                               struct iattr *iattr,
+                               int *);
        int (*have_delegation)(struct inode *, fmode_t);
        int (*return_delegation)(struct inode *);
        struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *);
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
deleted file mode 100644 (file)
index c841282..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __OF_RESERVED_MEM_H
-#define __OF_RESERVED_MEM_H
-
-#ifdef CONFIG_OF_RESERVED_MEM
-void of_reserved_mem_device_init(struct device *dev);
-void of_reserved_mem_device_release(struct device *dev);
-void early_init_dt_scan_reserved_mem(void);
-#else
-static inline void of_reserved_mem_device_init(struct device *dev) { }
-static inline void of_reserved_mem_device_release(struct device *dev) { }
-static inline void early_init_dt_scan_reserved_mem(void) { }
-#endif
-
-#endif /* __OF_RESERVED_MEM_H */
index cc88172..c74088a 100644 (file)
@@ -332,7 +332,7 @@ do {                                                                        \
 #endif
 
 #ifndef this_cpu_sub
-# define this_cpu_sub(pcp, val)                this_cpu_add((pcp), -(val))
+# define this_cpu_sub(pcp, val)                this_cpu_add((pcp), -(typeof(pcp))(val))
 #endif
 
 #ifndef this_cpu_inc
@@ -418,7 +418,7 @@ do {                                                                        \
 # define this_cpu_add_return(pcp, val) __pcpu_size_call_return2(this_cpu_add_return_, pcp, val)
 #endif
 
-#define this_cpu_sub_return(pcp, val)  this_cpu_add_return(pcp, -(val))
+#define this_cpu_sub_return(pcp, val)  this_cpu_add_return(pcp, -(typeof(pcp))(val))
 #define this_cpu_inc_return(pcp)       this_cpu_add_return(pcp, 1)
 #define this_cpu_dec_return(pcp)       this_cpu_add_return(pcp, -1)
 
@@ -586,7 +586,7 @@ do {                                                                        \
 #endif
 
 #ifndef __this_cpu_sub
-# define __this_cpu_sub(pcp, val)      __this_cpu_add((pcp), -(val))
+# define __this_cpu_sub(pcp, val)      __this_cpu_add((pcp), -(typeof(pcp))(val))
 #endif
 
 #ifndef __this_cpu_inc
@@ -668,7 +668,7 @@ do {                                                                        \
        __pcpu_size_call_return2(__this_cpu_add_return_, pcp, val)
 #endif
 
-#define __this_cpu_sub_return(pcp, val)        __this_cpu_add_return(pcp, -(val))
+#define __this_cpu_sub_return(pcp, val)        __this_cpu_add_return(pcp, -(typeof(pcp))(val))
 #define __this_cpu_inc_return(pcp)     __this_cpu_add_return(pcp, 1)
 #define __this_cpu_dec_return(pcp)     __this_cpu_add_return(pcp, -1)
 
index 866e85c..c8ba627 100644 (file)
@@ -294,9 +294,31 @@ struct ring_buffer;
  */
 struct perf_event {
 #ifdef CONFIG_PERF_EVENTS
-       struct list_head                group_entry;
+       /*
+        * entry onto perf_event_context::event_list;
+        *   modifications require ctx->lock
+        *   RCU safe iterations.
+        */
        struct list_head                event_entry;
+
+       /*
+        * XXX: group_entry and sibling_list should be mutually exclusive;
+        * either you're a sibling on a group, or you're the group leader.
+        * Rework the code to always use the same list element.
+        *
+        * Locked for modification by both ctx->mutex and ctx->lock; holding
+        * either sufficies for read.
+        */
+       struct list_head                group_entry;
        struct list_head                sibling_list;
+
+       /*
+        * We need storage to track the entries in perf_pmu_migrate_context; we
+        * cannot use the event_entry because of RCU and we want to keep the
+        * group in tact which avoids us using the other two entries.
+        */
+       struct list_head                migrate_entry;
+
        struct hlist_node               hlist_entry;
        int                             nr_siblings;
        int                             group_flags;
index 3b9377d..6312dd9 100644 (file)
@@ -17,6 +17,7 @@ extern void add_interrupt_randomness(int irq, int irq_flags);
 extern void get_random_bytes(void *buf, int nbytes);
 extern void get_random_bytes_arch(void *buf, int nbytes);
 void generate_random_uuid(unsigned char uuid_out[16]);
+extern int random_int_secret_init(void);
 
 #ifndef MODULE
 extern const struct file_operations random_fops, urandom_fops;
index 67e13aa..9bdad43 100644 (file)
@@ -40,6 +40,8 @@ enum regulator_status {
 };
 
 /**
+ * struct regulator_linear_range - specify linear voltage ranges
+ *
  * Specify a range of voltages for regulator_map_linar_range() and
  * regulator_list_linear_range().
  *
index 6682da3..e27baee 100644 (file)
@@ -1394,11 +1394,10 @@ struct task_struct {
        } memcg_batch;
        unsigned int memcg_kmem_skip_account;
        struct memcg_oom_info {
+               struct mem_cgroup *memcg;
+               gfp_t gfp_mask;
+               int order;
                unsigned int may_oom:1;
-               unsigned int in_memcg_oom:1;
-               unsigned int oom_locked:1;
-               int wakeups;
-               struct mem_cgroup *wait_on_memcg;
        } memcg_oom;
 #endif
 #ifdef CONFIG_UPROBES
index 2ddb48d..c2d8933 100644 (file)
@@ -498,7 +498,7 @@ struct sk_buff {
         * headers if needed
         */
        __u8                    encapsulation:1;
-       /* 7/9 bit hole (depending on ndisc_nodetype presence) */
+       /* 6/8 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
 #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
diff --git a/include/linux/tc_act/tc_defact.h b/include/linux/tc_act/tc_defact.h
deleted file mode 100644 (file)
index 6f65d07..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __LINUX_TC_DEF_H
-#define __LINUX_TC_DEF_H
-
-#include <linux/pkt_cls.h>
-
-struct tc_defact {
-       tc_gen;
-};
-                                                                                
-enum {
-       TCA_DEF_UNSPEC,
-       TCA_DEF_TM,
-       TCA_DEF_PARMS,
-       TCA_DEF_DATA,
-       __TCA_DEF_MAX
-};
-#define TCA_DEF_MAX (__TCA_DEF_MAX - 1)
-
-#endif
index dd3edd7..9d3f1a5 100644 (file)
 
 #include <asm/timex.h>
 
+#ifndef random_get_entropy
+/*
+ * The random_get_entropy() function is used by the /dev/random driver
+ * in order to extract entropy via the relative unpredictability of
+ * when an interrupt takes places versus a high speed, fine-grained
+ * timing source or cycle counter.  Since it will be occurred on every
+ * single interrupt, it must have a very low cost/overhead.
+ *
+ * By default we use get_cycles() for this purpose, but individual
+ * architectures may override this in their asm/timex.h header file.
+ */
+#define random_get_entropy()   get_cycles()
+#endif
+
 /*
  * SHIFT_PLL is used as a dampening factor to define how much we
  * adjust the frequency correction for a given offset in PLL mode.
index f9a7e7b..11d85b9 100644 (file)
@@ -12,7 +12,7 @@ struct usb_phy_gen_xceiv_platform_data {
        unsigned int needs_reset:1;
 };
 
-#if IS_ENABLED(CONFIG_NOP_USB_XCEIV)
+#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
 /* sometimes transceivers are accessed only through e.g. ULPI */
 extern void usb_nop_xceiv_register(void);
 extern void usb_nop_xceiv_unregister(void);
index 9cb2fe8..e303eef 100644 (file)
@@ -42,6 +42,7 @@ struct usbnet {
        struct usb_host_endpoint *status;
        unsigned                maxpacket;
        struct timer_list       delay;
+       const char              *padding_pkt;
 
        /* protocol/interface state */
        struct net_device       *net;
index bf99cd0..6303568 100644 (file)
@@ -66,7 +66,9 @@
        US_FLAG(INITIAL_READ10, 0x00100000)                     \
                /* Initial READ(10) (and others) must be retried */     \
        US_FLAG(WRITE_CACHE,    0x00200000)                     \
-               /* Write Cache status is not available */
+               /* Write Cache status is not available */       \
+       US_FLAG(NEEDS_CAP16,    0x00400000)
+               /* cannot handle READ_CAPACITY_10 */
 
 #define US_FLAG(name, value)   US_FL_##name = value ,
 enum { US_DO_ALL_FLAGS };
index 80cf817..2c02f3a 100644 (file)
@@ -65,15 +65,8 @@ struct pci_dev;
  *     out of the arbitration process (and can be safe to take
  *     interrupts at any time.
  */
-#if defined(CONFIG_VGA_ARB)
 extern void vga_set_legacy_decoding(struct pci_dev *pdev,
                                    unsigned int decodes);
-#else
-static inline void vga_set_legacy_decoding(struct pci_dev *pdev,
-                                          unsigned int decodes)
-{
-}
-#endif
 
 /**
  *     vga_get         - acquire & locks VGA resources
index 7fe2822..512cdc2 100644 (file)
@@ -77,6 +77,6 @@ struct yamdrv_ioctl_cfg {
 
 struct yamdrv_ioctl_mcs {
        int cmd;
-       int bitrate;
+       unsigned int bitrate;
        unsigned char bits[YAM_FPGA_SIZE];
 };
index fb314de..86505bf 100644 (file)
@@ -67,6 +67,10 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
 int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr);
 #endif
 
+bool ipv6_chk_custom_prefix(const struct in6_addr *addr,
+                                  const unsigned int prefix_len,
+                                  struct net_device *dev);
+
 int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev);
 
 struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net,
index aaeaf09..15f1084 100644 (file)
@@ -104,6 +104,7 @@ enum {
 enum {
        HCI_SETUP,
        HCI_AUTO_OFF,
+       HCI_RFKILLED,
        HCI_MGMT,
        HCI_PAIRABLE,
        HCI_SERVICE_CACHE,
index a7a683e..a8c2ef6 100644 (file)
@@ -290,6 +290,7 @@ static inline int cipso_v4_validate(const struct sk_buff *skb,
        unsigned char err_offset = 0;
        u8 opt_len = opt[1];
        u8 opt_iter;
+       u8 tag_len;
 
        if (opt_len < 8) {
                err_offset = 1;
@@ -302,11 +303,12 @@ static inline int cipso_v4_validate(const struct sk_buff *skb,
        }
 
        for (opt_iter = 6; opt_iter < opt_len;) {
-               if (opt[opt_iter + 1] > (opt_len - opt_iter)) {
+               tag_len = opt[opt_iter + 1];
+               if ((tag_len == 0) || (opt[opt_iter + 1] > (opt_len - opt_iter))) {
                        err_offset = opt_iter + 1;
                        goto out;
                }
-               opt_iter += opt[opt_iter + 1];
+               opt_iter += tag_len;
        }
 
 out:
index 3bc4865..3c4c944 100644 (file)
@@ -479,10 +479,22 @@ static inline struct dst_entry *xfrm_lookup(struct net *net,
 {
        return dst_orig;
 } 
+
+static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst)
+{
+       return NULL;
+}
+
 #else
 extern struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
                                     const struct flowi *fl, struct sock *sk,
                                     int flags);
+
+/* skb attached with this dst needs transformation if dst->xfrm is valid */
+static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst)
+{
+       return dst->xfrm;
+}
 #endif
 
 #endif /* _NET_DST_H */
index f525e70..2b786b7 100644 (file)
@@ -194,11 +194,9 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
               skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
 }
 
-static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt, struct in6_addr *dest)
+static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt)
 {
-       if (rt->rt6i_flags & RTF_GATEWAY)
-               return &rt->rt6i_gateway;
-       return dest;
+       return &rt->rt6i_gateway;
 }
 
 #endif
index f0d70f0..9c4d37e 100644 (file)
@@ -723,8 +723,6 @@ struct ip_vs_dest_dst {
        struct rcu_head         rcu_head;
 };
 
-/* In grace period after removing */
-#define IP_VS_DEST_STATE_REMOVING      0x01
 /*
  *     The real server destination forwarding entry
  *     with ip address, port number, and so on.
@@ -742,7 +740,7 @@ struct ip_vs_dest {
 
        atomic_t                refcnt;         /* reference counter */
        struct ip_vs_stats      stats;          /* statistics */
-       unsigned long           state;          /* state flags */
+       unsigned long           idle_start;     /* start time, jiffies */
 
        /* connection counters and thresholds */
        atomic_t                activeconns;    /* active connections */
@@ -756,14 +754,13 @@ struct ip_vs_dest {
        struct ip_vs_dest_dst __rcu *dest_dst;  /* cached dst info */
 
        /* for virtual service */
-       struct ip_vs_service    *svc;           /* service it belongs to */
+       struct ip_vs_service __rcu *svc;        /* service it belongs to */
        __u16                   protocol;       /* which protocol (TCP/UDP) */
        __be16                  vport;          /* virtual port number */
        union nf_inet_addr      vaddr;          /* virtual IP address */
        __u32                   vfwmark;        /* firewall mark of service */
 
        struct list_head        t_list;         /* in dest_trash */
-       struct rcu_head         rcu_head;
        unsigned int            in_rs_table:1;  /* we are in rs_table */
 };
 
@@ -1649,7 +1646,7 @@ static inline void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp)
 /* CONFIG_IP_VS_NFCT */
 #endif
 
-static inline unsigned int
+static inline int
 ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
 {
        /*
index d0d11df..807d6b7 100644 (file)
@@ -133,7 +133,7 @@ struct ieee802154_ops {
 
 /* Basic interface to register ieee802154 device */
 struct ieee802154_dev *
-ieee802154_alloc_device(size_t priv_data_lex, struct ieee802154_ops *ops);
+ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops);
 void ieee802154_free_device(struct ieee802154_dev *dev);
 int ieee802154_register_device(struct ieee802154_dev *dev);
 void ieee802154_unregister_device(struct ieee802154_dev *dev);
index 4fbf02a..0f7558b 100644 (file)
@@ -112,6 +112,7 @@ struct mrp_applicant {
        struct mrp_application  *app;
        struct net_device       *dev;
        struct timer_list       join_timer;
+       struct timer_list       periodic_timer;
 
        spinlock_t              lock;
        struct sk_buff_head     queue;
index 1313456..9d22f08 100644 (file)
@@ -74,6 +74,7 @@ struct net {
        struct hlist_head       *dev_index_head;
        unsigned int            dev_base_seq;   /* protected by rtnl_mutex */
        int                     ifindex;
+       unsigned int            dev_unreg_count;
 
        /* core fib_rules */
        struct list_head        rules_ops;
index 806f54a..f572f31 100644 (file)
@@ -56,7 +56,7 @@ struct synproxy_options {
 
 struct tcphdr;
 struct xt_synproxy_info;
-extern void synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
+extern bool synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
                                   const struct tcphdr *th,
                                   struct synproxy_options *opts);
 extern unsigned int synproxy_options_size(const struct synproxy_options *opts);
index 6ca975b..c2e542b 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <linux/types.h>
 
-extern void net_secret_init(void);
 extern __u32 secure_ip_id(__be32 daddr);
 extern __u32 secure_ipv6_id(const __be32 daddr[4]);
 extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
index 6ba2e7b..808cbc2 100644 (file)
@@ -409,6 +409,11 @@ struct sock {
        void                    (*sk_destruct)(struct sock *sk);
 };
 
+#define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data)))
+
+#define rcu_dereference_sk_user_data(sk)       rcu_dereference(__sk_user_data((sk)))
+#define rcu_assign_sk_user_data(sk, ptr)       rcu_assign_pointer(__sk_user_data((sk)), ptr)
+
 /*
  * SK_CAN_REUSE and SK_NO_REUSE on a socket mean that the socket is OK
  * or not whether his port will be reused by someone else. SK_FORCE_REUSE
@@ -1625,16 +1630,14 @@ static inline void sk_filter_release(struct sk_filter *fp)
 
 static inline void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp)
 {
-       unsigned int size = sk_filter_len(fp);
-
-       atomic_sub(size, &sk->sk_omem_alloc);
+       atomic_sub(sk_filter_size(fp->len), &sk->sk_omem_alloc);
        sk_filter_release(fp);
 }
 
 static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp)
 {
        atomic_inc(&fp->refcnt);
-       atomic_add(sk_filter_len(fp), &sk->sk_omem_alloc);
+       atomic_add(sk_filter_size(fp->len), &sk->sk_omem_alloc);
 }
 
 /*
index fe66533..fb0a312 100644 (file)
@@ -68,6 +68,7 @@ struct rsnd_scu_platform_info {
  *
  * A : generation
  */
+#define RSND_GEN_MASK  (0xF << 0)
 #define RSND_GEN1      (1 << 0) /* fixme */
 #define RSND_GEN2      (2 << 0) /* fixme */
 
index aef8fc3..da9cc0f 100644 (file)
@@ -144,7 +144,7 @@ TRACE_EVENT(target_sequencer_start,
        ),
 
        TP_fast_assign(
-               __entry->unpacked_lun   = cmd->se_lun->unpacked_lun;
+               __entry->unpacked_lun   = cmd->orig_fe_lun;
                __entry->opcode         = cmd->t_task_cdb[0];
                __entry->data_length    = cmd->data_length;
                __entry->task_attribute = cmd->sam_task_attr;
@@ -182,7 +182,7 @@ TRACE_EVENT(target_cmd_complete,
        ),
 
        TP_fast_assign(
-               __entry->unpacked_lun   = cmd->se_lun->unpacked_lun;
+               __entry->unpacked_lun   = cmd->orig_fe_lun;
                __entry->opcode         = cmd->t_task_cdb[0];
                __entry->data_length    = cmd->data_length;
                __entry->task_attribute = cmd->sam_task_attr;
index c2c4ace..f104c26 100644 (file)
@@ -240,6 +240,8 @@ struct drm_mode_get_connector {
        __u32 connection;
        __u32 mm_width, mm_height; /**< HxW in millimeters */
        __u32 subpixel;
+
+       __u32 pad;
 };
 
 #define DRM_MODE_PROP_PENDING  (1<<0)
index 009a655..2fc1602 100644 (file)
@@ -456,13 +456,15 @@ struct perf_event_mmap_page {
        /*
         * Control data for the mmap() data buffer.
         *
-        * User-space reading the @data_head value should issue an rmb(), on
-        * SMP capable platforms, after reading this value -- see
-        * perf_event_wakeup().
+        * User-space reading the @data_head value should issue an smp_rmb(),
+        * after reading this value.
         *
         * When the mapping is PROT_WRITE the @data_tail value should be
-        * written by userspace to reflect the last read data. In this case
-        * the kernel will not over-write unread data.
+        * written by userspace to reflect the last read data, after issueing
+        * an smp_mb() to separate the data read from the ->data_tail store.
+        * In this case the kernel will not over-write unread data.
+        *
+        * See perf_output_put_handle() for the data ordering.
         */
        __u64   data_head;              /* head in the data section */
        __u64   data_tail;              /* user-space written tail */
index 0623ec4..56f1216 100644 (file)
@@ -1,5 +1,6 @@
 # UAPI Header export list
 header-y += tc_csum.h
+header-y += tc_defact.h
 header-y += tc_gact.h
 header-y += tc_ipt.h
 header-y += tc_mirred.h
diff --git a/include/uapi/linux/tc_act/tc_defact.h b/include/uapi/linux/tc_act/tc_defact.h
new file mode 100644 (file)
index 0000000..17dddb4
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __LINUX_TC_DEF_H
+#define __LINUX_TC_DEF_H
+
+#include <linux/pkt_cls.h>
+
+struct tc_defact {
+       tc_gen;
+};
+
+enum {
+       TCA_DEF_UNSPEC,
+       TCA_DEF_TM,
+       TCA_DEF_PARMS,
+       TCA_DEF_DATA,
+       __TCA_DEF_MAX
+};
+#define TCA_DEF_MAX (__TCA_DEF_MAX - 1)
+
+#endif
index 0b233c5..e3ddd86 100644 (file)
@@ -87,8 +87,10 @@ enum {
        IB_USER_VERBS_CMD_CLOSE_XRCD,
        IB_USER_VERBS_CMD_CREATE_XSRQ,
        IB_USER_VERBS_CMD_OPEN_QP,
+#ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
        IB_USER_VERBS_CMD_CREATE_FLOW = IB_USER_VERBS_CMD_THRESHOLD,
        IB_USER_VERBS_CMD_DESTROY_FLOW
+#endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */
 };
 
 /*
@@ -126,6 +128,7 @@ struct ib_uverbs_cmd_hdr {
        __u16 out_words;
 };
 
+#ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
 struct ib_uverbs_cmd_hdr_ex {
        __u32 command;
        __u16 in_words;
@@ -134,6 +137,7 @@ struct ib_uverbs_cmd_hdr_ex {
        __u16 provider_out_words;
        __u32 cmd_hdr_reserved;
 };
+#endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */
 
 struct ib_uverbs_get_context {
        __u64 response;
@@ -696,6 +700,7 @@ struct ib_uverbs_detach_mcast {
        __u64 driver_data[0];
 };
 
+#ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING
 struct ib_kern_eth_filter {
        __u8  dst_mac[6];
        __u8  src_mac[6];
@@ -780,6 +785,7 @@ struct ib_uverbs_destroy_flow  {
        __u32 comp_mask;
        __u32 flow_handle;
 };
+#endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */
 
 struct ib_uverbs_create_srq {
        __u64 response;
index af310af..63d3e8f 100644 (file)
@@ -76,6 +76,7 @@
 #include <linux/elevator.h>
 #include <linux/sched_clock.h>
 #include <linux/context_tracking.h>
+#include <linux/random.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -780,6 +781,7 @@ static void __init do_basic_setup(void)
        do_ctors();
        usermodehelper_enable();
        do_initcalls();
+       random_int_secret_init();
 }
 
 static void __init do_pre_smp_initcalls(void)
index 130dfec..b0e99de 100644 (file)
@@ -62,7 +62,7 @@ static int proc_ipc_dointvec_minmax_orphans(ctl_table *table, int write,
        return err;
 }
 
-static int proc_ipc_callback_dointvec(ctl_table *table, int write,
+static int proc_ipc_callback_dointvec_minmax(ctl_table *table, int write,
        void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        struct ctl_table ipc_table;
@@ -72,7 +72,7 @@ static int proc_ipc_callback_dointvec(ctl_table *table, int write,
        memcpy(&ipc_table, table, sizeof(ipc_table));
        ipc_table.data = get_ipc(table);
 
-       rc = proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
+       rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
 
        if (write && !rc && lenp_bef == *lenp)
                /*
@@ -152,15 +152,13 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
 #define proc_ipc_dointvec         NULL
 #define proc_ipc_dointvec_minmax   NULL
 #define proc_ipc_dointvec_minmax_orphans   NULL
-#define proc_ipc_callback_dointvec NULL
+#define proc_ipc_callback_dointvec_minmax  NULL
 #define proc_ipcauto_dointvec_minmax NULL
 #endif
 
 static int zero;
 static int one = 1;
-#ifdef CONFIG_CHECKPOINT_RESTORE
 static int int_max = INT_MAX;
-#endif
 
 static struct ctl_table ipc_kern_table[] = {
        {
@@ -198,21 +196,27 @@ static struct ctl_table ipc_kern_table[] = {
                .data           = &init_ipc_ns.msg_ctlmax,
                .maxlen         = sizeof (init_ipc_ns.msg_ctlmax),
                .mode           = 0644,
-               .proc_handler   = proc_ipc_dointvec,
+               .proc_handler   = proc_ipc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &int_max,
        },
        {
                .procname       = "msgmni",
                .data           = &init_ipc_ns.msg_ctlmni,
                .maxlen         = sizeof (init_ipc_ns.msg_ctlmni),
                .mode           = 0644,
-               .proc_handler   = proc_ipc_callback_dointvec,
+               .proc_handler   = proc_ipc_callback_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &int_max,
        },
        {
                .procname       =  "msgmnb",
                .data           = &init_ipc_ns.msg_ctlmnb,
                .maxlen         = sizeof (init_ipc_ns.msg_ctlmnb),
                .mode           = 0644,
-               .proc_handler   = proc_ipc_dointvec,
+               .proc_handler   = proc_ipc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &int_max,
        },
        {
                .procname       = "sem",
index 9e4310c..558aa91 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -695,6 +695,12 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                if (ipcperms(ns, &msq->q_perm, S_IWUGO))
                        goto out_unlock0;
 
+               /* raced with RMID? */
+               if (msq->q_perm.deleted) {
+                       err = -EIDRM;
+                       goto out_unlock0;
+               }
+
                err = security_msg_queue_msgsnd(msq, msg, msgflg);
                if (err)
                        goto out_unlock0;
@@ -901,6 +907,13 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
                        goto out_unlock1;
 
                ipc_lock_object(&msq->q_perm);
+
+               /* raced with RMID? */
+               if (msq->q_perm.deleted) {
+                       msg = ERR_PTR(-EIDRM);
+                       goto out_unlock0;
+               }
+
                msg = find_msg(msq, &msgtyp, mode);
                if (!IS_ERR(msg)) {
                        /*
index 19c8b98..db9d241 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -252,71 +252,113 @@ static void sem_rcu_free(struct rcu_head *head)
        ipc_rcu_free(head);
 }
 
+/*
+ * Wait until all currently ongoing simple ops have completed.
+ * Caller must own sem_perm.lock.
+ * New simple ops cannot start, because simple ops first check
+ * that sem_perm.lock is free.
+ * that a) sem_perm.lock is free and b) complex_count is 0.
+ */
+static void sem_wait_array(struct sem_array *sma)
+{
+       int i;
+       struct sem *sem;
+
+       if (sma->complex_count)  {
+               /* The thread that increased sma->complex_count waited on
+                * all sem->lock locks. Thus we don't need to wait again.
+                */
+               return;
+       }
+
+       for (i = 0; i < sma->sem_nsems; i++) {
+               sem = sma->sem_base + i;
+               spin_unlock_wait(&sem->lock);
+       }
+}
+
 /*
  * If the request contains only one semaphore operation, and there are
  * no complex transactions pending, lock only the semaphore involved.
  * Otherwise, lock the entire semaphore array, since we either have
  * multiple semaphores in our own semops, or we need to look at
  * semaphores from other pending complex operations.
- *
- * Carefully guard against sma->complex_count changing between zero
- * and non-zero while we are spinning for the lock. The value of
- * sma->complex_count cannot change while we are holding the lock,
- * so sem_unlock should be fine.
- *
- * The global lock path checks that all the local locks have been released,
- * checking each local lock once. This means that the local lock paths
- * cannot start their critical sections while the global lock is held.
  */
 static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
                              int nsops)
 {
-       int locknum;
- again:
-       if (nsops == 1 && !sma->complex_count) {
-               struct sem *sem = sma->sem_base + sops->sem_num;
+       struct sem *sem;
 
-               /* Lock just the semaphore we are interested in. */
-               spin_lock(&sem->lock);
+       if (nsops != 1) {
+               /* Complex operation - acquire a full lock */
+               ipc_lock_object(&sma->sem_perm);
 
-               /*
-                * If sma->complex_count was set while we were spinning,
-                * we may need to look at things we did not lock here.
+               /* And wait until all simple ops that are processed
+                * right now have dropped their locks.
                 */
-               if (unlikely(sma->complex_count)) {
-                       spin_unlock(&sem->lock);
-                       goto lock_array;
-               }
+               sem_wait_array(sma);
+               return -1;
+       }
+
+       /*
+        * Only one semaphore affected - try to optimize locking.
+        * The rules are:
+        * - optimized locking is possible if no complex operation
+        *   is either enqueued or processed right now.
+        * - The test for enqueued complex ops is simple:
+        *      sma->complex_count != 0
+        * - Testing for complex ops that are processed right now is
+        *   a bit more difficult. Complex ops acquire the full lock
+        *   and first wait that the running simple ops have completed.
+        *   (see above)
+        *   Thus: If we own a simple lock and the global lock is free
+        *      and complex_count is now 0, then it will stay 0 and
+        *      thus just locking sem->lock is sufficient.
+        */
+       sem = sma->sem_base + sops->sem_num;
 
+       if (sma->complex_count == 0) {
                /*
-                * Another process is holding the global lock on the
-                * sem_array; we cannot enter our critical section,
-                * but have to wait for the global lock to be released.
+                * It appears that no complex operation is around.
+                * Acquire the per-semaphore lock.
                 */
-               if (unlikely(spin_is_locked(&sma->sem_perm.lock))) {
-                       spin_unlock(&sem->lock);
-                       spin_unlock_wait(&sma->sem_perm.lock);
-                       goto again;
+               spin_lock(&sem->lock);
+
+               /* Then check that the global lock is free */
+               if (!spin_is_locked(&sma->sem_perm.lock)) {
+                       /* spin_is_locked() is not a memory barrier */
+                       smp_mb();
+
+                       /* Now repeat the test of complex_count:
+                        * It can't change anymore until we drop sem->lock.
+                        * Thus: if is now 0, then it will stay 0.
+                        */
+                       if (sma->complex_count == 0) {
+                               /* fast path successful! */
+                               return sops->sem_num;
+                       }
                }
+               spin_unlock(&sem->lock);
+       }
+
+       /* slow path: acquire the full lock */
+       ipc_lock_object(&sma->sem_perm);
 
-               locknum = sops->sem_num;
+       if (sma->complex_count == 0) {
+               /* False alarm:
+                * There is no complex operation, thus we can switch
+                * back to the fast path.
+                */
+               spin_lock(&sem->lock);
+               ipc_unlock_object(&sma->sem_perm);
+               return sops->sem_num;
        } else {
-               int i;
-               /*
-                * Lock the semaphore array, and wait for all of the
-                * individual semaphore locks to go away.  The code
-                * above ensures no new single-lock holders will enter
-                * their critical section while the array lock is held.
+               /* Not a false alarm, thus complete the sequence for a
+                * full lock.
                 */
- lock_array:
-               ipc_lock_object(&sma->sem_perm);
-               for (i = 0; i < sma->sem_nsems; i++) {
-                       struct sem *sem = sma->sem_base + i;
-                       spin_unlock_wait(&sem->lock);
-               }
-               locknum = -1;
+               sem_wait_array(sma);
+               return -1;
        }
-       return locknum;
 }
 
 static inline void sem_unlock(struct sem_array *sma, int locknum)
@@ -875,6 +917,24 @@ again:
        return semop_completed;
 }
 
+/**
+ * set_semotime(sma, sops) - set sem_otime
+ * @sma: semaphore array
+ * @sops: operations that modified the array, may be NULL
+ *
+ * sem_otime is replicated to avoid cache line trashing.
+ * This function sets one instance to the current time.
+ */
+static void set_semotime(struct sem_array *sma, struct sembuf *sops)
+{
+       if (sops == NULL) {
+               sma->sem_base[0].sem_otime = get_seconds();
+       } else {
+               sma->sem_base[sops[0].sem_num].sem_otime =
+                                                       get_seconds();
+       }
+}
+
 /**
  * do_smart_update(sma, sops, nsops, otime, pt) - optimized update_queue
  * @sma: semaphore array
@@ -925,17 +985,10 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop
                        }
                }
        }
-       if (otime) {
-               if (sops == NULL) {
-                       sma->sem_base[0].sem_otime = get_seconds();
-               } else {
-                       sma->sem_base[sops[0].sem_num].sem_otime =
-                                                               get_seconds();
-               }
-       }
+       if (otime)
+               set_semotime(sma, sops);
 }
 
-
 /* The following counts are associated to each semaphore:
  *   semncnt        number of tasks waiting on semval being nonzero
  *   semzcnt        number of tasks waiting on semval being zero
@@ -1229,6 +1282,12 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
 
        sem_lock(sma, NULL, -1);
 
+       if (sma->sem_perm.deleted) {
+               sem_unlock(sma, -1);
+               rcu_read_unlock();
+               return -EIDRM;
+       }
+
        curr = &sma->sem_base[semnum];
 
        ipc_assert_locked_object(&sma->sem_perm);
@@ -1283,12 +1342,14 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                int i;
 
                sem_lock(sma, NULL, -1);
+               if (sma->sem_perm.deleted) {
+                       err = -EIDRM;
+                       goto out_unlock;
+               }
                if(nsems > SEMMSL_FAST) {
                        if (!ipc_rcu_getref(sma)) {
-                               sem_unlock(sma, -1);
-                               rcu_read_unlock();
                                err = -EIDRM;
-                               goto out_free;
+                               goto out_unlock;
                        }
                        sem_unlock(sma, -1);
                        rcu_read_unlock();
@@ -1301,10 +1362,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                        rcu_read_lock();
                        sem_lock_and_putref(sma);
                        if (sma->sem_perm.deleted) {
-                               sem_unlock(sma, -1);
-                               rcu_read_unlock();
                                err = -EIDRM;
-                               goto out_free;
+                               goto out_unlock;
                        }
                }
                for (i = 0; i < sma->sem_nsems; i++)
@@ -1322,8 +1381,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                struct sem_undo *un;
 
                if (!ipc_rcu_getref(sma)) {
-                       rcu_read_unlock();
-                       return -EIDRM;
+                       err = -EIDRM;
+                       goto out_rcu_wakeup;
                }
                rcu_read_unlock();
 
@@ -1351,10 +1410,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                rcu_read_lock();
                sem_lock_and_putref(sma);
                if (sma->sem_perm.deleted) {
-                       sem_unlock(sma, -1);
-                       rcu_read_unlock();
                        err = -EIDRM;
-                       goto out_free;
+                       goto out_unlock;
                }
 
                for (i = 0; i < nsems; i++)
@@ -1378,6 +1435,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                goto out_rcu_wakeup;
 
        sem_lock(sma, NULL, -1);
+       if (sma->sem_perm.deleted) {
+               err = -EIDRM;
+               goto out_unlock;
+       }
        curr = &sma->sem_base[semnum];
 
        switch (cmd) {
@@ -1783,6 +1844,10 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        if (error)
                goto out_rcu_wakeup;
 
+       error = -EIDRM;
+       locknum = sem_lock(sma, sops, nsops);
+       if (sma->sem_perm.deleted)
+               goto out_unlock_free;
        /*
         * semid identifiers are not unique - find_alloc_undo may have
         * allocated an undo structure, it was invalidated by an RMID
@@ -1790,19 +1855,22 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
         * This case can be detected checking un->semid. The existence of
         * "un" itself is guaranteed by rcu.
         */
-       error = -EIDRM;
-       locknum = sem_lock(sma, sops, nsops);
        if (un && un->semid == -1)
                goto out_unlock_free;
 
        error = perform_atomic_semop(sma, sops, nsops, un,
                                        task_tgid_vnr(current));
-       if (error <= 0) {
-               if (alter && error == 0)
+       if (error == 0) {
+               /* If the operation was successful, then do
+                * the required updates.
+                */
+               if (alter)
                        do_smart_update(sma, sops, nsops, 1, &tasks);
-
-               goto out_unlock_free;
+               else
+                       set_semotime(sma, sops);
        }
+       if (error <= 0)
+               goto out_unlock_free;
 
        /* We need to sleep on this operation, so we put the current
         * task into the pending queue and go to sleep.
@@ -1999,6 +2067,12 @@ void exit_sem(struct task_struct *tsk)
                }
 
                sem_lock(sma, NULL, -1);
+               /* exit_sem raced with IPC_RMID, nothing to do */
+               if (sma->sem_perm.deleted) {
+                       sem_unlock(sma, -1);
+                       rcu_read_unlock();
+                       continue;
+               }
                un = __lookup_undo(ulp, semid);
                if (un == NULL) {
                        /* exit_sem raced with IPC_RMID+semget() that created
@@ -2061,6 +2135,14 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
        struct sem_array *sma = it;
        time_t sem_otime;
 
+       /*
+        * The proc interface isn't aware of sem_lock(), it calls
+        * ipc_lock_object() directly (in sysvipc_find_ipc).
+        * In order to stay compatible with sem_lock(), we must wait until
+        * all simple semop() calls have left their critical regions.
+        */
+       sem_wait_array(sma);
+
        sem_otime = get_semotime(sma);
 
        return seq_printf(s,
index fdb8ae7..7684f41 100644 (file)
  *            Pavel Emelianov <xemul@openvz.org>
  *
  * General sysv ipc locking scheme:
- *  when doing ipc id lookups, take the ids->rwsem
- *      rcu_read_lock()
- *          obtain the ipc object (kern_ipc_perm)
- *          perform security, capabilities, auditing and permission checks, etc.
- *          acquire the ipc lock (kern_ipc_perm.lock) throught ipc_lock_object()
- *             perform data updates (ie: SET, RMID, LOCK/UNLOCK commands)
+ *     rcu_read_lock()
+ *          obtain the ipc object (kern_ipc_perm) by looking up the id in an idr
+ *         tree.
+ *         - perform initial checks (capabilities, auditing and permission,
+ *           etc).
+ *         - perform read-only operations, such as STAT, INFO commands.
+ *           acquire the ipc lock (kern_ipc_perm.lock) through
+ *           ipc_lock_object()
+ *             - perform data updates, such as SET, RMID commands and
+ *               mechanism-specific operations (semop/semtimedop,
+ *               msgsnd/msgrcv, shmat/shmdt).
+ *         drop the ipc lock, through ipc_unlock_object().
+ *     rcu_read_unlock()
+ *
+ *  The ids->rwsem must be taken when:
+ *     - creating, removing and iterating the existing entries in ipc
+ *       identifier sets.
+ *     - iterating through files under /proc/sysvipc/
+ *
+ *  Note that sems have a special fast path that avoids kern_ipc_perm.lock -
+ *  see sem_lock().
  */
 
 #include <linux/mm.h>
index 2418b6e..8bd9cfd 100644 (file)
@@ -2039,7 +2039,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
 
                /* @tsk either already exited or can't exit until the end */
                if (tsk->flags & PF_EXITING)
-                       continue;
+                       goto next;
 
                /* as per above, nr_threads may decrease, but not increase. */
                BUG_ON(i >= group_size);
@@ -2047,7 +2047,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
                ent.cgrp = task_cgroup_from_root(tsk, root);
                /* nothing to do if this task is already in the cgroup */
                if (ent.cgrp == cgrp)
-                       continue;
+                       goto next;
                /*
                 * saying GFP_ATOMIC has no effect here because we did prealloc
                 * earlier, but it's good form to communicate our expectations.
@@ -2055,7 +2055,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
                retval = flex_array_put(group, i, &ent, GFP_ATOMIC);
                BUG_ON(retval != 0);
                i++;
-
+       next:
                if (!threadgroup)
                        break;
        } while_each_thread(leader, tsk);
@@ -3188,11 +3188,9 @@ css_next_descendant_post(struct cgroup_subsys_state *pos,
 
        WARN_ON_ONCE(!rcu_read_lock_held());
 
-       /* if first iteration, visit the leftmost descendant */
-       if (!pos) {
-               next = css_leftmost_descendant(root);
-               return next != root ? next : NULL;
-       }
+       /* if first iteration, visit leftmost descendant which may be @root */
+       if (!pos)
+               return css_leftmost_descendant(root);
 
        /* if we visited @root, we're done */
        if (pos == root)
index cb4238e..953c143 100644 (file)
@@ -6767,6 +6767,10 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
        if (ret)
                return -EFAULT;
 
+       /* disabled for now */
+       if (attr->mmap2)
+               return -EINVAL;
+
        if (attr->__reserved_1)
                return -EINVAL;
 
@@ -7234,15 +7238,15 @@ void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu)
                perf_remove_from_context(event);
                unaccount_event_cpu(event, src_cpu);
                put_ctx(src_ctx);
-               list_add(&event->event_entry, &events);
+               list_add(&event->migrate_entry, &events);
        }
        mutex_unlock(&src_ctx->mutex);
 
        synchronize_rcu();
 
        mutex_lock(&dst_ctx->mutex);
-       list_for_each_entry_safe(event, tmp, &events, event_entry) {
-               list_del(&event->event_entry);
+       list_for_each_entry_safe(event, tmp, &events, migrate_entry) {
+               list_del(&event->migrate_entry);
                if (event->state >= PERF_EVENT_STATE_OFF)
                        event->state = PERF_EVENT_STATE_INACTIVE;
                account_event_cpu(event, dst_cpu);
index cd55144..9c2ddfb 100644 (file)
@@ -87,10 +87,31 @@ again:
                goto out;
 
        /*
-        * Publish the known good head. Rely on the full barrier implied
-        * by atomic_dec_and_test() order the rb->head read and this
-        * write.
+        * Since the mmap() consumer (userspace) can run on a different CPU:
+        *
+        *   kernel                             user
+        *
+        *   READ ->data_tail                   READ ->data_head
+        *   smp_mb()   (A)                     smp_rmb()       (C)
+        *   WRITE $data                        READ $data
+        *   smp_wmb()  (B)                     smp_mb()        (D)
+        *   STORE ->data_head                  WRITE ->data_tail
+        *
+        * Where A pairs with D, and B pairs with C.
+        *
+        * I don't think A needs to be a full barrier because we won't in fact
+        * write data until we see the store from userspace. So we simply don't
+        * issue the data WRITE until we observe it. Be conservative for now.
+        *
+        * OTOH, D needs to be a full barrier since it separates the data READ
+        * from the tail WRITE.
+        *
+        * For B a WMB is sufficient since it separates two WRITEs, and for C
+        * an RMB is sufficient since it separates two READs.
+        *
+        * See perf_output_begin().
         */
+       smp_wmb();
        rb->user_page->data_head = head;
 
        /*
@@ -154,9 +175,11 @@ int perf_output_begin(struct perf_output_handle *handle,
                 * Userspace could choose to issue a mb() before updating the
                 * tail pointer. So that all reads will be completed before the
                 * write is issued.
+                *
+                * See perf_output_put_handle().
                 */
                tail = ACCESS_ONCE(rb->user_page->data_tail);
-               smp_rmb();
+               smp_mb();
                offset = head = local_read(&rb->head);
                head += size;
                if (unlikely(!perf_output_space(rb, tail, offset, head)))
index fb32636..b086006 100644 (file)
@@ -571,6 +571,10 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
        DECLARE_COMPLETION_ONSTACK(done);
        int retval = 0;
 
+       if (!sub_info->path) {
+               call_usermodehelper_freeinfo(sub_info);
+               return -EINVAL;
+       }
        helper_lock();
        if (!khelper_wq || usermodehelper_disabled) {
                retval = -EBUSY;
index 6d647ae..d24105b 100644 (file)
@@ -410,7 +410,7 @@ ww_mutex_set_context_fastpath(struct ww_mutex *lock,
 static __always_inline int __sched
 __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                    struct lockdep_map *nest_lock, unsigned long ip,
-                   struct ww_acquire_ctx *ww_ctx)
+                   struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx)
 {
        struct task_struct *task = current;
        struct mutex_waiter waiter;
@@ -450,7 +450,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                struct task_struct *owner;
                struct mspin_node  node;
 
-               if (!__builtin_constant_p(ww_ctx == NULL) && ww_ctx->acquired > 0) {
+               if (use_ww_ctx && ww_ctx->acquired > 0) {
                        struct ww_mutex *ww;
 
                        ww = container_of(lock, struct ww_mutex, base);
@@ -480,7 +480,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                if ((atomic_read(&lock->count) == 1) &&
                    (atomic_cmpxchg(&lock->count, 1, 0) == 1)) {
                        lock_acquired(&lock->dep_map, ip);
-                       if (!__builtin_constant_p(ww_ctx == NULL)) {
+                       if (use_ww_ctx) {
                                struct ww_mutex *ww;
                                ww = container_of(lock, struct ww_mutex, base);
 
@@ -551,7 +551,7 @@ slowpath:
                        goto err;
                }
 
-               if (!__builtin_constant_p(ww_ctx == NULL) && ww_ctx->acquired > 0) {
+               if (use_ww_ctx && ww_ctx->acquired > 0) {
                        ret = __mutex_lock_check_stamp(lock, ww_ctx);
                        if (ret)
                                goto err;
@@ -575,7 +575,7 @@ skip_wait:
        lock_acquired(&lock->dep_map, ip);
        mutex_set_owner(lock);
 
-       if (!__builtin_constant_p(ww_ctx == NULL)) {
+       if (use_ww_ctx) {
                struct ww_mutex *ww = container_of(lock, struct ww_mutex, base);
                struct mutex_waiter *cur;
 
@@ -615,7 +615,7 @@ mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
        __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE,
-                           subclass, NULL, _RET_IP_, NULL);
+                           subclass, NULL, _RET_IP_, NULL, 0);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_nested);
@@ -625,7 +625,7 @@ _mutex_lock_nest_lock(struct mutex *lock, struct lockdep_map *nest)
 {
        might_sleep();
        __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE,
-                           0, nest, _RET_IP_, NULL);
+                           0, nest, _RET_IP_, NULL, 0);
 }
 
 EXPORT_SYMBOL_GPL(_mutex_lock_nest_lock);
@@ -635,7 +635,7 @@ mutex_lock_killable_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
        return __mutex_lock_common(lock, TASK_KILLABLE,
-                                  subclass, NULL, _RET_IP_, NULL);
+                                  subclass, NULL, _RET_IP_, NULL, 0);
 }
 EXPORT_SYMBOL_GPL(mutex_lock_killable_nested);
 
@@ -644,7 +644,7 @@ mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
        return __mutex_lock_common(lock, TASK_INTERRUPTIBLE,
-                                  subclass, NULL, _RET_IP_, NULL);
+                                  subclass, NULL, _RET_IP_, NULL, 0);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
@@ -682,7 +682,7 @@ __ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
 
        might_sleep();
        ret =  __mutex_lock_common(&lock->base, TASK_UNINTERRUPTIBLE,
-                                  0, &ctx->dep_map, _RET_IP_, ctx);
+                                  0, &ctx->dep_map, _RET_IP_, ctx, 1);
        if (!ret && ctx->acquired > 1)
                return ww_mutex_deadlock_injection(lock, ctx);
 
@@ -697,7 +697,7 @@ __ww_mutex_lock_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
 
        might_sleep();
        ret = __mutex_lock_common(&lock->base, TASK_INTERRUPTIBLE,
-                                 0, &ctx->dep_map, _RET_IP_, ctx);
+                                 0, &ctx->dep_map, _RET_IP_, ctx, 1);
 
        if (!ret && ctx->acquired > 1)
                return ww_mutex_deadlock_injection(lock, ctx);
@@ -809,28 +809,28 @@ __mutex_lock_slowpath(atomic_t *lock_count)
        struct mutex *lock = container_of(lock_count, struct mutex, count);
 
        __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0,
-                           NULL, _RET_IP_, NULL);
+                           NULL, _RET_IP_, NULL, 0);
 }
 
 static noinline int __sched
 __mutex_lock_killable_slowpath(struct mutex *lock)
 {
        return __mutex_lock_common(lock, TASK_KILLABLE, 0,
-                                  NULL, _RET_IP_, NULL);
+                                  NULL, _RET_IP_, NULL, 0);
 }
 
 static noinline int __sched
 __mutex_lock_interruptible_slowpath(struct mutex *lock)
 {
        return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0,
-                                  NULL, _RET_IP_, NULL);
+                                  NULL, _RET_IP_, NULL, 0);
 }
 
 static noinline int __sched
 __ww_mutex_lock_slowpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
 {
        return __mutex_lock_common(&lock->base, TASK_UNINTERRUPTIBLE, 0,
-                                  NULL, _RET_IP_, ctx);
+                                  NULL, _RET_IP_, ctx, 1);
 }
 
 static noinline int __sched
@@ -838,7 +838,7 @@ __ww_mutex_lock_interruptible_slowpath(struct ww_mutex *lock,
                                            struct ww_acquire_ctx *ctx)
 {
        return __mutex_lock_common(&lock->base, TASK_INTERRUPTIBLE, 0,
-                                  NULL, _RET_IP_, ctx);
+                                  NULL, _RET_IP_, ctx, 1);
 }
 
 #endif
index ebe5e80..9b9a266 100644 (file)
@@ -273,6 +273,11 @@ void free_pid(struct pid *pid)
                         */
                        wake_up_process(ns->child_reaper);
                        break;
+               case PIDNS_HASH_ADDING:
+                       /* Handle a fork failure of the first process */
+                       WARN_ON(ns->child_reaper);
+                       ns->nr_hashed = 0;
+                       /* fall through */
                case 0:
                        schedule_work(&ns->proc_work);
                        break;
index c9c759d..0121dab 100644 (file)
@@ -846,7 +846,7 @@ static int software_resume(void)
        goto Finish;
 }
 
-late_initcall(software_resume);
+late_initcall_sync(software_resume);
 
 
 static const char * const hibernation_modes[] = {
index 358a146..98c3b34 100644 (file)
@@ -743,7 +743,10 @@ int create_basic_memory_bitmaps(void)
        struct memory_bitmap *bm1, *bm2;
        int error = 0;
 
-       BUG_ON(forbidden_pages_map || free_pages_map);
+       if (forbidden_pages_map && free_pages_map)
+               return 0;
+       else
+               BUG_ON(forbidden_pages_map || free_pages_map);
 
        bm1 = kzalloc(sizeof(struct memory_bitmap), GFP_KERNEL);
        if (!bm1)
index 72e8f4f..957f061 100644 (file)
@@ -39,6 +39,7 @@ static struct snapshot_data {
        char frozen;
        char ready;
        char platform_support;
+       bool free_bitmaps;
 } snapshot_state;
 
 atomic_t snapshot_device_available = ATOMIC_INIT(1);
@@ -82,6 +83,10 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                data->swap = -1;
                data->mode = O_WRONLY;
                error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+               if (!error) {
+                       error = create_basic_memory_bitmaps();
+                       data->free_bitmaps = !error;
+               }
                if (error)
                        pm_notifier_call_chain(PM_POST_RESTORE);
        }
@@ -111,6 +116,8 @@ static int snapshot_release(struct inode *inode, struct file *filp)
                pm_restore_gfp_mask();
                free_basic_memory_bitmaps();
                thaw_processes();
+       } else if (data->free_bitmaps) {
+               free_basic_memory_bitmaps();
        }
        pm_notifier_call_chain(data->mode == O_RDONLY ?
                        PM_POST_HIBERNATION : PM_POST_RESTORE);
@@ -231,6 +238,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
                        break;
                pm_restore_gfp_mask();
                free_basic_memory_bitmaps();
+               data->free_bitmaps = false;
                thaw_processes();
                data->frozen = 0;
                break;
index 53cc09c..d7d498d 100644 (file)
@@ -328,10 +328,19 @@ void irq_enter(void)
 
 static inline void invoke_softirq(void)
 {
-       if (!force_irqthreads)
-               __do_softirq();
-       else
+       if (!force_irqthreads) {
+               /*
+                * We can safely execute softirq on the current stack if
+                * it is the irq stack, because it should be near empty
+                * at this stage. But we have no way to know if the arch
+                * calls irq_exit() on the irq stack. So call softirq
+                * in its own stack to prevent from any overrun on top
+                * of a potentially deep task stack.
+                */
+               do_softirq();
+       } else {
                wakeup_softirqd();
+       }
 }
 
 static inline void tick_irq_exit(void)
index 38959c8..662c579 100644 (file)
@@ -33,29 +33,64 @@ struct ce_unbind {
        int res;
 };
 
-/**
- * clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
- * @latch:     value to convert
- * @evt:       pointer to clock event device descriptor
- *
- * Math helper, returns latch value converted to nanoseconds (bound checked)
- */
-u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
+static u64 cev_delta2ns(unsigned long latch, struct clock_event_device *evt,
+                       bool ismax)
 {
        u64 clc = (u64) latch << evt->shift;
+       u64 rnd;
 
        if (unlikely(!evt->mult)) {
                evt->mult = 1;
                WARN_ON(1);
        }
+       rnd = (u64) evt->mult - 1;
+
+       /*
+        * Upper bound sanity check. If the backwards conversion is
+        * not equal latch, we know that the above shift overflowed.
+        */
+       if ((clc >> evt->shift) != (u64)latch)
+               clc = ~0ULL;
+
+       /*
+        * Scaled math oddities:
+        *
+        * For mult <= (1 << shift) we can safely add mult - 1 to
+        * prevent integer rounding loss. So the backwards conversion
+        * from nsec to device ticks will be correct.
+        *
+        * For mult > (1 << shift), i.e. device frequency is > 1GHz we
+        * need to be careful. Adding mult - 1 will result in a value
+        * which when converted back to device ticks can be larger
+        * than latch by up to (mult - 1) >> shift. For the min_delta
+        * calculation we still want to apply this in order to stay
+        * above the minimum device ticks limit. For the upper limit
+        * we would end up with a latch value larger than the upper
+        * limit of the device, so we omit the add to stay below the
+        * device upper boundary.
+        *
+        * Also omit the add if it would overflow the u64 boundary.
+        */
+       if ((~0ULL - clc > rnd) &&
+           (!ismax || evt->mult <= (1U << evt->shift)))
+               clc += rnd;
 
        do_div(clc, evt->mult);
-       if (clc < 1000)
-               clc = 1000;
-       if (clc > KTIME_MAX)
-               clc = KTIME_MAX;
 
-       return clc;
+       /* Deltas less than 1usec are pointless noise */
+       return clc > 1000 ? clc : 1000;
+}
+
+/**
+ * clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
+ * @latch:     value to convert
+ * @evt:       pointer to clock event device descriptor
+ *
+ * Math helper, returns latch value converted to nanoseconds (bound checked)
+ */
+u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
+{
+       return cev_delta2ns(latch, evt, false);
 }
 EXPORT_SYMBOL_GPL(clockevent_delta2ns);
 
@@ -380,8 +415,8 @@ void clockevents_config(struct clock_event_device *dev, u32 freq)
                sec = 600;
 
        clockevents_calc_mult_shift(dev, freq, sec);
-       dev->min_delta_ns = clockevent_delta2ns(dev->min_delta_ticks, dev);
-       dev->max_delta_ns = clockevent_delta2ns(dev->max_delta_ticks, dev);
+       dev->min_delta_ns = cev_delta2ns(dev->min_delta_ticks, dev, false);
+       dev->max_delta_ns = cev_delta2ns(dev->max_delta_ticks, dev, true);
 }
 
 /**
index 06344d9..094f315 100644 (file)
@@ -983,7 +983,7 @@ config DEBUG_KOBJECT
 
 config DEBUG_KOBJECT_RELEASE
        bool "kobject release debugging"
-       depends on DEBUG_KERNEL
+       depends on DEBUG_OBJECTS_TIMERS
        help
          kobjects are reference counted objects.  This means that their
          last reference count put is not predictable, and the kobject can
index 3f0494c..8499c81 100644 (file)
@@ -14,6 +14,8 @@
 
 const char hex_asc[] = "0123456789abcdef";
 EXPORT_SYMBOL(hex_asc);
+const char hex_asc_upper[] = "0123456789ABCDEF";
+EXPORT_SYMBOL(hex_asc_upper);
 
 /**
  * hex_to_bin - convert a hex digit to its real value
index 669bf19..084f7b1 100644 (file)
@@ -592,7 +592,7 @@ static void kobject_release(struct kref *kref)
 {
        struct kobject *kobj = container_of(kref, struct kobject, kref);
 #ifdef CONFIG_DEBUG_KOBJECT_RELEASE
-       pr_debug("kobject: '%s' (%p): %s, parent %p (delayed)\n",
+       pr_info("kobject: '%s' (%p): %s, parent %p (delayed)\n",
                 kobject_name(kobj), kobj, __func__, kobj->parent);
        INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup);
        schedule_delayed_work(&kobj->release, HZ);
index 7deeb62..1a53d49 100644 (file)
@@ -53,6 +53,7 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release)
        ref->release = release;
        return 0;
 }
+EXPORT_SYMBOL_GPL(percpu_ref_init);
 
 /**
  * percpu_ref_cancel_init - cancel percpu_ref_init()
@@ -84,6 +85,7 @@ void percpu_ref_cancel_init(struct percpu_ref *ref)
                free_percpu(ref->pcpu_count);
        }
 }
+EXPORT_SYMBOL_GPL(percpu_ref_cancel_init);
 
 static void percpu_ref_kill_rcu(struct rcu_head *rcu)
 {
@@ -156,3 +158,4 @@ void percpu_ref_kill_and_confirm(struct percpu_ref *ref,
 
        call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu);
 }
+EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm);
index a685c8a..d16fa29 100644 (file)
@@ -577,7 +577,8 @@ void sg_miter_stop(struct sg_mapping_iter *miter)
                miter->__offset += miter->consumed;
                miter->__remaining -= miter->consumed;
 
-               if (miter->__flags & SG_MITER_TO_SG)
+               if ((miter->__flags & SG_MITER_TO_SG) &&
+                   !PageSlab(miter->page))
                        flush_kernel_dcache_page(miter->page);
 
                if (miter->__flags & SG_MITER_ATOMIC) {
index 026771a..394838f 100644 (file)
@@ -183,7 +183,7 @@ config MEMORY_HOTPLUG_SPARSE
 config MEMORY_HOTREMOVE
        bool "Allow for memory hot remove"
        select MEMORY_ISOLATION
-       select HAVE_BOOTMEM_INFO_NODE if X86_64
+       select HAVE_BOOTMEM_INFO_NODE if (X86_64 || PPC64)
        depends on MEMORY_HOTPLUG && ARCH_ENABLE_MEMORY_HOTREMOVE
        depends on MIGRATION
 
index c9f0a43..5a7d58f 100644 (file)
@@ -204,6 +204,8 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
        struct bio_vec *to, *from;
        unsigned i;
 
+       if (force)
+               goto bounce;
        bio_for_each_segment(from, *bio_orig, i)
                if (page_to_pfn(from->bv_page) > queue_bounce_pfn(q))
                        goto bounce;
index c437893..b5326b1 100644 (file)
@@ -677,6 +677,13 @@ static void isolate_freepages(struct zone *zone,
                                        pfn -= pageblock_nr_pages) {
                unsigned long isolated;
 
+               /*
+                * This can iterate a massively long zone without finding any
+                * suitable migration targets, so periodically check if we need
+                * to schedule.
+                */
+               cond_resched();
+
                if (!pfn_valid(pfn))
                        continue;
 
index 1e6aec4..ae4846f 100644 (file)
@@ -1616,7 +1616,6 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        struct inode *inode = mapping->host;
        pgoff_t offset = vmf->pgoff;
        struct page *page;
-       bool memcg_oom;
        pgoff_t size;
        int ret = 0;
 
@@ -1625,11 +1624,7 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                return VM_FAULT_SIGBUS;
 
        /*
-        * Do we have something in the page cache already?  Either
-        * way, try readahead, but disable the memcg OOM killer for it
-        * as readahead is optional and no errors are propagated up
-        * the fault stack.  The OOM killer is enabled while trying to
-        * instantiate the faulting page individually below.
+        * Do we have something in the page cache already?
         */
        page = find_get_page(mapping, offset);
        if (likely(page) && !(vmf->flags & FAULT_FLAG_TRIED)) {
@@ -1637,14 +1632,10 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                 * We found the page, so try async readahead before
                 * waiting for the lock.
                 */
-               memcg_oom = mem_cgroup_toggle_oom(false);
                do_async_mmap_readahead(vma, ra, file, page, offset);
-               mem_cgroup_toggle_oom(memcg_oom);
        } else if (!page) {
                /* No page in the page cache at all */
-               memcg_oom = mem_cgroup_toggle_oom(false);
                do_sync_mmap_readahead(vma, ra, file, offset);
-               mem_cgroup_toggle_oom(memcg_oom);
                count_vm_event(PGMAJFAULT);
                mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
                ret = VM_FAULT_MAJOR;
index 7489884..cca80d9 100644 (file)
@@ -1278,64 +1278,90 @@ out:
 int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                                unsigned long addr, pmd_t pmd, pmd_t *pmdp)
 {
+       struct anon_vma *anon_vma = NULL;
        struct page *page;
        unsigned long haddr = addr & HPAGE_PMD_MASK;
+       int page_nid = -1, this_nid = numa_node_id();
        int target_nid;
-       int current_nid = -1;
-       bool migrated;
+       bool page_locked;
+       bool migrated = false;
 
        spin_lock(&mm->page_table_lock);
        if (unlikely(!pmd_same(pmd, *pmdp)))
                goto out_unlock;
 
        page = pmd_page(pmd);
-       get_page(page);
-       current_nid = page_to_nid(page);
+       page_nid = page_to_nid(page);
        count_vm_numa_event(NUMA_HINT_FAULTS);
-       if (current_nid == numa_node_id())
+       if (page_nid == this_nid)
                count_vm_numa_event(NUMA_HINT_FAULTS_LOCAL);
 
+       /*
+        * Acquire the page lock to serialise THP migrations but avoid dropping
+        * page_table_lock if at all possible
+        */
+       page_locked = trylock_page(page);
        target_nid = mpol_misplaced(page, vma, haddr);
        if (target_nid == -1) {
-               put_page(page);
-               goto clear_pmdnuma;
+               /* If the page was locked, there are no parallel migrations */
+               if (page_locked)
+                       goto clear_pmdnuma;
+
+               /*
+                * Otherwise wait for potential migrations and retry. We do
+                * relock and check_same as the page may no longer be mapped.
+                * As the fault is being retried, do not account for it.
+                */
+               spin_unlock(&mm->page_table_lock);
+               wait_on_page_locked(page);
+               page_nid = -1;
+               goto out;
        }
 
-       /* Acquire the page lock to serialise THP migrations */
+       /* Page is misplaced, serialise migrations and parallel THP splits */
+       get_page(page);
        spin_unlock(&mm->page_table_lock);
-       lock_page(page);
+       if (!page_locked)
+               lock_page(page);
+       anon_vma = page_lock_anon_vma_read(page);
 
        /* Confirm the PTE did not while locked */
        spin_lock(&mm->page_table_lock);
        if (unlikely(!pmd_same(pmd, *pmdp))) {
                unlock_page(page);
                put_page(page);
+               page_nid = -1;
                goto out_unlock;
        }
-       spin_unlock(&mm->page_table_lock);
 
-       /* Migrate the THP to the requested node */
+       /*
+        * Migrate the THP to the requested node, returns with page unlocked
+        * and pmd_numa cleared.
+        */
+       spin_unlock(&mm->page_table_lock);
        migrated = migrate_misplaced_transhuge_page(mm, vma,
                                pmdp, pmd, addr, page, target_nid);
-       if (!migrated)
-               goto check_same;
+       if (migrated)
+               page_nid = target_nid;
 
-       task_numa_fault(target_nid, HPAGE_PMD_NR, true);
-       return 0;
-
-check_same:
-       spin_lock(&mm->page_table_lock);
-       if (unlikely(!pmd_same(pmd, *pmdp)))
-               goto out_unlock;
+       goto out;
 clear_pmdnuma:
+       BUG_ON(!PageLocked(page));
        pmd = pmd_mknonnuma(pmd);
        set_pmd_at(mm, haddr, pmdp, pmd);
        VM_BUG_ON(pmd_numa(*pmdp));
        update_mmu_cache_pmd(vma, addr, pmdp);
+       unlock_page(page);
 out_unlock:
        spin_unlock(&mm->page_table_lock);
-       if (current_nid != -1)
-               task_numa_fault(current_nid, HPAGE_PMD_NR, false);
+
+out:
+       if (anon_vma)
+               page_unlock_anon_vma_read(anon_vma);
+
+       if (page_nid != -1)
+               task_numa_fault(page_nid, HPAGE_PMD_NR, migrated);
+
        return 0;
 }
 
@@ -2697,6 +2723,7 @@ void __split_huge_page_pmd(struct vm_area_struct *vma, unsigned long address,
 
        mmun_start = haddr;
        mmun_end   = haddr + HPAGE_PMD_SIZE;
+again:
        mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
        spin_lock(&mm->page_table_lock);
        if (unlikely(!pmd_trans_huge(*pmd))) {
@@ -2719,7 +2746,14 @@ void __split_huge_page_pmd(struct vm_area_struct *vma, unsigned long address,
        split_huge_page(page);
 
        put_page(page);
-       BUG_ON(pmd_trans_huge(*pmd));
+
+       /*
+        * We don't always have down_write of mmap_sem here: a racing
+        * do_huge_pmd_wp_page() might have copied-on-write to another
+        * huge page before our split_huge_page() got the anon_vma lock.
+        */
+       if (unlikely(pmd_trans_huge(*pmd)))
+               goto again;
 }
 
 void split_huge_page_pmd_mm(struct mm_struct *mm, unsigned long address,
index b49579c..0b7656e 100644 (file)
@@ -653,6 +653,7 @@ static void free_huge_page(struct page *page)
        BUG_ON(page_count(page));
        BUG_ON(page_mapcount(page));
        restore_reserve = PagePrivate(page);
+       ClearPagePrivate(page);
 
        spin_lock(&hugetlb_lock);
        hugetlb_cgroup_uncharge_page(hstate_index(h),
@@ -695,8 +696,22 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order)
        /* we rely on prep_new_huge_page to set the destructor */
        set_compound_order(page, 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
+                * hugepages and clear the PG_reserved bit from all tail pages
+                * too.  Otherwse drivers using get_user_pages() to access tail
+                * pages may get the reference counting wrong if they see
+                * PG_reserved set on a tail page (despite the head page not
+                * having PG_reserved set).  Enforcing this consistency between
+                * head and tail pages allows drivers to optimize away a check
+                * on the head page when they need know if put_page() is needed
+                * after get_user_pages().
+                */
+               __ClearPageReserved(p);
                set_page_count(p, 0);
                p->first_page = page;
        }
@@ -1329,9 +1344,9 @@ static void __init gather_bootmem_prealloc(void)
 #else
                page = virt_to_page(m);
 #endif
-               __ClearPageReserved(page);
                WARN_ON(page_count(page) != 1);
                prep_compound_huge_page(page, h->order);
+               WARN_ON(PageReserved(page));
                prep_new_huge_page(h, page, page_to_nid(page));
                /*
                 * If we had gigantic hugepages allocated at boot time, we need
index afc2daa..4c84678 100644 (file)
@@ -20,8 +20,6 @@ static int hwpoison_inject(void *data, u64 val)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (!hwpoison_filter_enable)
-               goto inject;
        if (!pfn_valid(pfn))
                return -ENXIO;
 
@@ -33,6 +31,9 @@ static int hwpoison_inject(void *data, u64 val)
        if (!get_page_unless_zero(hpage))
                return 0;
 
+       if (!hwpoison_filter_enable)
+               goto inject;
+
        if (!PageLRU(p) && !PageHuge(p))
                shake_page(p, 0);
        /*
index 7246791..72f9dec 100644 (file)
@@ -81,8 +81,9 @@ restart:
                 * decrement nr_to_walk first so that we don't livelock if we
                 * get stuck on large numbesr of LRU_RETRY items
                 */
-               if (--(*nr_to_walk) == 0)
+               if (!*nr_to_walk)
                        break;
+               --*nr_to_walk;
 
                ret = isolate(item, &nlru->lock, cb_arg);
                switch (ret) {
index 6975bc8..539eeb9 100644 (file)
@@ -343,10 +343,11 @@ static long madvise_remove(struct vm_area_struct *vma,
  */
 static int madvise_hwpoison(int bhv, unsigned long start, unsigned long end)
 {
+       struct page *p;
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
-       for (; start < end; start += PAGE_SIZE) {
-               struct page *p;
+       for (; start < end; start += PAGE_SIZE <<
+                               compound_order(compound_head(p))) {
                int ret;
 
                ret = get_user_pages_fast(start, 1, 0, &p);
index 1c52ddb..13b9d0f 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/page_cgroup.h>
 #include <linux/cpu.h>
 #include <linux/oom.h>
+#include <linux/lockdep.h>
 #include "internal.h"
 #include <net/sock.h>
 #include <net/ip.h>
@@ -866,6 +867,7 @@ static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg,
        unsigned long val = 0;
        int cpu;
 
+       get_online_cpus();
        for_each_online_cpu(cpu)
                val += per_cpu(memcg->stat->events[idx], cpu);
 #ifdef CONFIG_HOTPLUG_CPU
@@ -873,6 +875,7 @@ static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg,
        val += memcg->nocpu_base.events[idx];
        spin_unlock(&memcg->pcp_counter_lock);
 #endif
+       put_online_cpus();
        return val;
 }
 
@@ -2044,6 +2047,12 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
        return total;
 }
 
+#ifdef CONFIG_LOCKDEP
+static struct lockdep_map memcg_oom_lock_dep_map = {
+       .name = "memcg_oom_lock",
+};
+#endif
+
 static DEFINE_SPINLOCK(memcg_oom_lock);
 
 /*
@@ -2081,7 +2090,8 @@ static bool mem_cgroup_oom_trylock(struct mem_cgroup *memcg)
                        }
                        iter->oom_lock = false;
                }
-       }
+       } else
+               mutex_acquire(&memcg_oom_lock_dep_map, 0, 1, _RET_IP_);
 
        spin_unlock(&memcg_oom_lock);
 
@@ -2093,6 +2103,7 @@ static void mem_cgroup_oom_unlock(struct mem_cgroup *memcg)
        struct mem_cgroup *iter;
 
        spin_lock(&memcg_oom_lock);
+       mutex_release(&memcg_oom_lock_dep_map, 1, _RET_IP_);
        for_each_mem_cgroup_tree(iter, memcg)
                iter->oom_lock = false;
        spin_unlock(&memcg_oom_lock);
@@ -2159,110 +2170,59 @@ static void memcg_oom_recover(struct mem_cgroup *memcg)
                memcg_wakeup_oom(memcg);
 }
 
-/*
- * try to call OOM killer
- */
 static void mem_cgroup_oom(struct mem_cgroup *memcg, gfp_t mask, int order)
 {
-       bool locked;
-       int wakeups;
-
        if (!current->memcg_oom.may_oom)
                return;
-
-       current->memcg_oom.in_memcg_oom = 1;
-
        /*
-        * As with any blocking lock, a contender needs to start
-        * listening for wakeups before attempting the trylock,
-        * otherwise it can miss the wakeup from the unlock and sleep
-        * indefinitely.  This is just open-coded because our locking
-        * is so particular to memcg hierarchies.
+        * We are in the middle of the charge context here, so we
+        * don't want to block when potentially sitting on a callstack
+        * that holds all kinds of filesystem and mm locks.
+        *
+        * Also, the caller may handle a failed allocation gracefully
+        * (like optional page cache readahead) and so an OOM killer
+        * invocation might not even be necessary.
+        *
+        * That's why we don't do anything here except remember the
+        * OOM context and then deal with it at the end of the page
+        * fault when the stack is unwound, the locks are released,
+        * and when we know whether the fault was overall successful.
         */
-       wakeups = atomic_read(&memcg->oom_wakeups);
-       mem_cgroup_mark_under_oom(memcg);
-
-       locked = mem_cgroup_oom_trylock(memcg);
-
-       if (locked)
-               mem_cgroup_oom_notify(memcg);
-
-       if (locked && !memcg->oom_kill_disable) {
-               mem_cgroup_unmark_under_oom(memcg);
-               mem_cgroup_out_of_memory(memcg, mask, order);
-               mem_cgroup_oom_unlock(memcg);
-               /*
-                * There is no guarantee that an OOM-lock contender
-                * sees the wakeups triggered by the OOM kill
-                * uncharges.  Wake any sleepers explicitely.
-                */
-               memcg_oom_recover(memcg);
-       } else {
-               /*
-                * A system call can just return -ENOMEM, but if this
-                * is a page fault and somebody else is handling the
-                * OOM already, we need to sleep on the OOM waitqueue
-                * for this memcg until the situation is resolved.
-                * Which can take some time because it might be
-                * handled by a userspace task.
-                *
-                * However, this is the charge context, which means
-                * that we may sit on a large call stack and hold
-                * various filesystem locks, the mmap_sem etc. and we
-                * don't want the OOM handler to deadlock on them
-                * while we sit here and wait.  Store the current OOM
-                * context in the task_struct, then return -ENOMEM.
-                * At the end of the page fault handler, with the
-                * stack unwound, pagefault_out_of_memory() will check
-                * back with us by calling
-                * mem_cgroup_oom_synchronize(), possibly putting the
-                * task to sleep.
-                */
-               current->memcg_oom.oom_locked = locked;
-               current->memcg_oom.wakeups = wakeups;
-               css_get(&memcg->css);
-               current->memcg_oom.wait_on_memcg = memcg;
-       }
+       css_get(&memcg->css);
+       current->memcg_oom.memcg = memcg;
+       current->memcg_oom.gfp_mask = mask;
+       current->memcg_oom.order = order;
 }
 
 /**
  * mem_cgroup_oom_synchronize - complete memcg OOM handling
+ * @handle: actually kill/wait or just clean up the OOM state
  *
- * This has to be called at the end of a page fault if the the memcg
- * OOM handler was enabled and the fault is returning %VM_FAULT_OOM.
+ * This has to be called at the end of a page fault if the memcg OOM
+ * handler was enabled.
  *
- * Memcg supports userspace OOM handling, so failed allocations must
+ * Memcg supports userspace OOM handling where failed allocations must
  * sleep on a waitqueue until the userspace task resolves the
  * situation.  Sleeping directly in the charge context with all kinds
  * of locks held is not a good idea, instead we remember an OOM state
  * in the task and mem_cgroup_oom_synchronize() has to be called at
- * the end of the page fault to put the task to sleep and clean up the
- * OOM state.
+ * the end of the page fault to complete the OOM handling.
  *
  * Returns %true if an ongoing memcg OOM situation was detected and
- * finalized, %false otherwise.
+ * completed, %false otherwise.
  */
-bool mem_cgroup_oom_synchronize(void)
+bool mem_cgroup_oom_synchronize(bool handle)
 {
+       struct mem_cgroup *memcg = current->memcg_oom.memcg;
        struct oom_wait_info owait;
-       struct mem_cgroup *memcg;
+       bool locked;
 
        /* OOM is global, do not handle */
-       if (!current->memcg_oom.in_memcg_oom)
-               return false;
-
-       /*
-        * We invoked the OOM killer but there is a chance that a kill
-        * did not free up any charges.  Everybody else might already
-        * be sleeping, so restart the fault and keep the rampage
-        * going until some charges are released.
-        */
-       memcg = current->memcg_oom.wait_on_memcg;
        if (!memcg)
-               goto out;
+               return false;
 
-       if (test_thread_flag(TIF_MEMDIE) || fatal_signal_pending(current))
-               goto out_memcg;
+       if (!handle)
+               goto cleanup;
 
        owait.memcg = memcg;
        owait.wait.flags = 0;
@@ -2271,13 +2231,25 @@ bool mem_cgroup_oom_synchronize(void)
        INIT_LIST_HEAD(&owait.wait.task_list);
 
        prepare_to_wait(&memcg_oom_waitq, &owait.wait, TASK_KILLABLE);
-       /* Only sleep if we didn't miss any wakeups since OOM */
-       if (atomic_read(&memcg->oom_wakeups) == current->memcg_oom.wakeups)
+       mem_cgroup_mark_under_oom(memcg);
+
+       locked = mem_cgroup_oom_trylock(memcg);
+
+       if (locked)
+               mem_cgroup_oom_notify(memcg);
+
+       if (locked && !memcg->oom_kill_disable) {
+               mem_cgroup_unmark_under_oom(memcg);
+               finish_wait(&memcg_oom_waitq, &owait.wait);
+               mem_cgroup_out_of_memory(memcg, current->memcg_oom.gfp_mask,
+                                        current->memcg_oom.order);
+       } else {
                schedule();
-       finish_wait(&memcg_oom_waitq, &owait.wait);
-out_memcg:
-       mem_cgroup_unmark_under_oom(memcg);
-       if (current->memcg_oom.oom_locked) {
+               mem_cgroup_unmark_under_oom(memcg);
+               finish_wait(&memcg_oom_waitq, &owait.wait);
+       }
+
+       if (locked) {
                mem_cgroup_oom_unlock(memcg);
                /*
                 * There is no guarantee that an OOM-lock contender
@@ -2286,10 +2258,9 @@ out_memcg:
                 */
                memcg_oom_recover(memcg);
        }
+cleanup:
+       current->memcg_oom.memcg = NULL;
        css_put(&memcg->css);
-       current->memcg_oom.wait_on_memcg = NULL;
-out:
-       current->memcg_oom.in_memcg_oom = 0;
        return true;
 }
 
@@ -2703,6 +2674,9 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
                     || fatal_signal_pending(current)))
                goto bypass;
 
+       if (unlikely(task_in_memcg_oom(current)))
+               goto bypass;
+
        /*
         * We always charge the cgroup the mm_struct belongs to.
         * The mm_struct's mem_cgroup changes on task migration if the
@@ -2800,8 +2774,10 @@ done:
        *ptr = memcg;
        return 0;
 nomem:
-       *ptr = NULL;
-       return -ENOMEM;
+       if (!(gfp_mask & __GFP_NOFAIL)) {
+               *ptr = NULL;
+               return -ENOMEM;
+       }
 bypass:
        *ptr = root_mem_cgroup;
        return -EINTR;
@@ -3806,8 +3782,7 @@ void mem_cgroup_move_account_page_stat(struct mem_cgroup *from,
 {
        /* Update stat data for mem_cgroup */
        preempt_disable();
-       WARN_ON_ONCE(from->stat->count[idx] < nr_pages);
-       __this_cpu_add(from->stat->count[idx], -nr_pages);
+       __this_cpu_sub(from->stat->count[idx], nr_pages);
        __this_cpu_add(to->stat->count[idx], nr_pages);
        preempt_enable();
 }
@@ -4983,31 +4958,18 @@ static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
        } while (usage > 0);
 }
 
-/*
- * This mainly exists for tests during the setting of set of use_hierarchy.
- * Since this is the very setting we are changing, the current hierarchy value
- * is meaningless
- */
-static inline bool __memcg_has_children(struct mem_cgroup *memcg)
-{
-       struct cgroup_subsys_state *pos;
-
-       /* bounce at first found */
-       css_for_each_child(pos, &memcg->css)
-               return true;
-       return false;
-}
-
-/*
- * Must be called with memcg_create_mutex held, unless the cgroup is guaranteed
- * to be already dead (as in mem_cgroup_force_empty, for instance).  This is
- * from mem_cgroup_count_children(), in the sense that we don't really care how
- * many children we have; we only need to know if we have any.  It also counts
- * any memcg without hierarchy as infertile.
- */
 static inline bool memcg_has_children(struct mem_cgroup *memcg)
 {
-       return memcg->use_hierarchy && __memcg_has_children(memcg);
+       lockdep_assert_held(&memcg_create_mutex);
+       /*
+        * The lock does not prevent addition or deletion to the list
+        * of children, but it prevents a new child from being
+        * initialized based on this parent in css_online(), so it's
+        * enough to decide whether hierarchically inherited
+        * attributes can still be changed or not.
+        */
+       return memcg->use_hierarchy &&
+               !list_empty(&memcg->css.cgroup->children);
 }
 
 /*
@@ -5087,7 +5049,7 @@ static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css,
         */
        if ((!parent_memcg || !parent_memcg->use_hierarchy) &&
                                (val == 1 || val == 0)) {
-               if (!__memcg_has_children(memcg))
+               if (list_empty(&memcg->css.cgroup->children))
                        memcg->use_hierarchy = val;
                else
                        retval = -EBUSY;
index 947ed54..bf3351b 100644 (file)
@@ -1114,8 +1114,10 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
                         * shake_page could have turned it free.
                         */
                        if (is_free_buddy_page(p)) {
-                               action_result(pfn, "free buddy, 2nd try",
-                                               DELAYED);
+                               if (flags & MF_COUNT_INCREASED)
+                                       action_result(pfn, "free buddy", DELAYED);
+                               else
+                                       action_result(pfn, "free buddy, 2nd try", DELAYED);
                                return 0;
                        }
                        action_result(pfn, "non LRU", IGNORED);
@@ -1349,7 +1351,7 @@ int unpoison_memory(unsigned long pfn)
         * worked by memory_failure() and the page lock is not held yet.
         * In such case, we yield to memory_failure() and make unpoison fail.
         */
-       if (PageTransHuge(page)) {
+       if (!PageHuge(page) && PageTransHuge(page)) {
                pr_info("MCE: Memory failure is now running on %#lx\n", pfn);
                        return 0;
        }
index ca00039..d176154 100644 (file)
@@ -837,6 +837,8 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                                         */
                                        make_migration_entry_read(&entry);
                                        pte = swp_entry_to_pte(entry);
+                                       if (pte_swp_soft_dirty(*src_pte))
+                                               pte = pte_swp_mksoft_dirty(pte);
                                        set_pte_at(src_mm, addr, src_pte, pte);
                                }
                        }
@@ -3519,12 +3521,12 @@ static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
 }
 
 int numa_migrate_prep(struct page *page, struct vm_area_struct *vma,
-                               unsigned long addr, int current_nid)
+                               unsigned long addr, int page_nid)
 {
        get_page(page);
 
        count_vm_numa_event(NUMA_HINT_FAULTS);
-       if (current_nid == numa_node_id())
+       if (page_nid == numa_node_id())
                count_vm_numa_event(NUMA_HINT_FAULTS_LOCAL);
 
        return mpol_misplaced(page, vma, addr);
@@ -3535,7 +3537,7 @@ int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
 {
        struct page *page = NULL;
        spinlock_t *ptl;
-       int current_nid = -1;
+       int page_nid = -1;
        int target_nid;
        bool migrated = false;
 
@@ -3565,15 +3567,10 @@ int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                return 0;
        }
 
-       current_nid = page_to_nid(page);
-       target_nid = numa_migrate_prep(page, vma, addr, current_nid);
+       page_nid = page_to_nid(page);
+       target_nid = numa_migrate_prep(page, vma, addr, page_nid);
        pte_unmap_unlock(ptep, ptl);
        if (target_nid == -1) {
-               /*
-                * Account for the fault against the current node if it not
-                * being replaced regardless of where the page is located.
-                */
-               current_nid = numa_node_id();
                put_page(page);
                goto out;
        }
@@ -3581,11 +3578,11 @@ int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        /* Migrate to the requested node */
        migrated = migrate_misplaced_page(page, target_nid);
        if (migrated)
-               current_nid = target_nid;
+               page_nid = target_nid;
 
 out:
-       if (current_nid != -1)
-               task_numa_fault(current_nid, 1, migrated);
+       if (page_nid != -1)
+               task_numa_fault(page_nid, 1, migrated);
        return 0;
 }
 
@@ -3600,7 +3597,6 @@ static int do_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        unsigned long offset;
        spinlock_t *ptl;
        bool numa = false;
-       int local_nid = numa_node_id();
 
        spin_lock(&mm->page_table_lock);
        pmd = *pmdp;
@@ -3623,9 +3619,10 @@ static int do_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        for (addr = _addr + offset; addr < _addr + PMD_SIZE; pte++, addr += PAGE_SIZE) {
                pte_t pteval = *pte;
                struct page *page;
-               int curr_nid = local_nid;
+               int page_nid = -1;
                int target_nid;
-               bool migrated;
+               bool migrated = false;
+
                if (!pte_present(pteval))
                        continue;
                if (!pte_numa(pteval))
@@ -3647,25 +3644,19 @@ static int do_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                if (unlikely(page_mapcount(page) != 1))
                        continue;
 
-               /*
-                * Note that the NUMA fault is later accounted to either
-                * the node that is currently running or where the page is
-                * migrated to.
-                */
-               curr_nid = local_nid;
-               target_nid = numa_migrate_prep(page, vma, addr,
-                                              page_to_nid(page));
-               if (target_nid == -1) {
+               page_nid = page_to_nid(page);
+               target_nid = numa_migrate_prep(page, vma, addr, page_nid);
+               pte_unmap_unlock(pte, ptl);
+               if (target_nid != -1) {
+                       migrated = migrate_misplaced_page(page, target_nid);
+                       if (migrated)
+                               page_nid = target_nid;
+               } else {
                        put_page(page);
-                       continue;
                }
 
-               /* Migrate to the requested node */
-               pte_unmap_unlock(pte, ptl);
-               migrated = migrate_misplaced_page(page, target_nid);
-               if (migrated)
-                       curr_nid = target_nid;
-               task_numa_fault(curr_nid, 1, migrated);
+               if (page_nid != -1)
+                       task_numa_fault(page_nid, 1, migrated);
 
                pte = pte_offset_map_lock(mm, pmdp, addr, &ptl);
        }
@@ -3863,15 +3854,21 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
         * space.  Kernel faults are handled more gracefully.
         */
        if (flags & FAULT_FLAG_USER)
-               mem_cgroup_enable_oom();
+               mem_cgroup_oom_enable();
 
        ret = __handle_mm_fault(mm, vma, address, flags);
 
-       if (flags & FAULT_FLAG_USER)
-               mem_cgroup_disable_oom();
-
-       if (WARN_ON(task_in_memcg_oom(current) && !(ret & VM_FAULT_OOM)))
-               mem_cgroup_oom_synchronize();
+       if (flags & FAULT_FLAG_USER) {
+               mem_cgroup_oom_disable();
+                /*
+                 * The task may have entered a memcg OOM situation but
+                 * if the allocation error was handled gracefully (no
+                 * VM_FAULT_OOM), there is no need to kill anything.
+                 * Just clean up the OOM state peacefully.
+                 */
+                if (task_in_memcg_oom(current) && !(ret & VM_FAULT_OOM))
+                        mem_cgroup_oom_synchronize(false);
+       }
 
        return ret;
 }
index 9c8d5f5..c046927 100644 (file)
@@ -107,7 +107,7 @@ void putback_movable_pages(struct list_head *l)
                list_del(&page->lru);
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
-               if (unlikely(balloon_page_movable(page)))
+               if (unlikely(isolated_balloon_page(page)))
                        balloon_page_putback(page);
                else
                        putback_lru_page(page);
@@ -161,6 +161,8 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
 
        get_page(new);
        pte = pte_mkold(mk_pte(new, vma->vm_page_prot));
+       if (pte_swp_soft_dirty(*ptep))
+               pte = pte_mksoft_dirty(pte);
        if (is_write_migration_entry(entry))
                pte = pte_mkwrite(pte);
 #ifdef CONFIG_HUGETLB_PAGE
@@ -1713,12 +1715,12 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
                unlock_page(new_page);
                put_page(new_page);             /* Free it */
 
-               unlock_page(page);
+               /* Retake the callers reference and putback on LRU */
+               get_page(page);
                putback_lru_page(page);
-
-               count_vm_events(PGMIGRATE_FAIL, HPAGE_PMD_NR);
-               isolated = 0;
-               goto out;
+               mod_zone_page_state(page_zone(page),
+                        NR_ISOLATED_ANON + page_lru, -HPAGE_PMD_NR);
+               goto out_fail;
        }
 
        /*
@@ -1735,9 +1737,9 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
        entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
        entry = pmd_mkhuge(entry);
 
-       page_add_new_anon_rmap(new_page, vma, haddr);
-
+       pmdp_clear_flush(vma, haddr, pmd);
        set_pmd_at(mm, haddr, pmd, entry);
+       page_add_new_anon_rmap(new_page, vma, haddr);
        update_mmu_cache_pmd(vma, address, &entry);
        page_remove_rmap(page);
        /*
@@ -1756,7 +1758,6 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
        count_vm_events(PGMIGRATE_SUCCESS, HPAGE_PMD_NR);
        count_vm_numa_events(NUMA_PAGE_MIGRATE, HPAGE_PMD_NR);
 
-out:
        mod_zone_page_state(page_zone(page),
                        NR_ISOLATED_ANON + page_lru,
                        -HPAGE_PMD_NR);
@@ -1765,6 +1766,10 @@ out:
 out_fail:
        count_vm_events(PGMIGRATE_FAIL, HPAGE_PMD_NR);
 out_dropref:
+       entry = pmd_mknonnuma(entry);
+       set_pmd_at(mm, haddr, pmd, entry);
+       update_mmu_cache_pmd(vma, address, &entry);
+
        unlock_page(page);
        put_page(page);
        return 0;
index 67ba6da..d480cd6 100644 (file)
@@ -379,10 +379,14 @@ static unsigned long __munlock_pagevec_fill(struct pagevec *pvec,
 
        /*
         * Initialize pte walk starting at the already pinned page where we
-        * are sure that there is a pte.
+        * are sure that there is a pte, as it was pinned under the same
+        * mmap_sem write op.
         */
        pte = get_locked_pte(vma->vm_mm, start, &ptl);
-       end = min(end, pmd_addr_end(start, end));
+       /* Make sure we do not cross the page table boundary */
+       end = pgd_addr_end(start, end);
+       end = pud_addr_end(start, end);
+       end = pmd_addr_end(start, end);
 
        /* The page next to the pinned page is the first we will try to get */
        start += PAGE_SIZE;
index 94722a4..412ba2b 100644 (file)
@@ -94,13 +94,16 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                        swp_entry_t entry = pte_to_swp_entry(oldpte);
 
                        if (is_write_migration_entry(entry)) {
+                               pte_t newpte;
                                /*
                                 * A protection check is difficult so
                                 * just be safe and disable write
                                 */
                                make_migration_entry_read(&entry);
-                               set_pte_at(mm, addr, pte,
-                                       swp_entry_to_pte(entry));
+                               newpte = swp_entry_to_pte(entry);
+                               if (pte_swp_soft_dirty(oldpte))
+                                       newpte = pte_swp_mksoft_dirty(newpte);
+                               set_pte_at(mm, addr, pte, newpte);
                        }
                        pages++;
                }
@@ -145,7 +148,7 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
                                split_huge_page_pmd(vma, addr, pmd);
                        else if (change_huge_pmd(vma, pmd, addr, newprot,
                                                 prot_numa)) {
-                               pages += HPAGE_PMD_NR;
+                               pages++;
                                continue;
                        }
                        /* fall through */
index 91b13d6..0843feb 100644 (file)
@@ -25,7 +25,6 @@
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
-#include <asm/pgalloc.h>
 
 #include "internal.h"
 
@@ -63,10 +62,8 @@ static pmd_t *alloc_new_pmd(struct mm_struct *mm, struct vm_area_struct *vma,
                return NULL;
 
        pmd = pmd_alloc(mm, pud, addr);
-       if (!pmd) {
-               pud_free(mm, pud);
+       if (!pmd)
                return NULL;
-       }
 
        VM_BUG_ON(pmd_trans_huge(*pmd));
 
index 314e9d2..6738c47 100644 (file)
@@ -680,7 +680,7 @@ void pagefault_out_of_memory(void)
 {
        struct zonelist *zonelist;
 
-       if (mem_cgroup_oom_synchronize())
+       if (mem_cgroup_oom_synchronize(true))
                return;
 
        zonelist = node_zonelist(first_online_node, GFP_KERNEL);
index f5236f8..6380758 100644 (file)
@@ -1210,11 +1210,11 @@ static unsigned long dirty_poll_interval(unsigned long dirty,
        return 1;
 }
 
-static long bdi_max_pause(struct backing_dev_info *bdi,
-                         unsigned long bdi_dirty)
+static unsigned long bdi_max_pause(struct backing_dev_info *bdi,
+                                  unsigned long bdi_dirty)
 {
-       long bw = bdi->avg_write_bandwidth;
-       long t;
+       unsigned long bw = bdi->avg_write_bandwidth;
+       unsigned long t;
 
        /*
         * Limit pause time for small memory systems. If sleeping for too long
@@ -1226,7 +1226,7 @@ static long bdi_max_pause(struct backing_dev_info *bdi,
        t = bdi_dirty / (1 + bw / roundup_pow_of_two(1 + HZ / 8));
        t++;
 
-       return min_t(long, t, MAX_PAUSE);
+       return min_t(unsigned long, t, MAX_PAUSE);
 }
 
 static long bdi_min_pause(struct backing_dev_info *bdi,
index 0ee638f..dd886fa 100644 (file)
@@ -6366,10 +6366,6 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
                list_del(&page->lru);
                rmv_page_order(page);
                zone->free_area[order].nr_free--;
-#ifdef CONFIG_HIGHMEM
-               if (PageHighMem(page))
-                       totalhigh_pages -= 1 << order;
-#endif
                for (i = 0; i < (1 << order); i++)
                        SetPageReserved((page+i));
                pfn += (1 << order);
index 5da2cbc..2beeabf 100644 (file)
@@ -242,7 +242,7 @@ int walk_page_range(unsigned long addr, unsigned long end,
                if (err)
                        break;
                pgd++;
-       } while (addr = next, addr != end);
+       } while (addr = next, addr < end);
 
        return err;
 }
index a344327..e2e98af 100644 (file)
@@ -56,6 +56,7 @@ static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name,
                        continue;
                }
 
+#if !defined(CONFIG_SLUB) || !defined(CONFIG_SLUB_DEBUG_ON)
                /*
                 * For simplicity, we won't check this in the list of memcg
                 * caches. We have control over memcg naming, and if there
@@ -69,6 +70,7 @@ static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name,
                        s = NULL;
                        return -EINVAL;
                }
+#endif
        }
 
        WARN_ON(strchr(name, ' '));     /* It confuses parsers */
index 3963fc2..de7c904 100644 (file)
@@ -1824,6 +1824,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        struct filename *pathname;
        int i, type, prev;
        int err;
+       unsigned int old_block_size;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1914,6 +1915,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        }
 
        swap_file = p->swap_file;
+       old_block_size = p->old_block_size;
        p->swap_file = NULL;
        p->max = 0;
        swap_map = p->swap_map;
@@ -1938,7 +1940,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        inode = mapping->host;
        if (S_ISBLK(inode->i_mode)) {
                struct block_device *bdev = I_BDEV(inode);
-               set_blocksize(bdev, p->old_block_size);
+               set_blocksize(bdev, old_block_size);
                blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
        } else {
                mutex_lock(&inode->i_mutex);
index beb3577..eea668d 100644 (file)
@@ -48,6 +48,7 @@
 #include <asm/div64.h>
 
 #include <linux/swapops.h>
+#include <linux/balloon_compaction.h>
 
 #include "internal.h"
 
@@ -210,6 +211,7 @@ void unregister_shrinker(struct shrinker *shrinker)
        down_write(&shrinker_rwsem);
        list_del(&shrinker->list);
        up_write(&shrinker_rwsem);
+       kfree(shrinker->nr_deferred);
 }
 EXPORT_SYMBOL(unregister_shrinker);
 
@@ -1113,7 +1115,8 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
        LIST_HEAD(clean_pages);
 
        list_for_each_entry_safe(page, next, page_list, lru) {
-               if (page_is_file_cache(page) && !PageDirty(page)) {
+               if (page_is_file_cache(page) && !PageDirty(page) &&
+                   !isolated_balloon_page(page)) {
                        ClearPageActive(page);
                        list_move(&page->lru, &clean_pages);
                }
index 841e35f..d93510c 100644 (file)
@@ -804,6 +804,10 @@ static void zswap_frontswap_invalidate_area(unsigned type)
        }
        tree->rbroot = RB_ROOT;
        spin_unlock(&tree->lock);
+
+       zbud_destroy_pool(tree->pool);
+       kfree(tree);
+       zswap_trees[type] = NULL;
 }
 
 static struct zbud_ops zswap_zbud_ops = {
index 1eb05d8..3ed6162 100644 (file)
 static unsigned int mrp_join_time __read_mostly = 200;
 module_param(mrp_join_time, uint, 0644);
 MODULE_PARM_DESC(mrp_join_time, "Join time in ms (default 200ms)");
+
+static unsigned int mrp_periodic_time __read_mostly = 1000;
+module_param(mrp_periodic_time, uint, 0644);
+MODULE_PARM_DESC(mrp_periodic_time, "Periodic time in ms (default 1s)");
+
 MODULE_LICENSE("GPL");
 
 static const u8
@@ -595,6 +600,24 @@ static void mrp_join_timer(unsigned long data)
        mrp_join_timer_arm(app);
 }
 
+static void mrp_periodic_timer_arm(struct mrp_applicant *app)
+{
+       mod_timer(&app->periodic_timer,
+                 jiffies + msecs_to_jiffies(mrp_periodic_time));
+}
+
+static void mrp_periodic_timer(unsigned long data)
+{
+       struct mrp_applicant *app = (struct mrp_applicant *)data;
+
+       spin_lock(&app->lock);
+       mrp_mad_event(app, MRP_EVENT_PERIODIC);
+       mrp_pdu_queue(app);
+       spin_unlock(&app->lock);
+
+       mrp_periodic_timer_arm(app);
+}
+
 static int mrp_pdu_parse_end_mark(struct sk_buff *skb, int *offset)
 {
        __be16 endmark;
@@ -845,6 +868,9 @@ int mrp_init_applicant(struct net_device *dev, struct mrp_application *appl)
        rcu_assign_pointer(dev->mrp_port->applicants[appl->type], app);
        setup_timer(&app->join_timer, mrp_join_timer, (unsigned long)app);
        mrp_join_timer_arm(app);
+       setup_timer(&app->periodic_timer, mrp_periodic_timer,
+                   (unsigned long)app);
+       mrp_periodic_timer_arm(app);
        return 0;
 
 err3:
@@ -870,6 +896,7 @@ void mrp_uninit_applicant(struct net_device *dev, struct mrp_application *appl)
         * all pending messages before the applicant is gone.
         */
        del_timer_sync(&app->join_timer);
+       del_timer_sync(&app->periodic_timer);
 
        spin_lock_bh(&app->lock);
        mrp_mad_event(app, MRP_EVENT_TX);
index 3091297..c7e634a 100644 (file)
@@ -171,7 +171,7 @@ static size_t vlan_get_size(const struct net_device *dev)
 
        return nla_total_size(2) +      /* IFLA_VLAN_PROTOCOL */
               nla_total_size(2) +      /* IFLA_VLAN_ID */
-              sizeof(struct ifla_vlan_flags) + /* IFLA_VLAN_FLAGS */
+              nla_total_size(sizeof(struct ifla_vlan_flags)) + /* IFLA_VLAN_FLAGS */
               vlan_qos_map_size(vlan->nr_ingress_mappings) +
               vlan_qos_map_size(vlan->nr_egress_mappings);
 }
index c72d1bc..1356af6 100644 (file)
@@ -65,6 +65,7 @@ static int __init batadv_init(void)
        batadv_recv_handler_init();
 
        batadv_iv_init();
+       batadv_nc_init();
 
        batadv_event_workqueue = create_singlethread_workqueue("bat_events");
 
@@ -142,7 +143,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
        if (ret < 0)
                goto err;
 
-       ret = batadv_nc_init(bat_priv);
+       ret = batadv_nc_mesh_init(bat_priv);
        if (ret < 0)
                goto err;
 
@@ -167,7 +168,7 @@ void batadv_mesh_free(struct net_device *soft_iface)
        batadv_vis_quit(bat_priv);
 
        batadv_gw_node_purge(bat_priv);
-       batadv_nc_free(bat_priv);
+       batadv_nc_mesh_free(bat_priv);
        batadv_dat_free(bat_priv);
        batadv_bla_free(bat_priv);
 
index a487d46..4ecc0b6 100644 (file)
@@ -34,6 +34,20 @@ static void batadv_nc_worker(struct work_struct *work);
 static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
                                       struct batadv_hard_iface *recv_if);
 
+/**
+ * batadv_nc_init - one-time initialization for network coding
+ */
+int __init batadv_nc_init(void)
+{
+       int ret;
+
+       /* Register our packet type */
+       ret = batadv_recv_handler_register(BATADV_CODED,
+                                          batadv_nc_recv_coded_packet);
+
+       return ret;
+}
+
 /**
  * batadv_nc_start_timer - initialise the nc periodic worker
  * @bat_priv: the bat priv with all the soft interface information
@@ -45,10 +59,10 @@ static void batadv_nc_start_timer(struct batadv_priv *bat_priv)
 }
 
 /**
- * batadv_nc_init - initialise coding hash table and start house keeping
+ * batadv_nc_mesh_init - initialise coding hash table and start house keeping
  * @bat_priv: the bat priv with all the soft interface information
  */
-int batadv_nc_init(struct batadv_priv *bat_priv)
+int batadv_nc_mesh_init(struct batadv_priv *bat_priv)
 {
        bat_priv->nc.timestamp_fwd_flush = jiffies;
        bat_priv->nc.timestamp_sniffed_purge = jiffies;
@@ -70,11 +84,6 @@ int batadv_nc_init(struct batadv_priv *bat_priv)
        batadv_hash_set_lock_class(bat_priv->nc.coding_hash,
                                   &batadv_nc_decoding_hash_lock_class_key);
 
-       /* Register our packet type */
-       if (batadv_recv_handler_register(BATADV_CODED,
-                                        batadv_nc_recv_coded_packet) < 0)
-               goto err;
-
        INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker);
        batadv_nc_start_timer(bat_priv);
 
@@ -1721,12 +1730,11 @@ free_nc_packet:
 }
 
 /**
- * batadv_nc_free - clean up network coding memory
+ * batadv_nc_mesh_free - clean up network coding memory
  * @bat_priv: the bat priv with all the soft interface information
  */
-void batadv_nc_free(struct batadv_priv *bat_priv)
+void batadv_nc_mesh_free(struct batadv_priv *bat_priv)
 {
-       batadv_recv_handler_unregister(BATADV_CODED);
        cancel_delayed_work_sync(&bat_priv->nc.work);
 
        batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL);
index 85a4ec8..ddfa618 100644 (file)
@@ -22,8 +22,9 @@
 
 #ifdef CONFIG_BATMAN_ADV_NC
 
-int batadv_nc_init(struct batadv_priv *bat_priv);
-void batadv_nc_free(struct batadv_priv *bat_priv);
+int batadv_nc_init(void);
+int batadv_nc_mesh_init(struct batadv_priv *bat_priv);
+void batadv_nc_mesh_free(struct batadv_priv *bat_priv);
 void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
                              struct batadv_orig_node *orig_node,
                              struct batadv_orig_node *orig_neigh_node,
@@ -46,12 +47,17 @@ int batadv_nc_init_debugfs(struct batadv_priv *bat_priv);
 
 #else /* ifdef CONFIG_BATMAN_ADV_NC */
 
-static inline int batadv_nc_init(struct batadv_priv *bat_priv)
+static inline int batadv_nc_init(void)
 {
        return 0;
 }
 
-static inline void batadv_nc_free(struct batadv_priv *bat_priv)
+static inline int batadv_nc_mesh_init(struct batadv_priv *bat_priv)
+{
+       return 0;
+}
+
+static inline void batadv_nc_mesh_free(struct batadv_priv *bat_priv)
 {
        return;
 }
index 634deba..fb7356f 100644 (file)
@@ -1146,7 +1146,11 @@ int hci_dev_open(__u16 dev)
                goto done;
        }
 
-       if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) {
+       /* Check for rfkill but allow the HCI setup stage to proceed
+        * (which in itself doesn't cause any RF activity).
+        */
+       if (test_bit(HCI_RFKILLED, &hdev->dev_flags) &&
+           !test_bit(HCI_SETUP, &hdev->dev_flags)) {
                ret = -ERFKILL;
                goto done;
        }
@@ -1566,10 +1570,13 @@ static int hci_rfkill_set_block(void *data, bool blocked)
 
        BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
 
-       if (!blocked)
-               return 0;
-
-       hci_dev_do_close(hdev);
+       if (blocked) {
+               set_bit(HCI_RFKILLED, &hdev->dev_flags);
+               if (!test_bit(HCI_SETUP, &hdev->dev_flags))
+                       hci_dev_do_close(hdev);
+       } else {
+               clear_bit(HCI_RFKILLED, &hdev->dev_flags);
+       }
 
        return 0;
 }
@@ -1591,9 +1598,13 @@ static void hci_power_on(struct work_struct *work)
                return;
        }
 
-       if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
+       if (test_bit(HCI_RFKILLED, &hdev->dev_flags)) {
+               clear_bit(HCI_AUTO_OFF, &hdev->dev_flags);
+               hci_dev_do_close(hdev);
+       } else if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
                queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
                                   HCI_AUTO_OFF_TIMEOUT);
+       }
 
        if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
                mgmt_index_added(hdev);
@@ -2209,6 +2220,9 @@ int hci_register_dev(struct hci_dev *hdev)
                }
        }
 
+       if (hdev->rfkill && rfkill_blocked(hdev->rfkill))
+               set_bit(HCI_RFKILLED, &hdev->dev_flags);
+
        set_bit(HCI_SETUP, &hdev->dev_flags);
 
        if (hdev->dev_type != HCI_AMP)
index 94aab73..8db3e89 100644 (file)
@@ -3557,7 +3557,11 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
        cp.handle = cpu_to_le16(conn->handle);
 
        if (ltk->authenticated)
-               conn->sec_level = BT_SECURITY_HIGH;
+               conn->pending_sec_level = BT_SECURITY_HIGH;
+       else
+               conn->pending_sec_level = BT_SECURITY_MEDIUM;
+
+       conn->enc_key_size = ltk->enc_size;
 
        hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
 
index b3bb7bc..63fa111 100644 (file)
@@ -3755,6 +3755,13 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
 
        sk = chan->sk;
 
+       /* For certain devices (ex: HID mouse), support for authentication,
+        * pairing and bonding is optional. For such devices, inorder to avoid
+        * the ACL alive for too long after L2CAP disconnection, reset the ACL
+        * disc_timeout back to HCI_DISCONN_TIMEOUT during L2CAP connect.
+        */
+       conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
+
        bacpy(&bt_sk(sk)->src, conn->src);
        bacpy(&bt_sk(sk)->dst, conn->dst);
        chan->psm  = psm;
index 6d126fa..84fcf9f 100644 (file)
@@ -569,7 +569,6 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
 {
        struct rfcomm_dev *dev = dlc->owner;
-       struct tty_struct *tty;
        if (!dev)
                return;
 
@@ -581,38 +580,8 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
                            DPM_ORDER_DEV_AFTER_PARENT);
 
                wake_up_interruptible(&dev->port.open_wait);
-       } else if (dlc->state == BT_CLOSED) {
-               tty = tty_port_tty_get(&dev->port);
-               if (!tty) {
-                       if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
-                               /* Drop DLC lock here to avoid deadlock
-                                * 1. rfcomm_dev_get will take rfcomm_dev_lock
-                                *    but in rfcomm_dev_add there's lock order:
-                                *    rfcomm_dev_lock -> dlc lock
-                                * 2. tty_port_put will deadlock if it's
-                                *    the last reference
-                                *
-                                * FIXME: when we release the lock anything
-                                * could happen to dev, even its destruction
-                                */
-                               rfcomm_dlc_unlock(dlc);
-                               if (rfcomm_dev_get(dev->id) == NULL) {
-                                       rfcomm_dlc_lock(dlc);
-                                       return;
-                               }
-
-                               if (!test_and_set_bit(RFCOMM_TTY_RELEASED,
-                                                     &dev->flags))
-                                       tty_port_put(&dev->port);
-
-                               tty_port_put(&dev->port);
-                               rfcomm_dlc_lock(dlc);
-                       }
-               } else {
-                       tty_hangup(tty);
-                       tty_kref_put(tty);
-               }
-       }
+       } else if (dlc->state == BT_CLOSED)
+               tty_port_tty_hangup(&dev->port, false);
 }
 
 static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
index ffd5874..33e8f23 100644 (file)
@@ -700,7 +700,7 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 
                vid = nla_get_u16(tb[NDA_VLAN]);
 
-               if (vid >= VLAN_N_VID) {
+               if (!vid || vid >= VLAN_VID_MASK) {
                        pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n",
                                vid);
                        return -EINVAL;
@@ -794,7 +794,7 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
 
                vid = nla_get_u16(tb[NDA_VLAN]);
 
-               if (vid >= VLAN_N_VID) {
+               if (!vid || vid >= VLAN_VID_MASK) {
                        pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n",
                                vid);
                        return -EINVAL;
index 85a09bb..b7b1914 100644 (file)
@@ -453,7 +453,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
                call_rcu_bh(&p->rcu, br_multicast_free_pg);
                err = 0;
 
-               if (!mp->ports && !mp->mglist && mp->timer_armed &&
+               if (!mp->ports && !mp->mglist &&
                    netif_running(br->dev))
                        mod_timer(&mp->timer, jiffies);
                break;
index d1c5786..8b0b610 100644 (file)
@@ -272,7 +272,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
                del_timer(&p->timer);
                call_rcu_bh(&p->rcu, br_multicast_free_pg);
 
-               if (!mp->ports && !mp->mglist && mp->timer_armed &&
+               if (!mp->ports && !mp->mglist &&
                    netif_running(br->dev))
                        mod_timer(&mp->timer, jiffies);
 
@@ -620,7 +620,6 @@ rehash:
 
        mp->br = br;
        mp->addr = *group;
-
        setup_timer(&mp->timer, br_multicast_group_expired,
                    (unsigned long)mp);
 
@@ -660,6 +659,7 @@ static int br_multicast_add_group(struct net_bridge *br,
        struct net_bridge_mdb_entry *mp;
        struct net_bridge_port_group *p;
        struct net_bridge_port_group __rcu **pp;
+       unsigned long now = jiffies;
        int err;
 
        spin_lock(&br->multicast_lock);
@@ -674,6 +674,7 @@ static int br_multicast_add_group(struct net_bridge *br,
 
        if (!port) {
                mp->mglist = true;
+               mod_timer(&mp->timer, now + br->multicast_membership_interval);
                goto out;
        }
 
@@ -681,7 +682,7 @@ static int br_multicast_add_group(struct net_bridge *br,
             (p = mlock_dereference(*pp, br)) != NULL;
             pp = &p->next) {
                if (p->port == port)
-                       goto out;
+                       goto found;
                if ((unsigned long)p->port < (unsigned long)port)
                        break;
        }
@@ -692,6 +693,8 @@ static int br_multicast_add_group(struct net_bridge *br,
        rcu_assign_pointer(*pp, p);
        br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
 
+found:
+       mod_timer(&p->timer, now + br->multicast_membership_interval);
 out:
        err = 0;
 
@@ -1191,9 +1194,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
        if (!mp)
                goto out;
 
-       mod_timer(&mp->timer, now + br->multicast_membership_interval);
-       mp->timer_armed = true;
-
        max_delay *= br->multicast_last_member_count;
 
        if (mp->mglist &&
@@ -1270,9 +1270,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
        if (!mp)
                goto out;
 
-       mod_timer(&mp->timer, now + br->multicast_membership_interval);
-       mp->timer_armed = true;
-
        max_delay *= br->multicast_last_member_count;
        if (mp->mglist &&
            (timer_pending(&mp->timer) ?
@@ -1358,7 +1355,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
                        call_rcu_bh(&p->rcu, br_multicast_free_pg);
                        br_mdb_notify(br->dev, port, group, RTM_DELMDB);
 
-                       if (!mp->ports && !mp->mglist && mp->timer_armed &&
+                       if (!mp->ports && !mp->mglist &&
                            netif_running(br->dev))
                                mod_timer(&mp->timer, jiffies);
                }
@@ -1370,12 +1367,30 @@ static void br_multicast_leave_group(struct net_bridge *br,
                     br->multicast_last_member_interval;
 
        if (!port) {
-               if (mp->mglist && mp->timer_armed &&
+               if (mp->mglist &&
                    (timer_pending(&mp->timer) ?
                     time_after(mp->timer.expires, time) :
                     try_to_del_timer_sync(&mp->timer) >= 0)) {
                        mod_timer(&mp->timer, time);
                }
+
+               goto out;
+       }
+
+       for (p = mlock_dereference(mp->ports, br);
+            p != NULL;
+            p = mlock_dereference(p->next, br)) {
+               if (p->port != port)
+                       continue;
+
+               if (!hlist_unhashed(&p->mglist) &&
+                   (timer_pending(&p->timer) ?
+                    time_after(p->timer.expires, time) :
+                    try_to_del_timer_sync(&p->timer) >= 0)) {
+                       mod_timer(&p->timer, time);
+               }
+
+               break;
        }
 out:
        spin_unlock(&br->multicast_lock);
@@ -1798,7 +1813,6 @@ void br_multicast_stop(struct net_bridge *br)
                hlist_for_each_entry_safe(mp, n, &mdb->mhash[i],
                                          hlist[ver]) {
                        del_timer(&mp->timer);
-                       mp->timer_armed = false;
                        call_rcu_bh(&mp->rcu, br_multicast_free_group);
                }
        }
index e74ddc1..f75d92e 100644 (file)
@@ -243,7 +243,7 @@ static int br_afspec(struct net_bridge *br,
 
                vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
 
-               if (vinfo->vid >= VLAN_N_VID)
+               if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
                        return -EINVAL;
 
                switch (cmd) {
index efb57d9..e14c33b 100644 (file)
@@ -126,7 +126,6 @@ struct net_bridge_mdb_entry
        struct timer_list               timer;
        struct br_ip                    addr;
        bool                            mglist;
-       bool                            timer_armed;
 };
 
 struct net_bridge_mdb_htable
@@ -643,9 +642,7 @@ static inline u16 br_get_pvid(const struct net_port_vlans *v)
         * vid wasn't set
         */
        smp_rmb();
-       return (v->pvid & VLAN_TAG_PRESENT) ?
-                       (v->pvid & ~VLAN_TAG_PRESENT) :
-                       VLAN_N_VID;
+       return v->pvid ?: VLAN_N_VID;
 }
 
 #else
index 108084a..656a6f3 100644 (file)
@@ -134,7 +134,7 @@ static void br_stp_start(struct net_bridge *br)
 
        if (br->bridge_forward_delay < BR_MIN_FORWARD_DELAY)
                __br_set_forward_delay(br, BR_MIN_FORWARD_DELAY);
-       else if (br->bridge_forward_delay < BR_MAX_FORWARD_DELAY)
+       else if (br->bridge_forward_delay > BR_MAX_FORWARD_DELAY)
                __br_set_forward_delay(br, BR_MAX_FORWARD_DELAY);
 
        if (r == 0) {
index 9a9ffe7..53f0990 100644 (file)
@@ -45,37 +45,34 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
                return 0;
        }
 
-       if (vid) {
-               if (v->port_idx) {
-                       p = v->parent.port;
-                       br = p->br;
-                       dev = p->dev;
-               } else {
-                       br = v->parent.br;
-                       dev = br->dev;
-               }
-               ops = dev->netdev_ops;
-
-               if (p && (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
-                       /* Add VLAN to the device filter if it is supported.
-                        * Stricly speaking, this is not necessary now, since
-                        * devices are made promiscuous by the bridge, but if
-                        * that ever changes this code will allow tagged
-                        * traffic to enter the bridge.
-                        */
-                       err = ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q),
-                                                      vid);
-                       if (err)
-                               return err;
-               }
-
-               err = br_fdb_insert(br, p, dev->dev_addr, vid);
-               if (err) {
-                       br_err(br, "failed insert local address into bridge "
-                              "forwarding table\n");
-                       goto out_filt;
-               }
+       if (v->port_idx) {
+               p = v->parent.port;
+               br = p->br;
+               dev = p->dev;
+       } else {
+               br = v->parent.br;
+               dev = br->dev;
+       }
+       ops = dev->netdev_ops;
+
+       if (p && (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
+               /* Add VLAN to the device filter if it is supported.
+                * Stricly speaking, this is not necessary now, since
+                * devices are made promiscuous by the bridge, but if
+                * that ever changes this code will allow tagged
+                * traffic to enter the bridge.
+                */
+               err = ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q),
+                                              vid);
+               if (err)
+                       return err;
+       }
 
+       err = br_fdb_insert(br, p, dev->dev_addr, vid);
+       if (err) {
+               br_err(br, "failed insert local address into bridge "
+                      "forwarding table\n");
+               goto out_filt;
        }
 
        set_bit(vid, v->vlan_bitmap);
@@ -98,7 +95,7 @@ static int __vlan_del(struct net_port_vlans *v, u16 vid)
        __vlan_delete_pvid(v, vid);
        clear_bit(vid, v->untagged_bitmap);
 
-       if (v->port_idx && vid) {
+       if (v->port_idx) {
                struct net_device *dev = v->parent.port->dev;
                const struct net_device_ops *ops = dev->netdev_ops;
 
@@ -192,6 +189,8 @@ out:
 bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
                        struct sk_buff *skb, u16 *vid)
 {
+       int err;
+
        /* If VLAN filtering is disabled on the bridge, all packets are
         * permitted.
         */
@@ -204,20 +203,32 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
        if (!v)
                return false;
 
-       if (br_vlan_get_tag(skb, vid)) {
+       err = br_vlan_get_tag(skb, vid);
+       if (!*vid) {
                u16 pvid = br_get_pvid(v);
 
-               /* Frame did not have a tag.  See if pvid is set
-                * on this port.  That tells us which vlan untagged
-                * traffic belongs to.
+               /* Frame had a tag with VID 0 or did not have a tag.
+                * See if pvid is set on this port.  That tells us which
+                * vlan untagged or priority-tagged traffic belongs to.
                 */
                if (pvid == VLAN_N_VID)
                        return false;
 
-               /* PVID is set on this port.  Any untagged ingress
-                * frame is considered to belong to this vlan.
+               /* PVID is set on this port.  Any untagged or priority-tagged
+                * ingress frame is considered to belong to this vlan.
                 */
-               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), pvid);
+               *vid = pvid;
+               if (likely(err))
+                       /* Untagged Frame. */
+                       __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), pvid);
+               else
+                       /* Priority-tagged Frame.
+                        * At this point, We know that skb->vlan_tci had
+                        * VLAN_TAG_PRESENT bit and its VID field was 0x000.
+                        * We update only VID field and preserve PCP field.
+                        */
+                       skb->vlan_tci |= pvid;
+
                return true;
        }
 
@@ -248,7 +259,9 @@ bool br_allowed_egress(struct net_bridge *br,
        return false;
 }
 
-/* Must be protected by RTNL */
+/* Must be protected by RTNL.
+ * Must be called with vid in range from 1 to 4094 inclusive.
+ */
 int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags)
 {
        struct net_port_vlans *pv = NULL;
@@ -278,7 +291,9 @@ out:
        return err;
 }
 
-/* Must be protected by RTNL */
+/* Must be protected by RTNL.
+ * Must be called with vid in range from 1 to 4094 inclusive.
+ */
 int br_vlan_delete(struct net_bridge *br, u16 vid)
 {
        struct net_port_vlans *pv;
@@ -289,14 +304,9 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
        if (!pv)
                return -EINVAL;
 
-       if (vid) {
-               /* If the VID !=0 remove fdb for this vid. VID 0 is special
-                * in that it's the default and is always there in the fdb.
-                */
-               spin_lock_bh(&br->hash_lock);
-               fdb_delete_by_addr(br, br->dev->dev_addr, vid);
-               spin_unlock_bh(&br->hash_lock);
-       }
+       spin_lock_bh(&br->hash_lock);
+       fdb_delete_by_addr(br, br->dev->dev_addr, vid);
+       spin_unlock_bh(&br->hash_lock);
 
        __vlan_del(pv, vid);
        return 0;
@@ -329,7 +339,9 @@ unlock:
        return 0;
 }
 
-/* Must be protected by RTNL */
+/* Must be protected by RTNL.
+ * Must be called with vid in range from 1 to 4094 inclusive.
+ */
 int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags)
 {
        struct net_port_vlans *pv = NULL;
@@ -363,7 +375,9 @@ clean_up:
        return err;
 }
 
-/* Must be protected by RTNL */
+/* Must be protected by RTNL.
+ * Must be called with vid in range from 1 to 4094 inclusive.
+ */
 int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
 {
        struct net_port_vlans *pv;
@@ -374,14 +388,9 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
        if (!pv)
                return -EINVAL;
 
-       if (vid) {
-               /* If the VID !=0 remove fdb for this vid. VID 0 is special
-                * in that it's the default and is always there in the fdb.
-                */
-               spin_lock_bh(&port->br->hash_lock);
-               fdb_delete_by_addr(port->br, port->dev->dev_addr, vid);
-               spin_unlock_bh(&port->br->hash_lock);
-       }
+       spin_lock_bh(&port->br->hash_lock);
+       fdb_delete_by_addr(port->br, port->dev->dev_addr, vid);
+       spin_unlock_bh(&port->br->hash_lock);
 
        return __vlan_del(pv, vid);
 }
index f0a1ba6..8903258 100644 (file)
@@ -71,6 +71,8 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg)
            __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
            __get_user(kmsg->msg_flags, &umsg->msg_flags))
                return -EFAULT;
+       if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
+               return -EINVAL;
        kmsg->msg_name = compat_ptr(tmp1);
        kmsg->msg_iov = compat_ptr(tmp2);
        kmsg->msg_control = compat_ptr(tmp3);
index 5c713f2..3430b1e 100644 (file)
@@ -1917,7 +1917,8 @@ static struct xps_map *expand_xps_map(struct xps_map *map,
        return new_map;
 }
 
-int netif_set_xps_queue(struct net_device *dev, struct cpumask *mask, u16 index)
+int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
+                       u16 index)
 {
        struct xps_dev_maps *dev_maps, *new_dev_maps = NULL;
        struct xps_map *map, *new_map;
@@ -5247,10 +5248,12 @@ static int dev_new_index(struct net *net)
 
 /* Delayed registration/unregisteration */
 static LIST_HEAD(net_todo_list);
+static DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);
 
 static void net_set_todo(struct net_device *dev)
 {
        list_add_tail(&dev->todo_list, &net_todo_list);
+       dev_net(dev)->dev_unreg_count++;
 }
 
 static void rollback_registered_many(struct list_head *head)
@@ -5918,6 +5921,12 @@ void netdev_run_todo(void)
                if (dev->destructor)
                        dev->destructor(dev);
 
+               /* Report a network device has been unregistered */
+               rtnl_lock();
+               dev_net(dev)->dev_unreg_count--;
+               __rtnl_unlock();
+               wake_up(&netdev_unregistering_wq);
+
                /* Free network device */
                kobject_put(&dev->dev.kobj);
        }
@@ -6603,6 +6612,34 @@ static void __net_exit default_device_exit(struct net *net)
        rtnl_unlock();
 }
 
+static void __net_exit rtnl_lock_unregistering(struct list_head *net_list)
+{
+       /* Return with the rtnl_lock held when there are no network
+        * devices unregistering in any network namespace in net_list.
+        */
+       struct net *net;
+       bool unregistering;
+       DEFINE_WAIT(wait);
+
+       for (;;) {
+               prepare_to_wait(&netdev_unregistering_wq, &wait,
+                               TASK_UNINTERRUPTIBLE);
+               unregistering = false;
+               rtnl_lock();
+               list_for_each_entry(net, net_list, exit_list) {
+                       if (net->dev_unreg_count > 0) {
+                               unregistering = true;
+                               break;
+                       }
+               }
+               if (!unregistering)
+                       break;
+               __rtnl_unlock();
+               schedule();
+       }
+       finish_wait(&netdev_unregistering_wq, &wait);
+}
+
 static void __net_exit default_device_exit_batch(struct list_head *net_list)
 {
        /* At exit all network devices most be removed from a network
@@ -6614,7 +6651,18 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)
        struct net *net;
        LIST_HEAD(dev_kill_list);
 
-       rtnl_lock();
+       /* To prevent network device cleanup code from dereferencing
+        * loopback devices or network devices that have been freed
+        * wait here for all pending unregistrations to complete,
+        * before unregistring the loopback device and allowing the
+        * network namespace be freed.
+        *
+        * The netdev todo list containing all network devices
+        * unregistrations that happen in default_device_exit_batch
+        * will run in the rtnl_unlock() at the end of
+        * default_device_exit_batch.
+        */
+       rtnl_lock_unregistering(net_list);
        list_for_each_entry(net, net_list, exit_list) {
                for_each_netdev_reverse(net, dev) {
                        if (dev->rtnl_link_ops)
index 6438f29..01b7808 100644 (file)
@@ -644,7 +644,6 @@ void sk_filter_release_rcu(struct rcu_head *rcu)
        struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
 
        bpf_jit_free(fp);
-       kfree(fp);
 }
 EXPORT_SYMBOL(sk_filter_release_rcu);
 
@@ -683,7 +682,7 @@ int sk_unattached_filter_create(struct sk_filter **pfp,
        if (fprog->filter == NULL)
                return -EINVAL;
 
-       fp = kmalloc(fsize + sizeof(*fp), GFP_KERNEL);
+       fp = kmalloc(sk_filter_size(fprog->len), GFP_KERNEL);
        if (!fp)
                return -ENOMEM;
        memcpy(fp->insns, fprog->filter, fsize);
@@ -723,6 +722,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
 {
        struct sk_filter *fp, *old_fp;
        unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
+       unsigned int sk_fsize = sk_filter_size(fprog->len);
        int err;
 
        if (sock_flag(sk, SOCK_FILTER_LOCKED))
@@ -732,11 +732,11 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
        if (fprog->filter == NULL)
                return -EINVAL;
 
-       fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL);
+       fp = sock_kmalloc(sk, sk_fsize, GFP_KERNEL);
        if (!fp)
                return -ENOMEM;
        if (copy_from_user(fp->insns, fprog->filter, fsize)) {
-               sock_kfree_s(sk, fp, fsize+sizeof(*fp));
+               sock_kfree_s(sk, fp, sk_fsize);
                return -EFAULT;
        }
 
index 1929af8..8d7d0dd 100644 (file)
@@ -154,8 +154,8 @@ ipv6:
        if (poff >= 0) {
                __be32 *ports, _ports;
 
-               nhoff += poff;
-               ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports);
+               ports = skb_header_pointer(skb, nhoff + poff,
+                                          sizeof(_ports), &_ports);
                if (ports)
                        flow->ports = *ports;
        }
index 6a2f13c..8d9d05e 100644 (file)
 
 #include <net/secure_seq.h>
 
-static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
+#if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
+#define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4)
 
-void net_secret_init(void)
+static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned;
+
+static void net_secret_init(void)
 {
-       get_random_bytes(net_secret, sizeof(net_secret));
+       u32 tmp;
+       int i;
+
+       if (likely(net_secret[0]))
+               return;
+
+       for (i = NET_SECRET_SIZE; i > 0;) {
+               do {
+                       get_random_bytes(&tmp, sizeof(tmp));
+               } while (!tmp);
+               cmpxchg(&net_secret[--i], 0, tmp);
+       }
 }
+#endif
 
 #ifdef CONFIG_INET
 static u32 seq_scale(u32 seq)
@@ -42,6 +57,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
        u32 hash[MD5_DIGEST_WORDS];
        u32 i;
 
+       net_secret_init();
        memcpy(hash, saddr, 16);
        for (i = 0; i < 4; i++)
                secret[i] = net_secret[i] + (__force u32)daddr[i];
@@ -63,6 +79,7 @@ u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
        u32 hash[MD5_DIGEST_WORDS];
        u32 i;
 
+       net_secret_init();
        memcpy(hash, saddr, 16);
        for (i = 0; i < 4; i++)
                secret[i] = net_secret[i] + (__force u32) daddr[i];
@@ -82,6 +99,7 @@ __u32 secure_ip_id(__be32 daddr)
 {
        u32 hash[MD5_DIGEST_WORDS];
 
+       net_secret_init();
        hash[0] = (__force __u32) daddr;
        hash[1] = net_secret[13];
        hash[2] = net_secret[14];
@@ -96,6 +114,7 @@ __u32 secure_ipv6_id(const __be32 daddr[4])
 {
        __u32 hash[4];
 
+       net_secret_init();
        memcpy(hash, daddr, 16);
        md5_transform(hash, net_secret);
 
@@ -107,6 +126,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
 {
        u32 hash[MD5_DIGEST_WORDS];
 
+       net_secret_init();
        hash[0] = (__force u32)saddr;
        hash[1] = (__force u32)daddr;
        hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
@@ -121,6 +141,7 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
 {
        u32 hash[MD5_DIGEST_WORDS];
 
+       net_secret_init();
        hash[0] = (__force u32)saddr;
        hash[1] = (__force u32)daddr;
        hash[2] = (__force u32)dport ^ net_secret[14];
@@ -140,6 +161,7 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
        u32 hash[MD5_DIGEST_WORDS];
        u64 seq;
 
+       net_secret_init();
        hash[0] = (__force u32)saddr;
        hash[1] = (__force u32)daddr;
        hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
@@ -164,6 +186,7 @@ u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
        u64 seq;
        u32 i;
 
+       net_secret_init();
        memcpy(hash, saddr, 16);
        for (i = 0; i < 4; i++)
                secret[i] = net_secret[i] + daddr[i];
index 5b6beba..0b39e7a 100644 (file)
@@ -2319,6 +2319,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
        sk->sk_ll_usec          =       sysctl_net_busy_read;
 #endif
 
+       sk->sk_pacing_rate = ~0U;
        /*
         * Before updating sk_refcnt, we must commit prior changes to memory
         * (Documentation/RCU/rculist_nulls.txt for details)
index c85e71e..ff41b4d 100644 (file)
@@ -1372,6 +1372,8 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev,
        real_dev = dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
        if (!real_dev)
                return -ENODEV;
+       if (real_dev->type != ARPHRD_IEEE802154)
+               return -EINVAL;
 
        lowpan_dev_info(dev)->real_dev = real_dev;
        lowpan_dev_info(dev)->fragment_tag = 0;
@@ -1386,6 +1388,9 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev,
 
        entry->ldev = dev;
 
+       /* Set the lowpan harware address to the wpan hardware address. */
+       memcpy(dev->dev_addr, real_dev->dev_addr, IEEE802154_ADDR_LEN);
+
        mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
        INIT_LIST_HEAD(&entry->list);
        list_add_tail(&entry->list, &lowpan_devices);
index 7a1874b..cfeb85c 100644 (file)
@@ -263,10 +263,8 @@ void build_ehash_secret(void)
                get_random_bytes(&rnd, sizeof(rnd));
        } while (rnd == 0);
 
-       if (cmpxchg(&inet_ehash_secret, 0, rnd) == 0) {
+       if (cmpxchg(&inet_ehash_secret, 0, rnd) == 0)
                get_random_bytes(&ipv6_hash_secret, sizeof(ipv6_hash_secret));
-               net_secret_init();
-       }
 }
 EXPORT_SYMBOL(build_ehash_secret);
 
index dace87f..7defdc9 100644 (file)
@@ -736,7 +736,7 @@ static void igmp_gq_timer_expire(unsigned long data)
 
        in_dev->mr_gq_running = 0;
        igmpv3_send_report(in_dev, NULL);
-       __in_dev_put(in_dev);
+       in_dev_put(in_dev);
 }
 
 static void igmp_ifc_timer_expire(unsigned long data)
@@ -749,7 +749,7 @@ static void igmp_ifc_timer_expire(unsigned long data)
                igmp_ifc_start_timer(in_dev,
                                     unsolicited_report_interval(in_dev));
        }
-       __in_dev_put(in_dev);
+       in_dev_put(in_dev);
 }
 
 static void igmp_ifc_event(struct in_device *in_dev)
index 7bd8983..96da9c7 100644 (file)
@@ -287,7 +287,7 @@ begintw:
                        if (unlikely(!INET_TW_MATCH(sk, net, acookie,
                                                    saddr, daddr, ports,
                                                    dif))) {
-                               sock_put(sk);
+                               inet_twsk_put(inet_twsk(sk));
                                goto begintw;
                        }
                        goto out;
index a04d872..3982eab 100644 (file)
@@ -772,15 +772,20 @@ static inline int ip_ufo_append_data(struct sock *sk,
                /* initialize protocol header pointer */
                skb->transport_header = skb->network_header + fragheaderlen;
 
-               skb->ip_summed = CHECKSUM_PARTIAL;
                skb->csum = 0;
 
-               /* specify the length of each IP datagram fragment */
-               skb_shinfo(skb)->gso_size = maxfraglen - fragheaderlen;
-               skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+
                __skb_queue_tail(queue, skb);
+       } else if (skb_is_gso(skb)) {
+               goto append;
        }
 
+       skb->ip_summed = CHECKSUM_PARTIAL;
+       /* specify the length of each IP datagram fragment */
+       skb_shinfo(skb)->gso_size = maxfraglen - fragheaderlen;
+       skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+
+append:
        return skb_append_datato_frags(sk, skb, getfrag, from,
                                       (length - transhdrlen));
 }
index ac9fabe..63a6d6d 100644 (file)
@@ -623,6 +623,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                        tunnel->err_count = 0;
        }
 
+       tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
        ttl = tnl_params->ttl;
        if (ttl == 0) {
                if (skb->protocol == htons(ETH_P_IP))
@@ -641,18 +642,17 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
 
        max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
                        + rt->dst.header_len;
-       if (max_headroom > dev->needed_headroom) {
+       if (max_headroom > dev->needed_headroom)
                dev->needed_headroom = max_headroom;
-               if (skb_cow_head(skb, dev->needed_headroom)) {
-                       dev->stats.tx_dropped++;
-                       dev_kfree_skb(skb);
-                       return;
-               }
+
+       if (skb_cow_head(skb, dev->needed_headroom)) {
+               dev->stats.tx_dropped++;
+               dev_kfree_skb(skb);
+               return;
        }
 
        err = iptunnel_xmit(rt, skb, fl4.saddr, fl4.daddr, protocol,
-                           ip_tunnel_ecn_encap(tos, inner_iph, skb), ttl, df,
-                           !net_eq(tunnel->net, dev_net(dev)));
+                           tos, ttl, df, !net_eq(tunnel->net, dev_net(dev)));
        iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
 
        return;
@@ -853,8 +853,10 @@ int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,
        /* FB netdevice is special: we have one, and only one per netns.
         * Allowing to move it to another netns is clearly unsafe.
         */
-       if (!IS_ERR(itn->fb_tunnel_dev))
+       if (!IS_ERR(itn->fb_tunnel_dev)) {
                itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
+               ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev));
+       }
        rtnl_unlock();
 
        return PTR_RET(itn->fb_tunnel_dev);
@@ -884,8 +886,6 @@ static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head,
                        if (!net_eq(dev_net(t->dev), net))
                                unregister_netdevice_queue(t->dev, head);
        }
-       if (itn->fb_tunnel_dev)
-               unregister_netdevice_queue(itn->fb_tunnel_dev, head);
 }
 
 void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops)
index d6c856b..c31e3ad 100644 (file)
@@ -61,7 +61,7 @@ int iptunnel_xmit(struct rtable *rt, struct sk_buff *skb,
        memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
 
        /* Push down and install the IP header. */
-       __skb_push(skb, sizeof(struct iphdr));
+       skb_push(skb, sizeof(struct iphdr));
        skb_reset_network_header(skb);
 
        iph = ip_hdr(skb);
index e805e7b..6e87f85 100644 (file)
@@ -125,8 +125,17 @@ static int vti_rcv(struct sk_buff *skb)
                                  iph->saddr, iph->daddr, 0);
        if (tunnel != NULL) {
                struct pcpu_tstats *tstats;
+               u32 oldmark = skb->mark;
+               int ret;
 
-               if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
+
+               /* temporarily mark the skb with the tunnel o_key, to
+                * only match policies with this mark.
+                */
+               skb->mark = be32_to_cpu(tunnel->parms.o_key);
+               ret = xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb);
+               skb->mark = oldmark;
+               if (!ret)
                        return -1;
 
                tstats = this_cpu_ptr(tunnel->dev->tstats);
@@ -135,7 +144,6 @@ static int vti_rcv(struct sk_buff *skb)
                tstats->rx_bytes += skb->len;
                u64_stats_update_end(&tstats->syncp);
 
-               skb->mark = 0;
                secpath_reset(skb);
                skb->dev = tunnel->dev;
                return 1;
@@ -167,7 +175,7 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
        memset(&fl4, 0, sizeof(fl4));
        flowi4_init_output(&fl4, tunnel->parms.link,
-                          be32_to_cpu(tunnel->parms.i_key), RT_TOS(tos),
+                          be32_to_cpu(tunnel->parms.o_key), RT_TOS(tos),
                           RT_SCOPE_UNIVERSE,
                           IPPROTO_IPIP, 0,
                           dst, tiph->saddr, 0, 0);
index 67e17dc..b6346bf 100644 (file)
@@ -267,7 +267,8 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
        if (th == NULL)
                return NF_DROP;
 
-       synproxy_parse_options(skb, par->thoff, th, &opts);
+       if (!synproxy_parse_options(skb, par->thoff, th, &opts))
+               return NF_DROP;
 
        if (th->syn && !(th->ack || th->fin || th->rst)) {
                /* Initial SYN from client */
@@ -350,7 +351,8 @@ static unsigned int ipv4_synproxy_hook(unsigned int hooknum,
 
                /* fall through */
        case TCP_CONNTRACK_SYN_SENT:
-               synproxy_parse_options(skb, thoff, th, &opts);
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
 
                if (!th->syn && th->ack &&
                    CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
@@ -373,7 +375,9 @@ static unsigned int ipv4_synproxy_hook(unsigned int hooknum,
                if (!th->syn || !th->ack)
                        break;
 
-               synproxy_parse_options(skb, thoff, th, &opts);
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
+
                if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
                        synproxy->tsoff = opts.tsval - synproxy->its;
 
index bfec521..193db03 100644 (file)
@@ -218,8 +218,10 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
 
        if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
                ipv4_sk_update_pmtu(skb, sk, info);
-       else if (type == ICMP_REDIRECT)
+       else if (type == ICMP_REDIRECT) {
                ipv4_sk_redirect(skb, sk);
+               return;
+       }
 
        /* Report error on raw socket, if:
           1. User requested ip_recverr.
index 727f436..6011615 100644 (file)
@@ -2072,7 +2072,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
                                                              RT_SCOPE_LINK);
                        goto make_route;
                }
-               if (fl4->saddr) {
+               if (!fl4->saddr) {
                        if (ipv4_is_multicast(fl4->daddr))
                                fl4->saddr = inet_select_addr(dev_out, 0,
                                                              fl4->flowi4_scope);
index 25a89ea..a16b01b 100644 (file)
@@ -1284,7 +1284,10 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
                tp->lost_cnt_hint -= tcp_skb_pcount(prev);
        }
 
-       TCP_SKB_CB(skb)->tcp_flags |= TCP_SKB_CB(prev)->tcp_flags;
+       TCP_SKB_CB(prev)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags;
+       if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
+               TCP_SKB_CB(prev)->end_seq++;
+
        if (skb == tcp_highest_sack(sk))
                tcp_advance_highest_sack(sk, skb);
 
@@ -3288,7 +3291,7 @@ static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag)
                        tcp_init_cwnd_reduction(sk, true);
                        tcp_set_ca_state(sk, TCP_CA_CWR);
                        tcp_end_cwnd_reduction(sk);
-                       tcp_set_ca_state(sk, TCP_CA_Open);
+                       tcp_try_keep_open(sk);
                        NET_INC_STATS_BH(sock_net(sk),
                                         LINUX_MIB_TCPLOSSPROBERECOVERY);
                }
@@ -5709,6 +5712,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                } else
                        tcp_init_metrics(sk);
 
+               tcp_update_pacing_rate(sk);
+
                /* Prevent spurious tcp_cwnd_restart() on first data packet */
                tp->lsndtime = tcp_time_stamp;
 
index 7c83cb8..d46f214 100644 (file)
@@ -637,6 +637,8 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
        unsigned int size = 0;
        unsigned int eff_sacks;
 
+       opts->options = 0;
+
 #ifdef CONFIG_TCP_MD5SIG
        *md5 = tp->af_specific->md5_lookup(sk, sk);
        if (unlikely(*md5)) {
@@ -895,8 +897,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
 
        skb_orphan(skb);
        skb->sk = sk;
-       skb->destructor = (sysctl_tcp_limit_output_bytes > 0) ?
-                         tcp_wfree : sock_wfree;
+       skb->destructor = tcp_wfree;
        atomic_add(skb->truesize, &sk->sk_wmem_alloc);
 
        /* Build TCP header and checksum it. */
@@ -985,8 +986,10 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
 static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb,
                                 unsigned int mss_now)
 {
-       if (skb->len <= mss_now || !sk_can_gso(sk) ||
-           skb->ip_summed == CHECKSUM_NONE) {
+       /* Make sure we own this skb before messing gso_size/gso_segs */
+       WARN_ON_ONCE(skb_cloned(skb));
+
+       if (skb->len <= mss_now || skb->ip_summed == CHECKSUM_NONE) {
                /* Avoid the costly divide in the normal
                 * non-TSO case.
                 */
@@ -1066,9 +1069,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
        if (nsize < 0)
                nsize = 0;
 
-       if (skb_cloned(skb) &&
-           skb_is_nonlinear(skb) &&
-           pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+       if (skb_unclone(skb, GFP_ATOMIC))
                return -ENOMEM;
 
        /* Get a new skb... force flag on. */
@@ -1840,7 +1841,6 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
        while ((skb = tcp_send_head(sk))) {
                unsigned int limit;
 
-
                tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
                BUG_ON(!tso_segs);
 
@@ -1869,13 +1869,20 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                                break;
                }
 
-               /* TSQ : sk_wmem_alloc accounts skb truesize,
-                * including skb overhead. But thats OK.
+               /* TCP Small Queues :
+                * Control number of packets in qdisc/devices to two packets / or ~1 ms.
+                * This allows for :
+                *  - better RTT estimation and ACK scheduling
+                *  - faster recovery
+                *  - high rates
                 */
-               if (atomic_read(&sk->sk_wmem_alloc) >= sysctl_tcp_limit_output_bytes) {
+               limit = max(skb->truesize, sk->sk_pacing_rate >> 10);
+
+               if (atomic_read(&sk->sk_wmem_alloc) > limit) {
                        set_bit(TSQ_THROTTLED, &tp->tsq_flags);
                        break;
                }
+
                limit = mss_now;
                if (tso_segs > 1 && !tcp_urg_mode(tp))
                        limit = tcp_mss_split_point(sk, skb, mss_now,
@@ -2337,6 +2344,8 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                int oldpcount = tcp_skb_pcount(skb);
 
                if (unlikely(oldpcount > 1)) {
+                       if (skb_unclone(skb, GFP_ATOMIC))
+                               return -ENOMEM;
                        tcp_init_tso_segs(sk, skb, cur_mss);
                        tcp_adjust_pcount(sk, skb, oldpcount - tcp_skb_pcount(skb));
                }
index 74d2c95..0ca44df 100644 (file)
@@ -658,7 +658,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
                break;
        case ICMP_REDIRECT:
                ipv4_sk_redirect(skb, sk);
-               break;
+               goto out;
        }
 
        /*
index 9a459be..ccde542 100644 (file)
@@ -107,6 +107,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
 
        memset(fl4, 0, sizeof(struct flowi4));
        fl4->flowi4_mark = skb->mark;
+       fl4->flowi4_oif = skb_dst(skb)->dev->ifindex;
 
        if (!ip_is_fragment(iph)) {
                switch (iph->protocol) {
index d6ff126..cd3fb30 100644 (file)
@@ -1499,6 +1499,33 @@ static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
        return false;
 }
 
+/* Compares an address/prefix_len with addresses on device @dev.
+ * If one is found it returns true.
+ */
+bool ipv6_chk_custom_prefix(const struct in6_addr *addr,
+       const unsigned int prefix_len, struct net_device *dev)
+{
+       struct inet6_dev *idev;
+       struct inet6_ifaddr *ifa;
+       bool ret = false;
+
+       rcu_read_lock();
+       idev = __in6_dev_get(dev);
+       if (idev) {
+               read_lock_bh(&idev->lock);
+               list_for_each_entry(ifa, &idev->addr_list, if_list) {
+                       ret = ipv6_prefix_equal(addr, &ifa->addr, prefix_len);
+                       if (ret)
+                               break;
+               }
+               read_unlock_bh(&idev->lock);
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+EXPORT_SYMBOL(ipv6_chk_custom_prefix);
+
 int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev)
 {
        struct inet6_dev *idev;
@@ -2193,43 +2220,21 @@ ok:
                        else
                                stored_lft = 0;
                        if (!update_lft && !create && stored_lft) {
-                               if (valid_lft > MIN_VALID_LIFETIME ||
-                                   valid_lft > stored_lft)
-                                       update_lft = 1;
-                               else if (stored_lft <= MIN_VALID_LIFETIME) {
-                                       /* valid_lft <= stored_lft is always true */
-                                       /*
-                                        * RFC 4862 Section 5.5.3e:
-                                        * "Note that the preferred lifetime of
-                                        *  the corresponding address is always
-                                        *  reset to the Preferred Lifetime in
-                                        *  the received Prefix Information
-                                        *  option, regardless of whether the
-                                        *  valid lifetime is also reset or
-                                        *  ignored."
-                                        *
-                                        *  So if the preferred lifetime in
-                                        *  this advertisement is different
-                                        *  than what we have stored, but the
-                                        *  valid lifetime is invalid, just
-                                        *  reset prefered_lft.
-                                        *
-                                        *  We must set the valid lifetime
-                                        *  to the stored lifetime since we'll
-                                        *  be updating the timestamp below,
-                                        *  else we'll set it back to the
-                                        *  minimum.
-                                        */
-                                       if (prefered_lft != ifp->prefered_lft) {
-                                               valid_lft = stored_lft;
-                                               update_lft = 1;
-                                       }
-                               } else {
-                                       valid_lft = MIN_VALID_LIFETIME;
-                                       if (valid_lft < prefered_lft)
-                                               prefered_lft = valid_lft;
-                                       update_lft = 1;
-                               }
+                               const u32 minimum_lft = min(
+                                       stored_lft, (u32)MIN_VALID_LIFETIME);
+                               valid_lft = max(valid_lft, minimum_lft);
+
+                               /* RFC4862 Section 5.5.3e:
+                                * "Note that the preferred lifetime of the
+                                *  corresponding address is always reset to
+                                *  the Preferred Lifetime in the received
+                                *  Prefix Information option, regardless of
+                                *  whether the valid lifetime is also reset or
+                                *  ignored."
+                                *
+                                * So we should always update prefered_lft here.
+                                */
+                               update_lft = 1;
                        }
 
                        if (update_lft) {
index 73784c3..82e1da3 100644 (file)
@@ -618,8 +618,7 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset);
        struct xfrm_state *x;
 
-       if (type != ICMPV6_DEST_UNREACH &&
-           type != ICMPV6_PKT_TOOBIG &&
+       if (type != ICMPV6_PKT_TOOBIG &&
            type != NDISC_REDIRECT)
                return;
 
index d3618a7..e67e63f 100644 (file)
@@ -436,8 +436,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset);
        struct xfrm_state *x;
 
-       if (type != ICMPV6_DEST_UNREACH &&
-           type != ICMPV6_PKT_TOOBIG &&
+       if (type != ICMPV6_PKT_TOOBIG &&
            type != NDISC_REDIRECT)
                return;
 
index 32b4a16..066640e 100644 (file)
@@ -116,7 +116,7 @@ begintw:
                        }
                        if (unlikely(!INET6_TW_MATCH(sk, net, saddr, daddr,
                                                     ports, dif))) {
-                               sock_put(sk);
+                               inet_twsk_put(inet_twsk(sk));
                                goto begintw;
                        }
                        goto out;
index 6b26e9f..bf4a9a0 100644 (file)
@@ -618,7 +618,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
        struct ip6_tnl *tunnel = netdev_priv(dev);
        struct net_device *tdev;    /* Device to other host */
        struct ipv6hdr  *ipv6h;     /* Our new IP header */
-       unsigned int max_headroom /* The extra header space needed */
+       unsigned int max_headroom = 0; /* The extra header space needed */
        int    gre_hlen;
        struct ipv6_tel_txoption opt;
        int    mtu;
@@ -693,7 +693,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
 
        skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
 
-       max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len;
+       max_headroom += LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len;
 
        if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
            (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
@@ -976,6 +976,7 @@ static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu)
                if (t->parms.o_flags&GRE_SEQ)
                        addend += 4;
        }
+       t->hlen = addend;
 
        if (p->flags & IP6_TNL_F_CAP_XMIT) {
                int strict = (ipv6_addr_type(&p->raddr) &
@@ -1002,8 +1003,6 @@ static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu)
                }
                ip6_rt_put(rt);
        }
-
-       t->hlen = addend;
 }
 
 static int ip6gre_tnl_change(struct ip6_tnl *t,
@@ -1173,9 +1172,8 @@ done:
 
 static int ip6gre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
 {
-       struct ip6_tnl *tunnel = netdev_priv(dev);
        if (new_mtu < 68 ||
-           new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen)
+           new_mtu > 0xFFF8 - dev->hard_header_len)
                return -EINVAL;
        dev->mtu = new_mtu;
        return 0;
index 3a692d5..91fb4e8 100644 (file)
@@ -105,7 +105,7 @@ static int ip6_finish_output2(struct sk_buff *skb)
        }
 
        rcu_read_lock_bh();
-       nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr);
+       nexthop = rt6_nexthop((struct rt6_info *)dst);
        neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
        if (unlikely(!neigh))
                neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
@@ -874,7 +874,7 @@ static int ip6_dst_lookup_tail(struct sock *sk,
         */
        rt = (struct rt6_info *) *dst;
        rcu_read_lock_bh();
-       n = __ipv6_neigh_lookup_noref(rt->dst.dev, rt6_nexthop(rt, &fl6->daddr));
+       n = __ipv6_neigh_lookup_noref(rt->dst.dev, rt6_nexthop(rt));
        err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0;
        rcu_read_unlock_bh();
 
@@ -1008,6 +1008,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
 
 {
        struct sk_buff *skb;
+       struct frag_hdr fhdr;
        int err;
 
        /* There is support for UDP large send offload by network
@@ -1034,33 +1035,26 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                skb->transport_header = skb->network_header + fragheaderlen;
 
                skb->protocol = htons(ETH_P_IPV6);
-               skb->ip_summed = CHECKSUM_PARTIAL;
                skb->csum = 0;
-       }
-
-       err = skb_append_datato_frags(sk,skb, getfrag, from,
-                                     (length - transhdrlen));
-       if (!err) {
-               struct frag_hdr fhdr;
 
-               /* Specify the length of each IPv6 datagram fragment.
-                * It has to be a multiple of 8.
-                */
-               skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
-                                            sizeof(struct frag_hdr)) & ~7;
-               skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
-               ipv6_select_ident(&fhdr, rt);
-               skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
                __skb_queue_tail(&sk->sk_write_queue, skb);
-
-               return 0;
+       } else if (skb_is_gso(skb)) {
+               goto append;
        }
-       /* There is not enough support do UPD LSO,
-        * so follow normal path
-        */
-       kfree_skb(skb);
 
-       return err;
+       skb->ip_summed = CHECKSUM_PARTIAL;
+       /* Specify the length of each IPv6 datagram fragment.
+        * It has to be a multiple of 8.
+        */
+       skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
+                                    sizeof(struct frag_hdr)) & ~7;
+       skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+       ipv6_select_ident(&fhdr, rt);
+       skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
+
+append:
+       return skb_append_datato_frags(sk, skb, getfrag, from,
+                                      (length - transhdrlen));
 }
 
 static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,
@@ -1227,27 +1221,27 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
         * --yoshfuji
         */
 
-       cork->length += length;
-       if (length > mtu) {
-               int proto = sk->sk_protocol;
-               if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){
-                       ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
-                       return -EMSGSIZE;
-               }
-
-               if (proto == IPPROTO_UDP &&
-                   (rt->dst.dev->features & NETIF_F_UFO)) {
+       if ((length > mtu) && dontfrag && (sk->sk_protocol == IPPROTO_UDP ||
+                                          sk->sk_protocol == IPPROTO_RAW)) {
+               ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
+               return -EMSGSIZE;
+       }
 
-                       err = ip6_ufo_append_data(sk, getfrag, from, length,
-                                                 hh_len, fragheaderlen,
-                                                 transhdrlen, mtu, flags, rt);
-                       if (err)
-                               goto error;
-                       return 0;
-               }
+       skb = skb_peek_tail(&sk->sk_write_queue);
+       cork->length += length;
+       if (((length > mtu) ||
+            (skb && skb_is_gso(skb))) &&
+           (sk->sk_protocol == IPPROTO_UDP) &&
+           (rt->dst.dev->features & NETIF_F_UFO)) {
+               err = ip6_ufo_append_data(sk, getfrag, from, length,
+                                         hh_len, fragheaderlen,
+                                         transhdrlen, mtu, flags, rt);
+               if (err)
+                       goto error;
+               return 0;
        }
 
-       if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL)
+       if (!skb)
                goto alloc_new_skb;
 
        while (length > 0) {
index 2d8f482..583b77e 100644 (file)
@@ -1430,9 +1430,17 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 static int
 ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
 {
-       if (new_mtu < IPV6_MIN_MTU) {
-               return -EINVAL;
+       struct ip6_tnl *tnl = netdev_priv(dev);
+
+       if (tnl->parms.proto == IPPROTO_IPIP) {
+               if (new_mtu < 68)
+                       return -EINVAL;
+       } else {
+               if (new_mtu < IPV6_MIN_MTU)
+                       return -EINVAL;
        }
+       if (new_mtu > 0xFFF8 - dev->hard_header_len)
+               return -EINVAL;
        dev->mtu = new_mtu;
        return 0;
 }
@@ -1731,8 +1739,6 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
                }
        }
 
-       t = rtnl_dereference(ip6n->tnls_wc[0]);
-       unregister_netdevice_queue(t->dev, &list);
        unregister_netdevice_many(&list);
 }
 
@@ -1752,6 +1758,7 @@ static int __net_init ip6_tnl_init_net(struct net *net)
        if (!ip6n->fb_tnl_dev)
                goto err_alloc_dev;
        dev_net_set(ip6n->fb_tnl_dev, net);
+       ip6n->fb_tnl_dev->rtnl_link_ops = &ip6_link_ops;
        /* FB netdevice is special: we have one, and only one per netns.
         * Allowing to move it to another netns is clearly unsafe.
         */
index 5636a91..ce507d9 100644 (file)
@@ -64,8 +64,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                (struct ip_comp_hdr *)(skb->data + offset);
        struct xfrm_state *x;
 
-       if (type != ICMPV6_DEST_UNREACH &&
-           type != ICMPV6_PKT_TOOBIG &&
+       if (type != ICMPV6_PKT_TOOBIG &&
            type != NDISC_REDIRECT)
                return;
 
index 096cd67..d18f9f9 100644 (file)
@@ -2034,7 +2034,7 @@ static void mld_dad_timer_expire(unsigned long data)
                if (idev->mc_dad_count)
                        mld_dad_start_timer(idev, idev->mc_maxdelay);
        }
-       __in6_dev_put(idev);
+       in6_dev_put(idev);
 }
 
 static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
@@ -2379,7 +2379,7 @@ static void mld_gq_timer_expire(unsigned long data)
 
        idev->mc_gq_running = 0;
        mld_send_report(idev, NULL);
-       __in6_dev_put(idev);
+       in6_dev_put(idev);
 }
 
 static void mld_ifc_timer_expire(unsigned long data)
@@ -2392,7 +2392,7 @@ static void mld_ifc_timer_expire(unsigned long data)
                if (idev->mc_ifc_count)
                        mld_ifc_start_timer(idev, idev->mc_maxdelay);
        }
-       __in6_dev_put(idev);
+       in6_dev_put(idev);
 }
 
 static void mld_ifc_event(struct inet6_dev *idev)
index 19cfea8..2748b04 100644 (file)
@@ -282,7 +282,8 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
        if (th == NULL)
                return NF_DROP;
 
-       synproxy_parse_options(skb, par->thoff, th, &opts);
+       if (!synproxy_parse_options(skb, par->thoff, th, &opts))
+               return NF_DROP;
 
        if (th->syn && !(th->ack || th->fin || th->rst)) {
                /* Initial SYN from client */
@@ -372,7 +373,8 @@ static unsigned int ipv6_synproxy_hook(unsigned int hooknum,
 
                /* fall through */
        case TCP_CONNTRACK_SYN_SENT:
-               synproxy_parse_options(skb, thoff, th, &opts);
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
 
                if (!th->syn && th->ack &&
                    CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
@@ -395,7 +397,9 @@ static unsigned int ipv6_synproxy_hook(unsigned int hooknum,
                if (!th->syn || !th->ack)
                        break;
 
-               synproxy_parse_options(skb, thoff, th, &opts);
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
+
                if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
                        synproxy->tsoff = opts.tsval - synproxy->its;
 
index 58916bb..a4ed241 100644 (file)
@@ -335,8 +335,10 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb,
                ip6_sk_update_pmtu(skb, sk, info);
                harderr = (np->pmtudisc == IPV6_PMTUDISC_DO);
        }
-       if (type == NDISC_REDIRECT)
+       if (type == NDISC_REDIRECT) {
                ip6_sk_redirect(skb, sk);
+               return;
+       }
        if (np->recverr) {
                u8 *payload = skb->data;
                if (!inet->hdrincl)
index c979dd9..f54e3a1 100644 (file)
@@ -476,6 +476,24 @@ out:
 }
 
 #ifdef CONFIG_IPV6_ROUTER_PREF
+struct __rt6_probe_work {
+       struct work_struct work;
+       struct in6_addr target;
+       struct net_device *dev;
+};
+
+static void rt6_probe_deferred(struct work_struct *w)
+{
+       struct in6_addr mcaddr;
+       struct __rt6_probe_work *work =
+               container_of(w, struct __rt6_probe_work, work);
+
+       addrconf_addr_solict_mult(&work->target, &mcaddr);
+       ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL);
+       dev_put(work->dev);
+       kfree(w);
+}
+
 static void rt6_probe(struct rt6_info *rt)
 {
        struct neighbour *neigh;
@@ -499,17 +517,23 @@ static void rt6_probe(struct rt6_info *rt)
 
        if (!neigh ||
            time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
-               struct in6_addr mcaddr;
-               struct in6_addr *target;
+               struct __rt6_probe_work *work;
 
-               if (neigh) {
+               work = kmalloc(sizeof(*work), GFP_ATOMIC);
+
+               if (neigh && work)
                        neigh->updated = jiffies;
+
+               if (neigh)
                        write_unlock(&neigh->lock);
-               }
 
-               target = (struct in6_addr *)&rt->rt6i_gateway;
-               addrconf_addr_solict_mult(target, &mcaddr);
-               ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL);
+               if (work) {
+                       INIT_WORK(&work->work, rt6_probe_deferred);
+                       work->target = rt->rt6i_gateway;
+                       dev_hold(rt->dst.dev);
+                       work->dev = rt->dst.dev;
+                       schedule_work(&work->work);
+               }
        } else {
 out:
                write_unlock(&neigh->lock);
@@ -851,7 +875,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
                        if (ort->rt6i_dst.plen != 128 &&
                            ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
                                rt->rt6i_flags |= RTF_ANYCAST;
-                       rt->rt6i_gateway = *daddr;
                }
 
                rt->rt6i_flags |= RTF_CACHE;
@@ -1338,6 +1361,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
        rt->dst.flags |= DST_HOST;
        rt->dst.output  = ip6_output;
        atomic_set(&rt->dst.__refcnt, 1);
+       rt->rt6i_gateway  = fl6->daddr;
        rt->rt6i_dst.addr = fl6->daddr;
        rt->rt6i_dst.plen = 128;
        rt->rt6i_idev     = idev;
@@ -1873,7 +1897,10 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
                        in6_dev_hold(rt->rt6i_idev);
                rt->dst.lastuse = jiffies;
 
-               rt->rt6i_gateway = ort->rt6i_gateway;
+               if (ort->rt6i_flags & RTF_GATEWAY)
+                       rt->rt6i_gateway = ort->rt6i_gateway;
+               else
+                       rt->rt6i_gateway = *dest;
                rt->rt6i_flags = ort->rt6i_flags;
                if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ==
                    (RTF_DEFAULT | RTF_ADDRCONF))
@@ -2160,6 +2187,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
        else
                rt->rt6i_flags |= RTF_LOCAL;
 
+       rt->rt6i_gateway  = *addr;
        rt->rt6i_dst.addr = *addr;
        rt->rt6i_dst.plen = 128;
        rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
index 7ee5cb9..1926945 100644 (file)
@@ -566,6 +566,70 @@ static inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr,
        return false;
 }
 
+/* Checks if an address matches an address on the tunnel interface.
+ * Used to detect the NAT of proto 41 packets and let them pass spoofing test.
+ * Long story:
+ * This function is called after we considered the packet as spoofed
+ * in is_spoofed_6rd.
+ * We may have a router that is doing NAT for proto 41 packets
+ * for an internal station. Destination a.a.a.a/PREFIX:bbbb:bbbb
+ * will be translated to n.n.n.n/PREFIX:bbbb:bbbb. And is_spoofed_6rd
+ * function will return true, dropping the packet.
+ * But, we can still check if is spoofed against the IP
+ * addresses associated with the interface.
+ */
+static bool only_dnatted(const struct ip_tunnel *tunnel,
+       const struct in6_addr *v6dst)
+{
+       int prefix_len;
+
+#ifdef CONFIG_IPV6_SIT_6RD
+       prefix_len = tunnel->ip6rd.prefixlen + 32
+               - tunnel->ip6rd.relay_prefixlen;
+#else
+       prefix_len = 48;
+#endif
+       return ipv6_chk_custom_prefix(v6dst, prefix_len, tunnel->dev);
+}
+
+/* Returns true if a packet is spoofed */
+static bool packet_is_spoofed(struct sk_buff *skb,
+                             const struct iphdr *iph,
+                             struct ip_tunnel *tunnel)
+{
+       const struct ipv6hdr *ipv6h;
+
+       if (tunnel->dev->priv_flags & IFF_ISATAP) {
+               if (!isatap_chksrc(skb, iph, tunnel))
+                       return true;
+
+               return false;
+       }
+
+       if (tunnel->dev->flags & IFF_POINTOPOINT)
+               return false;
+
+       ipv6h = ipv6_hdr(skb);
+
+       if (unlikely(is_spoofed_6rd(tunnel, iph->saddr, &ipv6h->saddr))) {
+               net_warn_ratelimited("Src spoofed %pI4/%pI6c -> %pI4/%pI6c\n",
+                                    &iph->saddr, &ipv6h->saddr,
+                                    &iph->daddr, &ipv6h->daddr);
+               return true;
+       }
+
+       if (likely(!is_spoofed_6rd(tunnel, iph->daddr, &ipv6h->daddr)))
+               return false;
+
+       if (only_dnatted(tunnel, &ipv6h->daddr))
+               return false;
+
+       net_warn_ratelimited("Dst spoofed %pI4/%pI6c -> %pI4/%pI6c\n",
+                            &iph->saddr, &ipv6h->saddr,
+                            &iph->daddr, &ipv6h->daddr);
+       return true;
+}
+
 static int ipip6_rcv(struct sk_buff *skb)
 {
        const struct iphdr *iph = ip_hdr(skb);
@@ -586,19 +650,9 @@ static int ipip6_rcv(struct sk_buff *skb)
                IPCB(skb)->flags = 0;
                skb->protocol = htons(ETH_P_IPV6);
 
-               if (tunnel->dev->priv_flags & IFF_ISATAP) {
-                       if (!isatap_chksrc(skb, iph, tunnel)) {
-                               tunnel->dev->stats.rx_errors++;
-                               goto out;
-                       }
-               } else if (!(tunnel->dev->flags&IFF_POINTOPOINT)) {
-                       if (is_spoofed_6rd(tunnel, iph->saddr,
-                                          &ipv6_hdr(skb)->saddr) ||
-                           is_spoofed_6rd(tunnel, iph->daddr,
-                                          &ipv6_hdr(skb)->daddr)) {
-                               tunnel->dev->stats.rx_errors++;
-                               goto out;
-                       }
+               if (packet_is_spoofed(skb, iph, tunnel)) {
+                       tunnel->dev->stats.rx_errors++;
+                       goto out;
                }
 
                __skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
@@ -748,7 +802,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
                        neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr);
 
                if (neigh == NULL) {
-                       net_dbg_ratelimited("sit: nexthop == NULL\n");
+                       net_dbg_ratelimited("nexthop == NULL\n");
                        goto tx_error;
                }
 
@@ -777,7 +831,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
                        neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr);
 
                if (neigh == NULL) {
-                       net_dbg_ratelimited("sit: nexthop == NULL\n");
+                       net_dbg_ratelimited("nexthop == NULL\n");
                        goto tx_error;
                }
 
@@ -1612,6 +1666,7 @@ static int __net_init sit_init_net(struct net *net)
                goto err_alloc_dev;
        }
        dev_net_set(sitn->fb_tunnel_dev, net);
+       sitn->fb_tunnel_dev->rtnl_link_ops = &sit_link_ops;
        /* FB netdevice is special: we have one, and only one per netns.
         * Allowing to move it to another netns is clearly unsafe.
         */
@@ -1646,7 +1701,6 @@ static void __net_exit sit_exit_net(struct net *net)
 
        rtnl_lock();
        sit_destroy_tunnels(sitn, &list);
-       unregister_netdevice_queue(sitn->fb_tunnel_dev, &list);
        unregister_netdevice_many(&list);
        rtnl_unlock();
 }
index f405815..1878609 100644 (file)
@@ -525,8 +525,10 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
        if (type == ICMPV6_PKT_TOOBIG)
                ip6_sk_update_pmtu(skb, sk, info);
-       if (type == NDISC_REDIRECT)
+       if (type == NDISC_REDIRECT) {
                ip6_sk_redirect(skb, sk);
+               goto out;
+       }
 
        np = inet6_sk(sk);
 
@@ -1223,9 +1225,6 @@ do_udp_sendmsg:
        if (tclass < 0)
                tclass = np->tclass;
 
-       if (dontfrag < 0)
-               dontfrag = np->dontfrag;
-
        if (msg->msg_flags&MSG_CONFIRM)
                goto do_confirm;
 back_from_confirm:
@@ -1244,6 +1243,8 @@ back_from_confirm:
        up->pending = AF_INET6;
 
 do_append_data:
+       if (dontfrag < 0)
+               dontfrag = np->dontfrag;
        up->len += ulen;
        getfrag  =  is_udplite ?  udplite_getfrag : ip_generic_getfrag;
        err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen,
index 23ed03d..08ed277 100644 (file)
@@ -138,6 +138,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
 
        memset(fl6, 0, sizeof(struct flowi6));
        fl6->flowi6_mark = skb->mark;
+       fl6->flowi6_oif = skb_dst(skb)->dev->ifindex;
 
        fl6->daddr = reverse ? hdr->saddr : hdr->daddr;
        fl6->saddr = reverse ? hdr->daddr : hdr->saddr;
index 9d58537..911ef03 100644 (file)
@@ -1098,7 +1098,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
 
        x->id.proto = proto;
        x->id.spi = sa->sadb_sa_spi;
-       x->props.replay_window = sa->sadb_sa_replay;
+       x->props.replay_window = min_t(unsigned int, sa->sadb_sa_replay,
+                                       (sizeof(x->replay.bitmap) * 8));
        if (sa->sadb_sa_flags & SADB_SAFLAGS_NOECN)
                x->props.flags |= XFRM_STATE_NOECN;
        if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP)
index feae495..b076e83 100644 (file)
@@ -115,6 +115,11 @@ struct l2tp_net {
 static void l2tp_session_set_header_len(struct l2tp_session *session, int version);
 static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
 
+static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk)
+{
+       return sk->sk_user_data;
+}
+
 static inline struct l2tp_net *l2tp_pernet(struct net *net)
 {
        BUG_ON(!net);
@@ -504,7 +509,7 @@ static inline int l2tp_verify_udp_checksum(struct sock *sk,
                return 0;
 
 #if IS_ENABLED(CONFIG_IPV6)
-       if (sk->sk_family == PF_INET6) {
+       if (sk->sk_family == PF_INET6 && !l2tp_tunnel(sk)->v4mapped) {
                if (!uh->check) {
                        LIMIT_NETDEBUG(KERN_INFO "L2TP: IPv6: checksum is 0\n");
                        return 1;
@@ -1128,7 +1133,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
        /* Queue the packet to IP for output */
        skb->local_df = 1;
 #if IS_ENABLED(CONFIG_IPV6)
-       if (skb->sk->sk_family == PF_INET6)
+       if (skb->sk->sk_family == PF_INET6 && !tunnel->v4mapped)
                error = inet6_csk_xmit(skb, NULL);
        else
 #endif
@@ -1255,7 +1260,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
 
                /* Calculate UDP checksum if configured to do so */
 #if IS_ENABLED(CONFIG_IPV6)
-               if (sk->sk_family == PF_INET6)
+               if (sk->sk_family == PF_INET6 && !tunnel->v4mapped)
                        l2tp_xmit_ipv6_csum(sk, skb, udp_len);
                else
 #endif
@@ -1304,10 +1309,9 @@ EXPORT_SYMBOL_GPL(l2tp_xmit_skb);
  */
 static void l2tp_tunnel_destruct(struct sock *sk)
 {
-       struct l2tp_tunnel *tunnel;
+       struct l2tp_tunnel *tunnel = l2tp_tunnel(sk);
        struct l2tp_net *pn;
 
-       tunnel = sk->sk_user_data;
        if (tunnel == NULL)
                goto end;
 
@@ -1675,7 +1679,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
        }
 
        /* Check if this socket has already been prepped */
-       tunnel = (struct l2tp_tunnel *)sk->sk_user_data;
+       tunnel = l2tp_tunnel(sk);
        if (tunnel != NULL) {
                /* This socket has already been prepped */
                err = -EBUSY;
@@ -1704,6 +1708,24 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
        if (cfg != NULL)
                tunnel->debug = cfg->debug;
 
+#if IS_ENABLED(CONFIG_IPV6)
+       if (sk->sk_family == PF_INET6) {
+               struct ipv6_pinfo *np = inet6_sk(sk);
+
+               if (ipv6_addr_v4mapped(&np->saddr) &&
+                   ipv6_addr_v4mapped(&np->daddr)) {
+                       struct inet_sock *inet = inet_sk(sk);
+
+                       tunnel->v4mapped = true;
+                       inet->inet_saddr = np->saddr.s6_addr32[3];
+                       inet->inet_rcv_saddr = np->rcv_saddr.s6_addr32[3];
+                       inet->inet_daddr = np->daddr.s6_addr32[3];
+               } else {
+                       tunnel->v4mapped = false;
+               }
+       }
+#endif
+
        /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
        tunnel->encap = encap;
        if (encap == L2TP_ENCAPTYPE_UDP) {
@@ -1712,7 +1734,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
                udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
                udp_sk(sk)->encap_destroy = l2tp_udp_encap_destroy;
 #if IS_ENABLED(CONFIG_IPV6)
-               if (sk->sk_family == PF_INET6)
+               if (sk->sk_family == PF_INET6 && !tunnel->v4mapped)
                        udpv6_encap_enable();
                else
 #endif
index 66a559b..6f251cb 100644 (file)
@@ -194,6 +194,9 @@ struct l2tp_tunnel {
        struct sock             *sock;          /* Parent socket */
        int                     fd;             /* Parent fd, if tunnel socket
                                                 * was created by userspace */
+#if IS_ENABLED(CONFIG_IPV6)
+       bool                    v4mapped;
+#endif
 
        struct work_struct      del_work;
 
index 5ebee2d..8c46b27 100644 (file)
@@ -353,7 +353,9 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
                goto error_put_sess_tun;
        }
 
+       local_bh_disable();
        l2tp_xmit_skb(session, skb, session->hdr_len);
+       local_bh_enable();
 
        sock_put(ps->tunnel_sock);
        sock_put(sk);
@@ -422,7 +424,9 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        skb->data[0] = ppph[0];
        skb->data[1] = ppph[1];
 
+       local_bh_disable();
        l2tp_xmit_skb(session, skb, session->hdr_len);
+       local_bh_enable();
 
        sock_put(sk_tun);
        sock_put(sk);
index 54563ad..355cc3b 100644 (file)
@@ -154,6 +154,7 @@ static void lapb_t1timer_expiry(unsigned long param)
                        } else {
                                lapb->n2count++;
                                lapb_requeue_frames(lapb);
+                               lapb_kick(lapb);
                        }
                        break;
 
index 2e7855a..629dee7 100644 (file)
@@ -3518,7 +3518,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
                return -EINVAL;
        }
        band = chanctx_conf->def.chan->band;
-       sta = sta_info_get(sdata, peer);
+       sta = sta_info_get_bss(sdata, peer);
        if (sta) {
                qos = test_sta_flag(sta, WLAN_STA_WME);
        } else {
index b618651..611abfc 100644 (file)
@@ -893,6 +893,8 @@ struct tpt_led_trigger {
  *     that the scan completed.
  * @SCAN_ABORTED: Set for our scan work function when the driver reported
  *     a scan complete for an aborted scan.
+ * @SCAN_HW_CANCELLED: Set for our scan work function when the scan is being
+ *     cancelled.
  */
 enum {
        SCAN_SW_SCANNING,
@@ -900,6 +902,7 @@ enum {
        SCAN_ONCHANNEL_SCANNING,
        SCAN_COMPLETED,
        SCAN_ABORTED,
+       SCAN_HW_CANCELLED,
 };
 
 /**
index acd1f71..0c2a294 100644 (file)
@@ -394,6 +394,8 @@ void ieee80211_sw_roc_work(struct work_struct *work)
 
                if (started)
                        ieee80211_start_next_roc(local);
+               else if (list_empty(&local->roc_list))
+                       ieee80211_run_deferred_scan(local);
        }
 
  out_unlock:
index 54395d7..674eac1 100644 (file)
@@ -3056,6 +3056,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
        case NL80211_IFTYPE_ADHOC:
                if (!bssid)
                        return 0;
+               if (ether_addr_equal(sdata->vif.addr, hdr->addr2) ||
+                   ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2))
+                       return 0;
                if (ieee80211_is_beacon(hdr->frame_control)) {
                        return 1;
                } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
index 08afe74..d2d17a4 100644 (file)
@@ -238,6 +238,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
        enum ieee80211_band band;
        int i, ielen, n_chans;
 
+       if (test_bit(SCAN_HW_CANCELLED, &local->scanning))
+               return false;
+
        do {
                if (local->hw_scan_band == IEEE80211_NUM_BANDS)
                        return false;
@@ -940,7 +943,23 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
        if (!local->scan_req)
                goto out;
 
+       /*
+        * We have a scan running and the driver already reported completion,
+        * but the worker hasn't run yet or is stuck on the mutex - mark it as
+        * cancelled.
+        */
+       if (test_bit(SCAN_HW_SCANNING, &local->scanning) &&
+           test_bit(SCAN_COMPLETED, &local->scanning)) {
+               set_bit(SCAN_HW_CANCELLED, &local->scanning);
+               goto out;
+       }
+
        if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
+               /*
+                * Make sure that __ieee80211_scan_completed doesn't trigger a
+                * scan on another band.
+                */
+               set_bit(SCAN_HW_CANCELLED, &local->scanning);
                if (local->ops->cancel_hw_scan)
                        drv_cancel_hw_scan(local,
                                rcu_dereference_protected(local->scan_sdata,
index 368837f..78dc2e9 100644 (file)
@@ -180,6 +180,9 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
 
+       if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
+               sta->last_rx = jiffies;
+
        if (ieee80211_is_data_qos(mgmt->frame_control)) {
                struct ieee80211_hdr *hdr = (void *) skb->data;
                u8 *qc = ieee80211_get_qos_ctl(hdr);
index 3456c04..70b5a05 100644 (file)
@@ -1120,7 +1120,8 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
                tx->sta = rcu_dereference(sdata->u.vlan.sta);
                if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
                        return TX_DROP;
-       } else if (info->flags & IEEE80211_TX_CTL_INJECTED ||
+       } else if (info->flags & (IEEE80211_TX_CTL_INJECTED |
+                                 IEEE80211_TX_INTFL_NL80211_FRAME_TX) ||
                   tx->sdata->control_port_protocol == tx->skb->protocol) {
                tx->sta = sta_info_get_bss(sdata, hdr->addr1);
        }
index e1b34a1..69e4ef5 100644 (file)
@@ -2103,7 +2103,7 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
-       int rate, skip, shift;
+       int rate, shift;
        u8 i, exrates, *pos;
        u32 basic_rates = sdata->vif.bss_conf.basic_rates;
        u32 rate_flags;
@@ -2131,14 +2131,11 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
                pos = skb_put(skb, exrates + 2);
                *pos++ = WLAN_EID_EXT_SUPP_RATES;
                *pos++ = exrates;
-               skip = 0;
                for (i = 8; i < sband->n_bitrates; i++) {
                        u8 basic = 0;
                        if ((rate_flags & sband->bitrates[i].flags)
                            != rate_flags)
                                continue;
-                       if (skip++ < 8)
-                               continue;
                        if (need_basic && basic_rates & BIT(i))
                                basic = 0x80;
                        rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
@@ -2241,6 +2238,10 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
        }
 
        rate = cfg80211_calculate_bitrate(&ri);
+       if (WARN_ONCE(!rate,
+                     "Invalid bitrate: flags=0x%x, idx=%d, vht_nss=%d\n",
+                     status->flag, status->rate_idx, status->vht_nss))
+               return 0;
 
        /* rewind from end of MPDU */
        if (status->flag & RX_FLAG_MACTIME_END)
index 4f69e83..74fd00c 100644 (file)
@@ -116,6 +116,7 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
 
        if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
                struct ip_vs_cpu_stats *s;
+               struct ip_vs_service *svc;
 
                s = this_cpu_ptr(dest->stats.cpustats);
                s->ustats.inpkts++;
@@ -123,11 +124,14 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
                s->ustats.inbytes += skb->len;
                u64_stats_update_end(&s->syncp);
 
-               s = this_cpu_ptr(dest->svc->stats.cpustats);
+               rcu_read_lock();
+               svc = rcu_dereference(dest->svc);
+               s = this_cpu_ptr(svc->stats.cpustats);
                s->ustats.inpkts++;
                u64_stats_update_begin(&s->syncp);
                s->ustats.inbytes += skb->len;
                u64_stats_update_end(&s->syncp);
+               rcu_read_unlock();
 
                s = this_cpu_ptr(ipvs->tot_stats.cpustats);
                s->ustats.inpkts++;
@@ -146,6 +150,7 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
 
        if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
                struct ip_vs_cpu_stats *s;
+               struct ip_vs_service *svc;
 
                s = this_cpu_ptr(dest->stats.cpustats);
                s->ustats.outpkts++;
@@ -153,11 +158,14 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
                s->ustats.outbytes += skb->len;
                u64_stats_update_end(&s->syncp);
 
-               s = this_cpu_ptr(dest->svc->stats.cpustats);
+               rcu_read_lock();
+               svc = rcu_dereference(dest->svc);
+               s = this_cpu_ptr(svc->stats.cpustats);
                s->ustats.outpkts++;
                u64_stats_update_begin(&s->syncp);
                s->ustats.outbytes += skb->len;
                u64_stats_update_end(&s->syncp);
+               rcu_read_unlock();
 
                s = this_cpu_ptr(ipvs->tot_stats.cpustats);
                s->ustats.outpkts++;
index c8148e4..a3df9bd 100644 (file)
@@ -460,7 +460,7 @@ static inline void
 __ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
 {
        atomic_inc(&svc->refcnt);
-       dest->svc = svc;
+       rcu_assign_pointer(dest->svc, svc);
 }
 
 static void ip_vs_service_free(struct ip_vs_service *svc)
@@ -470,18 +470,25 @@ static void ip_vs_service_free(struct ip_vs_service *svc)
        kfree(svc);
 }
 
-static void
-__ip_vs_unbind_svc(struct ip_vs_dest *dest)
+static void ip_vs_service_rcu_free(struct rcu_head *head)
 {
-       struct ip_vs_service *svc = dest->svc;
+       struct ip_vs_service *svc;
+
+       svc = container_of(head, struct ip_vs_service, rcu_head);
+       ip_vs_service_free(svc);
+}
 
-       dest->svc = NULL;
+static void __ip_vs_svc_put(struct ip_vs_service *svc, bool do_delay)
+{
        if (atomic_dec_and_test(&svc->refcnt)) {
                IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n",
                              svc->fwmark,
                              IP_VS_DBG_ADDR(svc->af, &svc->addr),
                              ntohs(svc->port));
-               ip_vs_service_free(svc);
+               if (do_delay)
+                       call_rcu(&svc->rcu_head, ip_vs_service_rcu_free);
+               else
+                       ip_vs_service_free(svc);
        }
 }
 
@@ -667,11 +674,6 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
                              IP_VS_DBG_ADDR(svc->af, &dest->addr),
                              ntohs(dest->port),
                              atomic_read(&dest->refcnt));
-               /* We can not reuse dest while in grace period
-                * because conns still can use dest->svc
-                */
-               if (test_bit(IP_VS_DEST_STATE_REMOVING, &dest->state))
-                       continue;
                if (dest->af == svc->af &&
                    ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
                    dest->port == dport &&
@@ -697,8 +699,10 @@ out:
 
 static void ip_vs_dest_free(struct ip_vs_dest *dest)
 {
+       struct ip_vs_service *svc = rcu_dereference_protected(dest->svc, 1);
+
        __ip_vs_dst_cache_reset(dest);
-       __ip_vs_unbind_svc(dest);
+       __ip_vs_svc_put(svc, false);
        free_percpu(dest->stats.cpustats);
        kfree(dest);
 }
@@ -771,6 +775,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
                    struct ip_vs_dest_user_kern *udest, int add)
 {
        struct netns_ipvs *ipvs = net_ipvs(svc->net);
+       struct ip_vs_service *old_svc;
        struct ip_vs_scheduler *sched;
        int conn_flags;
 
@@ -792,13 +797,14 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
        atomic_set(&dest->conn_flags, conn_flags);
 
        /* bind the service */
-       if (!dest->svc) {
+       old_svc = rcu_dereference_protected(dest->svc, 1);
+       if (!old_svc) {
                __ip_vs_bind_svc(dest, svc);
        } else {
-               if (dest->svc != svc) {
-                       __ip_vs_unbind_svc(dest);
+               if (old_svc != svc) {
                        ip_vs_zero_stats(&dest->stats);
                        __ip_vs_bind_svc(dest, svc);
+                       __ip_vs_svc_put(old_svc, true);
                }
        }
 
@@ -998,16 +1004,6 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
        return 0;
 }
 
-static void ip_vs_dest_wait_readers(struct rcu_head *head)
-{
-       struct ip_vs_dest *dest = container_of(head, struct ip_vs_dest,
-                                              rcu_head);
-
-       /* End of grace period after unlinking */
-       clear_bit(IP_VS_DEST_STATE_REMOVING, &dest->state);
-}
-
-
 /*
  *     Delete a destination (must be already unlinked from the service)
  */
@@ -1023,20 +1019,16 @@ static void __ip_vs_del_dest(struct net *net, struct ip_vs_dest *dest,
         */
        ip_vs_rs_unhash(dest);
 
-       if (!cleanup) {
-               set_bit(IP_VS_DEST_STATE_REMOVING, &dest->state);
-               call_rcu(&dest->rcu_head, ip_vs_dest_wait_readers);
-       }
-
        spin_lock_bh(&ipvs->dest_trash_lock);
        IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n",
                      IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
                      atomic_read(&dest->refcnt));
        if (list_empty(&ipvs->dest_trash) && !cleanup)
                mod_timer(&ipvs->dest_trash_timer,
-                         jiffies + IP_VS_DEST_TRASH_PERIOD);
+                         jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
        /* dest lives in trash without reference */
        list_add(&dest->t_list, &ipvs->dest_trash);
+       dest->idle_start = 0;
        spin_unlock_bh(&ipvs->dest_trash_lock);
        ip_vs_dest_put(dest);
 }
@@ -1108,24 +1100,30 @@ static void ip_vs_dest_trash_expire(unsigned long data)
        struct net *net = (struct net *) data;
        struct netns_ipvs *ipvs = net_ipvs(net);
        struct ip_vs_dest *dest, *next;
+       unsigned long now = jiffies;
 
        spin_lock(&ipvs->dest_trash_lock);
        list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) {
-               /* Skip if dest is in grace period */
-               if (test_bit(IP_VS_DEST_STATE_REMOVING, &dest->state))
-                       continue;
                if (atomic_read(&dest->refcnt) > 0)
                        continue;
+               if (dest->idle_start) {
+                       if (time_before(now, dest->idle_start +
+                                            IP_VS_DEST_TRASH_PERIOD))
+                               continue;
+               } else {
+                       dest->idle_start = max(1UL, now);
+                       continue;
+               }
                IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u from trash\n",
                              dest->vfwmark,
-                             IP_VS_DBG_ADDR(dest->svc->af, &dest->addr),
+                             IP_VS_DBG_ADDR(dest->af, &dest->addr),
                              ntohs(dest->port));
                list_del(&dest->t_list);
                ip_vs_dest_free(dest);
        }
        if (!list_empty(&ipvs->dest_trash))
                mod_timer(&ipvs->dest_trash_timer,
-                         jiffies + IP_VS_DEST_TRASH_PERIOD);
+                         jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
        spin_unlock(&ipvs->dest_trash_lock);
 }
 
@@ -1320,14 +1318,6 @@ out:
        return ret;
 }
 
-static void ip_vs_service_rcu_free(struct rcu_head *head)
-{
-       struct ip_vs_service *svc;
-
-       svc = container_of(head, struct ip_vs_service, rcu_head);
-       ip_vs_service_free(svc);
-}
-
 /*
  *     Delete a service from the service list
  *     - The service must be unlinked, unlocked and not referenced!
@@ -1376,13 +1366,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup)
        /*
         *    Free the service if nobody refers to it
         */
-       if (atomic_dec_and_test(&svc->refcnt)) {
-               IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n",
-                             svc->fwmark,
-                             IP_VS_DBG_ADDR(svc->af, &svc->addr),
-                             ntohs(svc->port));
-               call_rcu(&svc->rcu_head, ip_vs_service_rcu_free);
-       }
+       __ip_vs_svc_put(svc, true);
 
        /* decrease the module use count */
        ip_vs_use_count_dec();
index 6bee6d0..1425e9a 100644 (file)
@@ -59,12 +59,13 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
                                 struct ip_vs_cpu_stats __percpu *stats)
 {
        int i;
+       bool add = false;
 
        for_each_possible_cpu(i) {
                struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
                unsigned int start;
                __u64 inbytes, outbytes;
-               if (i) {
+               if (add) {
                        sum->conns += s->ustats.conns;
                        sum->inpkts += s->ustats.inpkts;
                        sum->outpkts += s->ustats.outpkts;
@@ -76,6 +77,7 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
                        sum->inbytes += inbytes;
                        sum->outbytes += outbytes;
                } else {
+                       add = true;
                        sum->conns = s->ustats.conns;
                        sum->inpkts = s->ustats.inpkts;
                        sum->outpkts = s->ustats.outpkts;
index 1383b0e..eff13c9 100644 (file)
@@ -93,7 +93,7 @@ struct ip_vs_lblc_entry {
        struct hlist_node       list;
        int                     af;             /* address family */
        union nf_inet_addr      addr;           /* destination IP address */
-       struct ip_vs_dest __rcu *dest;          /* real server (cache) */
+       struct ip_vs_dest       *dest;          /* real server (cache) */
        unsigned long           lastuse;        /* last used time */
        struct rcu_head         rcu_head;
 };
@@ -130,20 +130,21 @@ static struct ctl_table vs_vars_table[] = {
 };
 #endif
 
-static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
+static void ip_vs_lblc_rcu_free(struct rcu_head *head)
 {
-       struct ip_vs_dest *dest;
+       struct ip_vs_lblc_entry *en = container_of(head,
+                                                  struct ip_vs_lblc_entry,
+                                                  rcu_head);
 
-       hlist_del_rcu(&en->list);
-       /*
-        * We don't kfree dest because it is referred either by its service
-        * or the trash dest list.
-        */
-       dest = rcu_dereference_protected(en->dest, 1);
-       ip_vs_dest_put(dest);
-       kfree_rcu(en, rcu_head);
+       ip_vs_dest_put(en->dest);
+       kfree(en);
 }
 
+static inline void ip_vs_lblc_del(struct ip_vs_lblc_entry *en)
+{
+       hlist_del_rcu(&en->list);
+       call_rcu(&en->rcu_head, ip_vs_lblc_rcu_free);
+}
 
 /*
  *     Returns hash value for IPVS LBLC entry
@@ -203,30 +204,23 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
        struct ip_vs_lblc_entry *en;
 
        en = ip_vs_lblc_get(dest->af, tbl, daddr);
-       if (!en) {
-               en = kmalloc(sizeof(*en), GFP_ATOMIC);
-               if (!en)
-                       return NULL;
-
-               en->af = dest->af;
-               ip_vs_addr_copy(dest->af, &en->addr, daddr);
-               en->lastuse = jiffies;
+       if (en) {
+               if (en->dest == dest)
+                       return en;
+               ip_vs_lblc_del(en);
+       }
+       en = kmalloc(sizeof(*en), GFP_ATOMIC);
+       if (!en)
+               return NULL;
 
-               ip_vs_dest_hold(dest);
-               RCU_INIT_POINTER(en->dest, dest);
+       en->af = dest->af;
+       ip_vs_addr_copy(dest->af, &en->addr, daddr);
+       en->lastuse = jiffies;
 
-               ip_vs_lblc_hash(tbl, en);
-       } else {
-               struct ip_vs_dest *old_dest;
+       ip_vs_dest_hold(dest);
+       en->dest = dest;
 
-               old_dest = rcu_dereference_protected(en->dest, 1);
-               if (old_dest != dest) {
-                       ip_vs_dest_put(old_dest);
-                       ip_vs_dest_hold(dest);
-                       /* No ordering constraints for refcnt */
-                       RCU_INIT_POINTER(en->dest, dest);
-               }
-       }
+       ip_vs_lblc_hash(tbl, en);
 
        return en;
 }
@@ -246,7 +240,7 @@ static void ip_vs_lblc_flush(struct ip_vs_service *svc)
        tbl->dead = 1;
        for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
                hlist_for_each_entry_safe(en, next, &tbl->bucket[i], list) {
-                       ip_vs_lblc_free(en);
+                       ip_vs_lblc_del(en);
                        atomic_dec(&tbl->entries);
                }
        }
@@ -281,7 +275,7 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
                                        sysctl_lblc_expiration(svc)))
                                continue;
 
-                       ip_vs_lblc_free(en);
+                       ip_vs_lblc_del(en);
                        atomic_dec(&tbl->entries);
                }
                spin_unlock(&svc->sched_lock);
@@ -335,7 +329,7 @@ static void ip_vs_lblc_check_expire(unsigned long data)
                        if (time_before(now, en->lastuse + ENTRY_TIMEOUT))
                                continue;
 
-                       ip_vs_lblc_free(en);
+                       ip_vs_lblc_del(en);
                        atomic_dec(&tbl->entries);
                        goal--;
                }
@@ -443,8 +437,8 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc)
                        continue;
 
                doh = ip_vs_dest_conn_overhead(dest);
-               if (loh * atomic_read(&dest->weight) >
-                   doh * atomic_read(&least->weight)) {
+               if ((__s64)loh * atomic_read(&dest->weight) >
+                   (__s64)doh * atomic_read(&least->weight)) {
                        least = dest;
                        loh = doh;
                }
@@ -511,7 +505,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                 * free up entries from the trash at any time.
                 */
 
-               dest = rcu_dereference(en->dest);
+               dest = en->dest;
                if ((dest->flags & IP_VS_DEST_F_AVAILABLE) &&
                    atomic_read(&dest->weight) > 0 && !is_overloaded(dest, svc))
                        goto out;
@@ -631,7 +625,7 @@ static void __exit ip_vs_lblc_cleanup(void)
 {
        unregister_ip_vs_scheduler(&ip_vs_lblc_scheduler);
        unregister_pernet_subsys(&ip_vs_lblc_ops);
-       synchronize_rcu();
+       rcu_barrier();
 }
 
 
index 5199448..0b85500 100644 (file)
@@ -89,7 +89,7 @@
  */
 struct ip_vs_dest_set_elem {
        struct list_head        list;          /* list link */
-       struct ip_vs_dest __rcu *dest;         /* destination server */
+       struct ip_vs_dest       *dest;          /* destination server */
        struct rcu_head         rcu_head;
 };
 
@@ -107,11 +107,7 @@ static void ip_vs_dest_set_insert(struct ip_vs_dest_set *set,
 
        if (check) {
                list_for_each_entry(e, &set->list, list) {
-                       struct ip_vs_dest *d;
-
-                       d = rcu_dereference_protected(e->dest, 1);
-                       if (d == dest)
-                               /* already existed */
+                       if (e->dest == dest)
                                return;
                }
        }
@@ -121,7 +117,7 @@ static void ip_vs_dest_set_insert(struct ip_vs_dest_set *set,
                return;
 
        ip_vs_dest_hold(dest);
-       RCU_INIT_POINTER(e->dest, dest);
+       e->dest = dest;
 
        list_add_rcu(&e->list, &set->list);
        atomic_inc(&set->size);
@@ -129,22 +125,27 @@ static void ip_vs_dest_set_insert(struct ip_vs_dest_set *set,
        set->lastmod = jiffies;
 }
 
+static void ip_vs_lblcr_elem_rcu_free(struct rcu_head *head)
+{
+       struct ip_vs_dest_set_elem *e;
+
+       e = container_of(head, struct ip_vs_dest_set_elem, rcu_head);
+       ip_vs_dest_put(e->dest);
+       kfree(e);
+}
+
 static void
 ip_vs_dest_set_erase(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
 {
        struct ip_vs_dest_set_elem *e;
 
        list_for_each_entry(e, &set->list, list) {
-               struct ip_vs_dest *d;
-
-               d = rcu_dereference_protected(e->dest, 1);
-               if (d == dest) {
+               if (e->dest == dest) {
                        /* HIT */
                        atomic_dec(&set->size);
                        set->lastmod = jiffies;
-                       ip_vs_dest_put(dest);
                        list_del_rcu(&e->list);
-                       kfree_rcu(e, rcu_head);
+                       call_rcu(&e->rcu_head, ip_vs_lblcr_elem_rcu_free);
                        break;
                }
        }
@@ -155,16 +156,8 @@ static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set)
        struct ip_vs_dest_set_elem *e, *ep;
 
        list_for_each_entry_safe(e, ep, &set->list, list) {
-               struct ip_vs_dest *d;
-
-               d = rcu_dereference_protected(e->dest, 1);
-               /*
-                * We don't kfree dest because it is referred either
-                * by its service or by the trash dest list.
-                */
-               ip_vs_dest_put(d);
                list_del_rcu(&e->list);
-               kfree_rcu(e, rcu_head);
+               call_rcu(&e->rcu_head, ip_vs_lblcr_elem_rcu_free);
        }
 }
 
@@ -175,12 +168,9 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
        struct ip_vs_dest *dest, *least;
        int loh, doh;
 
-       if (set == NULL)
-               return NULL;
-
        /* select the first destination server, whose weight > 0 */
        list_for_each_entry_rcu(e, &set->list, list) {
-               least = rcu_dereference(e->dest);
+               least = e->dest;
                if (least->flags & IP_VS_DEST_F_OVERLOAD)
                        continue;
 
@@ -195,13 +185,13 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
        /* find the destination with the weighted least load */
   nextstage:
        list_for_each_entry_continue_rcu(e, &set->list, list) {
-               dest = rcu_dereference(e->dest);
+               dest = e->dest;
                if (dest->flags & IP_VS_DEST_F_OVERLOAD)
                        continue;
 
                doh = ip_vs_dest_conn_overhead(dest);
-               if ((loh * atomic_read(&dest->weight) >
-                    doh * atomic_read(&least->weight))
+               if (((__s64)loh * atomic_read(&dest->weight) >
+                    (__s64)doh * atomic_read(&least->weight))
                    && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
                        least = dest;
                        loh = doh;
@@ -232,7 +222,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
 
        /* select the first destination server, whose weight > 0 */
        list_for_each_entry(e, &set->list, list) {
-               most = rcu_dereference_protected(e->dest, 1);
+               most = e->dest;
                if (atomic_read(&most->weight) > 0) {
                        moh = ip_vs_dest_conn_overhead(most);
                        goto nextstage;
@@ -243,11 +233,11 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
        /* find the destination with the weighted most load */
   nextstage:
        list_for_each_entry_continue(e, &set->list, list) {
-               dest = rcu_dereference_protected(e->dest, 1);
+               dest = e->dest;
                doh = ip_vs_dest_conn_overhead(dest);
                /* moh/mw < doh/dw ==> moh*dw < doh*mw, where mw,dw>0 */
-               if ((moh * atomic_read(&dest->weight) <
-                    doh * atomic_read(&most->weight))
+               if (((__s64)moh * atomic_read(&dest->weight) <
+                    (__s64)doh * atomic_read(&most->weight))
                    && (atomic_read(&dest->weight) > 0)) {
                        most = dest;
                        moh = doh;
@@ -611,8 +601,8 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc)
                        continue;
 
                doh = ip_vs_dest_conn_overhead(dest);
-               if (loh * atomic_read(&dest->weight) >
-                   doh * atomic_read(&least->weight)) {
+               if ((__s64)loh * atomic_read(&dest->weight) >
+                   (__s64)doh * atomic_read(&least->weight)) {
                        least = dest;
                        loh = doh;
                }
@@ -819,7 +809,7 @@ static void __exit ip_vs_lblcr_cleanup(void)
 {
        unregister_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
        unregister_pernet_subsys(&ip_vs_lblcr_ops);
-       synchronize_rcu();
+       rcu_barrier();
 }
 
 
index d8d9860..961a6de 100644 (file)
@@ -40,7 +40,7 @@
 #include <net/ip_vs.h>
 
 
-static inline unsigned int
+static inline int
 ip_vs_nq_dest_overhead(struct ip_vs_dest *dest)
 {
        /*
@@ -59,7 +59,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                  struct ip_vs_iphdr *iph)
 {
        struct ip_vs_dest *dest, *least = NULL;
-       unsigned int loh = 0, doh;
+       int loh = 0, doh;
 
        IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
 
@@ -92,8 +92,8 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                }
 
                if (!least ||
-                   (loh * atomic_read(&dest->weight) >
-                    doh * atomic_read(&least->weight))) {
+                   ((__s64)loh * atomic_read(&dest->weight) >
+                    (__s64)doh * atomic_read(&least->weight))) {
                        least = dest;
                        loh = doh;
                }
index a5284cc..e446b9f 100644 (file)
@@ -44,7 +44,7 @@
 #include <net/ip_vs.h>
 
 
-static inline unsigned int
+static inline int
 ip_vs_sed_dest_overhead(struct ip_vs_dest *dest)
 {
        /*
@@ -63,7 +63,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                   struct ip_vs_iphdr *iph)
 {
        struct ip_vs_dest *dest, *least;
-       unsigned int loh, doh;
+       int loh, doh;
 
        IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
 
@@ -99,8 +99,8 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                if (dest->flags & IP_VS_DEST_F_OVERLOAD)
                        continue;
                doh = ip_vs_sed_dest_overhead(dest);
-               if (loh * atomic_read(&dest->weight) >
-                   doh * atomic_read(&least->weight)) {
+               if ((__s64)loh * atomic_read(&dest->weight) >
+                   (__s64)doh * atomic_read(&least->weight)) {
                        least = dest;
                        loh = doh;
                }
index 6dc1fa1..b5b4650 100644 (file)
@@ -35,7 +35,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                   struct ip_vs_iphdr *iph)
 {
        struct ip_vs_dest *dest, *least;
-       unsigned int loh, doh;
+       int loh, doh;
 
        IP_VS_DBG(6, "ip_vs_wlc_schedule(): Scheduling...\n");
 
@@ -71,8 +71,8 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                if (dest->flags & IP_VS_DEST_F_OVERLOAD)
                        continue;
                doh = ip_vs_dest_conn_overhead(dest);
-               if (loh * atomic_read(&dest->weight) >
-                   doh * atomic_read(&least->weight)) {
+               if ((__s64)loh * atomic_read(&dest->weight) >
+                   (__s64)doh * atomic_read(&least->weight)) {
                        least = dest;
                        loh = doh;
                }
index bdebd03..70866d1 100644 (file)
@@ -778,8 +778,8 @@ static int callforward_do_filter(const union nf_inet_addr *src,
                                   flowi6_to_flowi(&fl1), false)) {
                        if (!afinfo->route(&init_net, (struct dst_entry **)&rt2,
                                           flowi6_to_flowi(&fl2), false)) {
-                               if (!memcmp(&rt1->rt6i_gateway, &rt2->rt6i_gateway,
-                                           sizeof(rt1->rt6i_gateway)) &&
+                               if (ipv6_addr_equal(rt6_nexthop(rt1),
+                                                   rt6_nexthop(rt2)) &&
                                    rt1->dst.dev == rt2->dst.dev)
                                        ret = 1;
                                dst_release(&rt2->dst);
index 6fd967c..cdf4567 100644 (file)
@@ -24,7 +24,7 @@
 int synproxy_net_id;
 EXPORT_SYMBOL_GPL(synproxy_net_id);
 
-void
+bool
 synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
                       const struct tcphdr *th, struct synproxy_options *opts)
 {
@@ -32,7 +32,8 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
        u8 buf[40], *ptr;
 
        ptr = skb_header_pointer(skb, doff + sizeof(*th), length, buf);
-       BUG_ON(ptr == NULL);
+       if (ptr == NULL)
+               return false;
 
        opts->options = 0;
        while (length > 0) {
@@ -41,16 +42,16 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
 
                switch (opcode) {
                case TCPOPT_EOL:
-                       return;
+                       return true;
                case TCPOPT_NOP:
                        length--;
                        continue;
                default:
                        opsize = *ptr++;
                        if (opsize < 2)
-                               return;
+                               return true;
                        if (opsize > length)
-                               return;
+                               return true;
 
                        switch (opcode) {
                        case TCPOPT_MSS:
@@ -84,6 +85,7 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
                        length -= opsize;
                }
        }
+       return true;
 }
 EXPORT_SYMBOL_GPL(synproxy_parse_options);
 
index 32ad015..a9dfdda 100644 (file)
@@ -285,7 +285,7 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
 
 
 /* remove one skb from head of flow queue */
-static struct sk_buff *fq_dequeue_head(struct fq_flow *flow)
+static struct sk_buff *fq_dequeue_head(struct Qdisc *sch, struct fq_flow *flow)
 {
        struct sk_buff *skb = flow->head;
 
@@ -293,6 +293,8 @@ static struct sk_buff *fq_dequeue_head(struct fq_flow *flow)
                flow->head = skb->next;
                skb->next = NULL;
                flow->qlen--;
+               sch->qstats.backlog -= qdisc_pkt_len(skb);
+               sch->q.qlen--;
        }
        return skb;
 }
@@ -418,8 +420,9 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
        struct fq_flow_head *head;
        struct sk_buff *skb;
        struct fq_flow *f;
+       u32 rate;
 
-       skb = fq_dequeue_head(&q->internal);
+       skb = fq_dequeue_head(sch, &q->internal);
        if (skb)
                goto out;
        fq_check_throttled(q, now);
@@ -449,7 +452,7 @@ begin:
                goto begin;
        }
 
-       skb = fq_dequeue_head(f);
+       skb = fq_dequeue_head(sch, f);
        if (!skb) {
                head->first = f->next;
                /* force a pass through old_flows to prevent starvation */
@@ -466,43 +469,70 @@ begin:
        f->time_next_packet = now;
        f->credit -= qdisc_pkt_len(skb);
 
-       if (f->credit <= 0 &&
-           q->rate_enable &&
-           skb->sk && skb->sk->sk_state != TCP_TIME_WAIT) {
-               u32 rate = skb->sk->sk_pacing_rate ?: q->flow_default_rate;
+       if (f->credit > 0 || !q->rate_enable)
+               goto out;
 
-               rate = min(rate, q->flow_max_rate);
-               if (rate) {
-                       u64 len = (u64)qdisc_pkt_len(skb) * NSEC_PER_SEC;
+       rate = q->flow_max_rate;
+       if (skb->sk && skb->sk->sk_state != TCP_TIME_WAIT)
+               rate = min(skb->sk->sk_pacing_rate, rate);
 
-                       do_div(len, rate);
-                       /* Since socket rate can change later,
-                        * clamp the delay to 125 ms.
-                        * TODO: maybe segment the too big skb, as in commit
-                        * e43ac79a4bc ("sch_tbf: segment too big GSO packets")
-                        */
-                       if (unlikely(len > 125 * NSEC_PER_MSEC)) {
-                               len = 125 * NSEC_PER_MSEC;
-                               q->stat_pkts_too_long++;
-                       }
+       if (rate != ~0U) {
+               u32 plen = max(qdisc_pkt_len(skb), q->quantum);
+               u64 len = (u64)plen * NSEC_PER_SEC;
 
-                       f->time_next_packet = now + len;
+               if (likely(rate))
+                       do_div(len, rate);
+               /* Since socket rate can change later,
+                * clamp the delay to 125 ms.
+                * TODO: maybe segment the too big skb, as in commit
+                * e43ac79a4bc ("sch_tbf: segment too big GSO packets")
+                */
+               if (unlikely(len > 125 * NSEC_PER_MSEC)) {
+                       len = 125 * NSEC_PER_MSEC;
+                       q->stat_pkts_too_long++;
                }
+
+               f->time_next_packet = now + len;
        }
 out:
-       sch->qstats.backlog -= qdisc_pkt_len(skb);
        qdisc_bstats_update(sch, skb);
-       sch->q.qlen--;
        qdisc_unthrottled(sch);
        return skb;
 }
 
 static void fq_reset(struct Qdisc *sch)
 {
+       struct fq_sched_data *q = qdisc_priv(sch);
+       struct rb_root *root;
        struct sk_buff *skb;
+       struct rb_node *p;
+       struct fq_flow *f;
+       unsigned int idx;
 
-       while ((skb = fq_dequeue(sch)) != NULL)
+       while ((skb = fq_dequeue_head(sch, &q->internal)) != NULL)
                kfree_skb(skb);
+
+       if (!q->fq_root)
+               return;
+
+       for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
+               root = &q->fq_root[idx];
+               while ((p = rb_first(root)) != NULL) {
+                       f = container_of(p, struct fq_flow, fq_node);
+                       rb_erase(p, root);
+
+                       while ((skb = fq_dequeue_head(sch, f)) != NULL)
+                               kfree_skb(skb);
+
+                       kmem_cache_free(fq_flow_cachep, f);
+               }
+       }
+       q->new_flows.first      = NULL;
+       q->old_flows.first      = NULL;
+       q->delayed              = RB_ROOT;
+       q->flows                = 0;
+       q->inactive_flows       = 0;
+       q->throttled_flows      = 0;
 }
 
 static void fq_rehash(struct fq_sched_data *q,
@@ -622,7 +652,7 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
                q->quantum = nla_get_u32(tb[TCA_FQ_QUANTUM]);
 
        if (tb[TCA_FQ_INITIAL_QUANTUM])
-               q->quantum = nla_get_u32(tb[TCA_FQ_INITIAL_QUANTUM]);
+               q->initial_quantum = nla_get_u32(tb[TCA_FQ_INITIAL_QUANTUM]);
 
        if (tb[TCA_FQ_FLOW_DEFAULT_RATE])
                q->flow_default_rate = nla_get_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]);
@@ -645,6 +675,8 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = fq_dequeue(sch);
 
+               if (!skb)
+                       break;
                kfree_skb(skb);
                drop_count++;
        }
@@ -657,21 +689,9 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
 static void fq_destroy(struct Qdisc *sch)
 {
        struct fq_sched_data *q = qdisc_priv(sch);
-       struct rb_root *root;
-       struct rb_node *p;
-       unsigned int idx;
 
-       if (q->fq_root) {
-               for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
-                       root = &q->fq_root[idx];
-                       while ((p = rb_first(root)) != NULL) {
-                               rb_erase(p, root);
-                               kmem_cache_free(fq_flow_cachep,
-                                               container_of(p, struct fq_flow, fq_node));
-                       }
-               }
-               kfree(q->fq_root);
-       }
+       fq_reset(sch);
+       kfree(q->fq_root);
        qdisc_watchdog_cancel(&q->watchdog);
 }
 
@@ -711,12 +731,14 @@ static int fq_dump(struct Qdisc *sch, struct sk_buff *skb)
        if (opts == NULL)
                goto nla_put_failure;
 
+       /* TCA_FQ_FLOW_DEFAULT_RATE is not used anymore,
+        * do not bother giving its value
+        */
        if (nla_put_u32(skb, TCA_FQ_PLIMIT, sch->limit) ||
            nla_put_u32(skb, TCA_FQ_FLOW_PLIMIT, q->flow_plimit) ||
            nla_put_u32(skb, TCA_FQ_QUANTUM, q->quantum) ||
            nla_put_u32(skb, TCA_FQ_INITIAL_QUANTUM, q->initial_quantum) ||
            nla_put_u32(skb, TCA_FQ_RATE_ENABLE, q->rate_enable) ||
-           nla_put_u32(skb, TCA_FQ_FLOW_DEFAULT_RATE, q->flow_default_rate) ||
            nla_put_u32(skb, TCA_FQ_FLOW_MAX_RATE, q->flow_max_rate) ||
            nla_put_u32(skb, TCA_FQ_BUCKETS_LOG, q->fq_trees_log))
                goto nla_put_failure;
index a6d788d..b87e83d 100644 (file)
@@ -358,6 +358,21 @@ static psched_time_t packet_len_2_sched_time(unsigned int len, struct netem_sche
        return PSCHED_NS2TICKS(ticks);
 }
 
+static void tfifo_reset(struct Qdisc *sch)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+       struct rb_node *p;
+
+       while ((p = rb_first(&q->t_root))) {
+               struct sk_buff *skb = netem_rb_to_skb(p);
+
+               rb_erase(p, &q->t_root);
+               skb->next = NULL;
+               skb->prev = NULL;
+               kfree_skb(skb);
+       }
+}
+
 static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
 {
        struct netem_sched_data *q = qdisc_priv(sch);
@@ -520,6 +535,7 @@ static unsigned int netem_drop(struct Qdisc *sch)
                        skb->next = NULL;
                        skb->prev = NULL;
                        len = qdisc_pkt_len(skb);
+                       sch->qstats.backlog -= len;
                        kfree_skb(skb);
                }
        }
@@ -609,6 +625,7 @@ static void netem_reset(struct Qdisc *sch)
        struct netem_sched_data *q = qdisc_priv(sch);
 
        qdisc_reset_queue(sch);
+       tfifo_reset(sch);
        if (q->qdisc)
                qdisc_reset(q->qdisc);
        qdisc_watchdog_cancel(&q->watchdog);
index 0ac3a65..3191373 100644 (file)
@@ -536,7 +536,8 @@ int sctp_packet_transmit(struct sctp_packet *packet)
         * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
         */
        if (!sctp_checksum_disable) {
-               if (!(dst->dev->features & NETIF_F_SCTP_CSUM)) {
+               if (!(dst->dev->features & NETIF_F_SCTP_CSUM) ||
+                   (dst_xfrm(dst) != NULL) || packet->ipfragok) {
                        __u32 crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len);
 
                        /* 3) Put the resultant value into the checksum field in the
index ebed4b6..c226ace 100644 (file)
@@ -1964,6 +1964,16 @@ struct used_address {
        unsigned int name_len;
 };
 
+static int copy_msghdr_from_user(struct msghdr *kmsg,
+                                struct msghdr __user *umsg)
+{
+       if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
+               return -EFAULT;
+       if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
+               return -EINVAL;
+       return 0;
+}
+
 static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
                         struct msghdr *msg_sys, unsigned int flags,
                         struct used_address *used_address)
@@ -1982,8 +1992,11 @@ static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
        if (MSG_CMSG_COMPAT & flags) {
                if (get_compat_msghdr(msg_sys, msg_compat))
                        return -EFAULT;
-       } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
-               return -EFAULT;
+       } else {
+               err = copy_msghdr_from_user(msg_sys, msg);
+               if (err)
+                       return err;
+       }
 
        if (msg_sys->msg_iovlen > UIO_FASTIOV) {
                err = -EMSGSIZE;
@@ -2191,8 +2204,11 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
        if (MSG_CMSG_COMPAT & flags) {
                if (get_compat_msghdr(msg_sys, msg_compat))
                        return -EFAULT;
-       } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
-               return -EFAULT;
+       } else {
+               err = copy_msghdr_from_user(msg_sys, msg);
+               if (err)
+                       return err;
+       }
 
        if (msg_sys->msg_iovlen > UIO_FASTIOV) {
                err = -EMSGSIZE;
index 9bc6db0..e7000be 100644 (file)
@@ -47,12 +47,12 @@ static int net_ctl_permissions(struct ctl_table_header *head,
 
        /* Allow network administrator to have same access as root. */
        if (ns_capable(net->user_ns, CAP_NET_ADMIN) ||
-           uid_eq(root_uid, current_uid())) {
+           uid_eq(root_uid, current_euid())) {
                int mode = (table->mode >> 6) & 7;
                return (mode << 6) | (mode << 3) | mode;
        }
        /* Allow netns root group to have the same access as the root group */
-       if (gid_eq(root_gid, current_gid())) {
+       if (in_egroup_p(root_gid)) {
                int mode = (table->mode >> 3) & 7;
                return (mode << 3) | mode;
        }
index 86de99a..c1f403b 100644 (file)
@@ -1246,6 +1246,15 @@ static int unix_socketpair(struct socket *socka, struct socket *sockb)
        return 0;
 }
 
+static void unix_sock_inherit_flags(const struct socket *old,
+                                   struct socket *new)
+{
+       if (test_bit(SOCK_PASSCRED, &old->flags))
+               set_bit(SOCK_PASSCRED, &new->flags);
+       if (test_bit(SOCK_PASSSEC, &old->flags))
+               set_bit(SOCK_PASSSEC, &new->flags);
+}
+
 static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
 {
        struct sock *sk = sock->sk;
@@ -1280,6 +1289,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
        /* attach accepted sock to socket */
        unix_state_lock(tsk);
        newsock->state = SS_CONNECTED;
+       unix_sock_inherit_flags(sock, newsock);
        sock_graft(tsk, newsock);
        unix_state_unlock(tsk);
        return 0;
index d591091..86fa0f3 100644 (file)
@@ -124,6 +124,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
        rep->udiag_family = AF_UNIX;
        rep->udiag_type = sk->sk_type;
        rep->udiag_state = sk->sk_state;
+       rep->pad = 0;
        rep->udiag_ino = sk_ino;
        sock_diag_save_cookie(sk, rep->udiag_cookie);
 
index 6715396..aff959e 100644 (file)
@@ -566,18 +566,13 @@ int wiphy_register(struct wiphy *wiphy)
        /* check and set up bitrates */
        ieee80211_set_bitrate_flags(wiphy);
 
-
+       rtnl_lock();
        res = device_add(&rdev->wiphy.dev);
-       if (res)
-               return res;
-
-       res = rfkill_register(rdev->rfkill);
        if (res) {
-               device_del(&rdev->wiphy.dev);
+               rtnl_unlock();
                return res;
        }
 
-       rtnl_lock();
        /* set up regulatory info */
        wiphy_regulatory_register(wiphy);
 
@@ -606,6 +601,15 @@ int wiphy_register(struct wiphy *wiphy)
 
        rdev->wiphy.registered = true;
        rtnl_unlock();
+
+       res = rfkill_register(rdev->rfkill);
+       if (res) {
+               rfkill_destroy(rdev->rfkill);
+               rdev->rfkill = NULL;
+               wiphy_unregister(&rdev->wiphy);
+               return res;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(wiphy_register);
@@ -640,7 +644,8 @@ void wiphy_unregister(struct wiphy *wiphy)
                rtnl_unlock();
                __count == 0; }));
 
-       rfkill_unregister(rdev->rfkill);
+       if (rdev->rfkill)
+               rfkill_unregister(rdev->rfkill);
 
        rtnl_lock();
        rdev->wiphy.registered = false;
@@ -953,8 +958,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
        case NETDEV_PRE_UP:
                if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
                        return notifier_from_errno(-EOPNOTSUPP);
-               if (rfkill_blocked(rdev->rfkill))
-                       return notifier_from_errno(-ERFKILL);
                ret = cfg80211_can_add_interface(rdev, wdev->iftype);
                if (ret)
                        return notifier_from_errno(ret);
index 9ad43c6..3159e9c 100644 (file)
@@ -411,6 +411,9 @@ static inline int
 cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
                           enum nl80211_iftype iftype)
 {
+       if (rfkill_blocked(rdev->rfkill))
+               return -ERFKILL;
+
        return cfg80211_can_change_interface(rdev, NULL, iftype);
 }
 
index 39bff7d..403fe29 100644 (file)
@@ -263,6 +263,8 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
                                if (chan->flags & IEEE80211_CHAN_DISABLED)
                                        continue;
                                wdev->wext.ibss.chandef.chan = chan;
+                               wdev->wext.ibss.chandef.center_freq1 =
+                                       chan->center_freq;
                                break;
                        }
 
@@ -347,6 +349,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
        if (chan) {
                wdev->wext.ibss.chandef.chan = chan;
                wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
+               wdev->wext.ibss.chandef.center_freq1 = freq;
                wdev->wext.ibss.channel_fixed = true;
        } else {
                /* cfg80211_ibss_wext_join will pick one if needed */
index af8d84a..626dc3b 100644 (file)
@@ -2421,7 +2421,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
                change = true;
        }
 
-       if (flags && (*flags & NL80211_MNTR_FLAG_ACTIVE) &&
+       if (flags && (*flags & MONITOR_FLAG_ACTIVE) &&
            !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
                return -EOPNOTSUPP;
 
@@ -2483,7 +2483,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                                  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
                                  &flags);
 
-       if (!err && (flags & NL80211_MNTR_FLAG_ACTIVE) &&
+       if (!err && (flags & MONITOR_FLAG_ACTIVE) &&
            !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
                return -EOPNOTSUPP;
 
index 7d604c0..a271c27 100644 (file)
@@ -97,6 +97,10 @@ int ieee80211_radiotap_iterator_init(
        struct ieee80211_radiotap_header *radiotap_header,
        int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
 {
+       /* check the radiotap header can actually be present */
+       if (max_length < sizeof(struct ieee80211_radiotap_header))
+               return -EINVAL;
+
        /* Linux only supports version 0 radiotap format */
        if (radiotap_header->it_version)
                return -EINVAL;
@@ -131,7 +135,8 @@ int ieee80211_radiotap_iterator_init(
                         */
 
                        if ((unsigned long)iterator->_arg -
-                           (unsigned long)iterator->_rtheader >
+                           (unsigned long)iterator->_rtheader +
+                           sizeof(uint32_t) >
                            (unsigned long)iterator->_max_length)
                                return -EINVAL;
                }
index ed38d5d..76e1873 100644 (file)
@@ -334,7 +334,8 @@ static void xfrm_policy_kill(struct xfrm_policy *policy)
 
        atomic_inc(&policy->genid);
 
-       del_timer(&policy->polq.hold_timer);
+       if (del_timer(&policy->polq.hold_timer))
+               xfrm_pol_put(policy);
        xfrm_queue_purge(&policy->polq.hold_queue);
 
        if (del_timer(&policy->timer))
@@ -589,7 +590,8 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
 
        spin_lock_bh(&pq->hold_queue.lock);
        skb_queue_splice_init(&pq->hold_queue, &list);
-       del_timer(&pq->hold_timer);
+       if (del_timer(&pq->hold_timer))
+               xfrm_pol_put(old);
        spin_unlock_bh(&pq->hold_queue.lock);
 
        if (skb_queue_empty(&list))
@@ -600,7 +602,8 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
        spin_lock_bh(&pq->hold_queue.lock);
        skb_queue_splice(&list, &pq->hold_queue);
        pq->timeout = XFRM_QUEUE_TMO_MIN;
-       mod_timer(&pq->hold_timer, jiffies);
+       if (!mod_timer(&pq->hold_timer, jiffies))
+               xfrm_pol_hold(new);
        spin_unlock_bh(&pq->hold_queue.lock);
 }
 
@@ -1769,6 +1772,10 @@ static void xfrm_policy_queue_process(unsigned long arg)
 
        spin_lock(&pq->hold_queue.lock);
        skb = skb_peek(&pq->hold_queue);
+       if (!skb) {
+               spin_unlock(&pq->hold_queue.lock);
+               goto out;
+       }
        dst = skb_dst(skb);
        sk = skb->sk;
        xfrm_decode_session(skb, &fl, dst->ops->family);
@@ -1787,8 +1794,9 @@ static void xfrm_policy_queue_process(unsigned long arg)
                        goto purge_queue;
 
                pq->timeout = pq->timeout << 1;
-               mod_timer(&pq->hold_timer, jiffies + pq->timeout);
-               return;
+               if (!mod_timer(&pq->hold_timer, jiffies + pq->timeout))
+                       xfrm_pol_hold(pol);
+       goto out;
        }
 
        dst_release(dst);
@@ -1819,11 +1827,14 @@ static void xfrm_policy_queue_process(unsigned long arg)
                err = dst_output(skb);
        }
 
+out:
+       xfrm_pol_put(pol);
        return;
 
 purge_queue:
        pq->timeout = 0;
        xfrm_queue_purge(&pq->hold_queue);
+       xfrm_pol_put(pol);
 }
 
 static int xdst_queue_output(struct sk_buff *skb)
@@ -1831,7 +1842,8 @@ static int xdst_queue_output(struct sk_buff *skb)
        unsigned long sched_next;
        struct dst_entry *dst = skb_dst(skb);
        struct xfrm_dst *xdst = (struct xfrm_dst *) dst;
-       struct xfrm_policy_queue *pq = &xdst->pols[0]->polq;
+       struct xfrm_policy *pol = xdst->pols[0];
+       struct xfrm_policy_queue *pq = &pol->polq;
 
        if (pq->hold_queue.qlen > XFRM_MAX_QUEUE_LEN) {
                kfree_skb(skb);
@@ -1850,10 +1862,12 @@ static int xdst_queue_output(struct sk_buff *skb)
        if (del_timer(&pq->hold_timer)) {
                if (time_before(pq->hold_timer.expires, sched_next))
                        sched_next = pq->hold_timer.expires;
+               xfrm_pol_put(pol);
        }
 
        __skb_queue_tail(&pq->hold_queue, skb);
-       mod_timer(&pq->hold_timer, sched_next);
+       if (!mod_timer(&pq->hold_timer, sched_next))
+               xfrm_pol_hold(pol);
 
        spin_unlock_bh(&pq->hold_queue.lock);
 
index 8dafe6d..dab57da 100644 (file)
@@ -61,9 +61,9 @@ static void xfrm_replay_notify(struct xfrm_state *x, int event)
 
        switch (event) {
        case XFRM_REPLAY_UPDATE:
-               if (x->replay_maxdiff &&
-                   (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
-                   (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
+               if (!x->replay_maxdiff ||
+                   ((x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
+                   (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff))) {
                        if (x->xflags & XFRM_TIME_DEFER)
                                event = XFRM_REPLAY_TIMEOUT;
                        else
@@ -129,8 +129,7 @@ static int xfrm_replay_check(struct xfrm_state *x,
                return 0;
 
        diff = x->replay.seq - seq;
-       if (diff >= min_t(unsigned int, x->props.replay_window,
-                         sizeof(x->replay.bitmap) * 8)) {
+       if (diff >= x->props.replay_window) {
                x->stats.replay_window++;
                goto err;
        }
@@ -302,9 +301,10 @@ static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
 
        switch (event) {
        case XFRM_REPLAY_UPDATE:
-               if (x->replay_maxdiff &&
-                   (replay_esn->seq - preplay_esn->seq < x->replay_maxdiff) &&
-                   (replay_esn->oseq - preplay_esn->oseq < x->replay_maxdiff)) {
+               if (!x->replay_maxdiff ||
+                   ((replay_esn->seq - preplay_esn->seq < x->replay_maxdiff) &&
+                   (replay_esn->oseq - preplay_esn->oseq
+                    < x->replay_maxdiff))) {
                        if (x->xflags & XFRM_TIME_DEFER)
                                event = XFRM_REPLAY_TIMEOUT;
                        else
@@ -353,28 +353,30 @@ static void xfrm_replay_notify_esn(struct xfrm_state *x, int event)
 
        switch (event) {
        case XFRM_REPLAY_UPDATE:
-               if (!x->replay_maxdiff)
-                       break;
-
-               if (replay_esn->seq_hi == preplay_esn->seq_hi)
-                       seq_diff = replay_esn->seq - preplay_esn->seq;
-               else
-                       seq_diff = ~preplay_esn->seq + replay_esn->seq + 1;
-
-               if (replay_esn->oseq_hi == preplay_esn->oseq_hi)
-                       oseq_diff = replay_esn->oseq - preplay_esn->oseq;
-               else
-                       oseq_diff = ~preplay_esn->oseq + replay_esn->oseq + 1;
-
-               if (seq_diff < x->replay_maxdiff &&
-                   oseq_diff < x->replay_maxdiff) {
+               if (x->replay_maxdiff) {
+                       if (replay_esn->seq_hi == preplay_esn->seq_hi)
+                               seq_diff = replay_esn->seq - preplay_esn->seq;
+                       else
+                               seq_diff = ~preplay_esn->seq + replay_esn->seq
+                                          + 1;
 
-                       if (x->xflags & XFRM_TIME_DEFER)
-                               event = XFRM_REPLAY_TIMEOUT;
+                       if (replay_esn->oseq_hi == preplay_esn->oseq_hi)
+                               oseq_diff = replay_esn->oseq
+                                           - preplay_esn->oseq;
                        else
-                               return;
+                               oseq_diff = ~preplay_esn->oseq
+                                           + replay_esn->oseq + 1;
+
+                       if (seq_diff >= x->replay_maxdiff ||
+                           oseq_diff >= x->replay_maxdiff)
+                               break;
                }
 
+               if (x->xflags & XFRM_TIME_DEFER)
+                       event = XFRM_REPLAY_TIMEOUT;
+               else
+                       return;
+
                break;
 
        case XFRM_REPLAY_TIMEOUT:
index 3f565e4..f964d4c 100644 (file)
@@ -446,7 +446,8 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *
        memcpy(&x->sel, &p->sel, sizeof(x->sel));
        memcpy(&x->lft, &p->lft, sizeof(x->lft));
        x->props.mode = p->mode;
-       x->props.replay_window = p->replay_window;
+       x->props.replay_window = min_t(unsigned int, p->replay_window,
+                                       sizeof(x->replay.bitmap) * 8);
        x->props.reqid = p->reqid;
        x->props.family = p->family;
        memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr));
@@ -1856,7 +1857,7 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
        if (x->km.state != XFRM_STATE_VALID)
                goto out;
 
-       err = xfrm_replay_verify_len(x->replay_esn, rp);
+       err = xfrm_replay_verify_len(x->replay_esn, re);
        if (err)
                goto out;
 
index 487ac6f..9a11f9f 100644 (file)
@@ -55,6 +55,7 @@ static struct sym_entry *table;
 static unsigned int table_size, table_cnt;
 static int all_symbols = 0;
 static char symbol_prefix_char = '\0';
+static unsigned long long kernel_start_addr = 0;
 
 int token_profit[0x10000];
 
@@ -65,7 +66,10 @@ unsigned char best_table_len[256];
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
+       fprintf(stderr, "Usage: kallsyms [--all-symbols] "
+                       "[--symbol-prefix=<prefix char>] "
+                       "[--page-offset=<CONFIG_PAGE_OFFSET>] "
+                       "< in.map > out.S\n");
        exit(1);
 }
 
@@ -194,6 +198,9 @@ static int symbol_valid(struct sym_entry *s)
        int i;
        int offset = 1;
 
+       if (s->addr < kernel_start_addr)
+               return 0;
+
        /* skip prefix char */
        if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char)
                offset++;
@@ -646,6 +653,9 @@ int main(int argc, char **argv)
                                if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
                                        p++;
                                symbol_prefix_char = *p;
+                       } else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
+                               const char *p = &argv[i][14];
+                               kernel_start_addr = strtoull(p, NULL, 16);
                        } else
                                usage();
                }
index 0149949..32b10f5 100644 (file)
@@ -82,6 +82,8 @@ kallsyms()
                kallsymopt="${kallsymopt} --all-symbols"
        fi
 
+       kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
+
        local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL}               \
                      ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
 
index 95c2b26..7db9954 100644 (file)
@@ -580,15 +580,13 @@ static struct aa_namespace *__next_namespace(struct aa_namespace *root,
 
        /* check if the next ns is a sibling, parent, gp, .. */
        parent = ns->parent;
-       while (parent) {
+       while (ns != root) {
                mutex_unlock(&ns->lock);
                next = list_entry_next(ns, base.list);
                if (!list_entry_is_head(next, &parent->sub_ns, base.list)) {
                        mutex_lock(&next->lock);
                        return next;
                }
-               if (parent == root)
-                       return NULL;
                ns = parent;
                parent = parent->parent;
        }
index d6222ba..532471d 100644 (file)
  * it should be.
  */
 
-#include <linux/crypto.h>
+#include <crypto/hash.h>
 
 #include "include/apparmor.h"
 #include "include/crypto.h"
 
 static unsigned int apparmor_hash_size;
 
-static struct crypto_hash *apparmor_tfm;
+static struct crypto_shash *apparmor_tfm;
 
 unsigned int aa_hash_size(void)
 {
@@ -32,35 +32,33 @@ unsigned int aa_hash_size(void)
 int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
                         size_t len)
 {
-       struct scatterlist sg[2];
-       struct hash_desc desc = {
-               .tfm = apparmor_tfm,
-               .flags = 0
-       };
+       struct {
+               struct shash_desc shash;
+               char ctx[crypto_shash_descsize(apparmor_tfm)];
+       } desc;
        int error = -ENOMEM;
        u32 le32_version = cpu_to_le32(version);
 
        if (!apparmor_tfm)
                return 0;
 
-       sg_init_table(sg, 2);
-       sg_set_buf(&sg[0], &le32_version, 4);
-       sg_set_buf(&sg[1], (u8 *) start, len);
-
        profile->hash = kzalloc(apparmor_hash_size, GFP_KERNEL);
        if (!profile->hash)
                goto fail;
 
-       error = crypto_hash_init(&desc);
+       desc.shash.tfm = apparmor_tfm;
+       desc.shash.flags = 0;
+
+       error = crypto_shash_init(&desc.shash);
        if (error)
                goto fail;
-       error = crypto_hash_update(&desc, &sg[0], 4);
+       error = crypto_shash_update(&desc.shash, (u8 *) &le32_version, 4);
        if (error)
                goto fail;
-       error = crypto_hash_update(&desc, &sg[1], len);
+       error = crypto_shash_update(&desc.shash, (u8 *) start, len);
        if (error)
                goto fail;
-       error = crypto_hash_final(&desc, profile->hash);
+       error = crypto_shash_final(&desc.shash, profile->hash);
        if (error)
                goto fail;
 
@@ -75,19 +73,19 @@ fail:
 
 static int __init init_profile_hash(void)
 {
-       struct crypto_hash *tfm;
+       struct crypto_shash *tfm;
 
        if (!apparmor_initialized)
                return 0;
 
-       tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+       tfm = crypto_alloc_shash("sha1", 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(tfm)) {
                int error = PTR_ERR(tfm);
                AA_ERROR("failed to setup profile sha1 hashing: %d\n", error);
                return error;
        }
        apparmor_tfm = tfm;
-       apparmor_hash_size = crypto_hash_digestsize(apparmor_tfm);
+       apparmor_hash_size = crypto_shash_digestsize(apparmor_tfm);
 
        aa_info_message("AppArmor sha1 policy hashing enabled");
 
index f2d4b63..c28b0f2 100644 (file)
@@ -360,7 +360,9 @@ static inline void aa_put_replacedby(struct aa_replacedby *p)
 static inline void __aa_update_replacedby(struct aa_profile *orig,
                                          struct aa_profile *new)
 {
-       struct aa_profile *tmp = rcu_dereference(orig->replacedby->profile);
+       struct aa_profile *tmp;
+       tmp = rcu_dereference_protected(orig->replacedby->profile,
+                                       mutex_is_locked(&orig->ns->lock));
        rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new));
        orig->flags |= PFLAG_INVALID;
        aa_put_profile(tmp);
index 6172509..705c287 100644 (file)
@@ -563,7 +563,8 @@ void __init aa_free_root_ns(void)
 static void free_replacedby(struct aa_replacedby *r)
 {
        if (r) {
-               aa_put_profile(rcu_dereference(r->profile));
+               /* r->profile will not be updated any more as r is dead */
+               aa_put_profile(rcu_dereference_protected(r->profile, true));
                kzfree(r);
        }
 }
@@ -609,6 +610,7 @@ void aa_free_profile(struct aa_profile *profile)
        aa_put_dfa(profile->policy.dfa);
        aa_put_replacedby(profile->replacedby);
 
+       kzfree(profile->hash);
        kzfree(profile);
 }
 
index dad36a6..fc3e662 100644 (file)
@@ -746,7 +746,6 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
  * @tclass: target security class
  * @requested: requested permissions, interpreted based on @tclass
  * @auditdata: auxiliary audit data
- * @flags: VFS walk flags
  *
  * Check the AVC to determine whether the @requested permissions are granted
  * for the SID pair (@ssid, @tsid), interpreting the permissions
@@ -756,17 +755,15 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
  * permissions are granted, -%EACCES if any permissions are denied, or
  * another -errno upon other errors.
  */
-int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass,
-                      u32 requested, struct common_audit_data *auditdata,
-                      unsigned flags)
+int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
+                u32 requested, struct common_audit_data *auditdata)
 {
        struct av_decision avd;
        int rc, rc2;
 
        rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
 
-       rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata,
-                       flags);
+       rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
        if (rc2)
                return rc2;
        return rc;
index a5091ec..5b52310 100644 (file)
@@ -1502,7 +1502,7 @@ static int cred_has_capability(const struct cred *cred,
 
        rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
        if (audit == SECURITY_CAP_AUDIT) {
-               int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
+               int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
                if (rc2)
                        return rc2;
        }
@@ -1525,8 +1525,7 @@ static int task_has_system(struct task_struct *tsk,
 static int inode_has_perm(const struct cred *cred,
                          struct inode *inode,
                          u32 perms,
-                         struct common_audit_data *adp,
-                         unsigned flags)
+                         struct common_audit_data *adp)
 {
        struct inode_security_struct *isec;
        u32 sid;
@@ -1539,7 +1538,7 @@ static int inode_has_perm(const struct cred *cred,
        sid = cred_sid(cred);
        isec = inode->i_security;
 
-       return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
+       return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
@@ -1554,7 +1553,7 @@ static inline int dentry_has_perm(const struct cred *cred,
 
        ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.u.dentry = dentry;
-       return inode_has_perm(cred, inode, av, &ad, 0);
+       return inode_has_perm(cred, inode, av, &ad);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
@@ -1569,7 +1568,7 @@ static inline int path_has_perm(const struct cred *cred,
 
        ad.type = LSM_AUDIT_DATA_PATH;
        ad.u.path = *path;
-       return inode_has_perm(cred, inode, av, &ad, 0);
+       return inode_has_perm(cred, inode, av, &ad);
 }
 
 /* Same as path_has_perm, but uses the inode from the file struct. */
@@ -1581,7 +1580,7 @@ static inline int file_path_has_perm(const struct cred *cred,
 
        ad.type = LSM_AUDIT_DATA_PATH;
        ad.u.path = file->f_path;
-       return inode_has_perm(cred, file_inode(file), av, &ad, 0);
+       return inode_has_perm(cred, file_inode(file), av, &ad);
 }
 
 /* Check whether a task can use an open file descriptor to
@@ -1617,7 +1616,7 @@ static int file_has_perm(const struct cred *cred,
        /* av is zero if only checking access to the descriptor. */
        rc = 0;
        if (av)
-               rc = inode_has_perm(cred, inode, av, &ad, 0);
+               rc = inode_has_perm(cred, inode, av, &ad);
 
 out:
        return rc;
index 92d0ab5..f53ee3c 100644 (file)
@@ -130,7 +130,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
                            u16 tclass, u32 requested,
                            struct av_decision *avd,
                            int result,
-                           struct common_audit_data *a, unsigned flags)
+                           struct common_audit_data *a)
 {
        u32 audited, denied;
        audited = avc_audit_required(requested, avd, result, 0, &denied);
@@ -138,7 +138,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
                return 0;
        return slow_avc_audit(ssid, tsid, tclass,
                              requested, audited, denied,
-                             a, flags);
+                             a, 0);
 }
 
 #define AVC_STRICT 1 /* Ignore permissive mode. */
@@ -147,17 +147,9 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
                         unsigned flags,
                         struct av_decision *avd);
 
-int avc_has_perm_flags(u32 ssid, u32 tsid,
-                      u16 tclass, u32 requested,
-                      struct common_audit_data *auditdata,
-                      unsigned);
-
-static inline int avc_has_perm(u32 ssid, u32 tsid,
-                              u16 tclass, u32 requested,
-                              struct common_audit_data *auditdata)
-{
-       return avc_has_perm_flags(ssid, tsid, tclass, requested, auditdata, 0);
-}
+int avc_has_perm(u32 ssid, u32 tsid,
+                u16 tclass, u32 requested,
+                struct common_audit_data *auditdata);
 
 u32 avc_policy_seqno(void);
 
index 17f45e8..e1e9e0c 100644 (file)
@@ -49,6 +49,8 @@ static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
        struct snd_pcm *pcm;
 
        list_for_each_entry(pcm, &snd_pcm_devices, list) {
+               if (pcm->internal)
+                       continue;
                if (pcm->card == card && pcm->device == device)
                        return pcm;
        }
@@ -60,6 +62,8 @@ static int snd_pcm_next(struct snd_card *card, int device)
        struct snd_pcm *pcm;
 
        list_for_each_entry(pcm, &snd_pcm_devices, list) {
+               if (pcm->internal)
+                       continue;
                if (pcm->card == card && pcm->device > device)
                        return pcm->device;
                else if (pcm->card->number > card->number)
index 445ca48..bf578ba 100644 (file)
@@ -175,6 +175,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
 { 0x54524106, 0xffffffff, "TR28026",           NULL,           NULL },
 { 0x54524108, 0xffffffff, "TR28028",           patch_tritech_tr28028,  NULL }, // added by xin jin [07/09/99]
 { 0x54524123, 0xffffffff, "TR28602",           NULL,           NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
+{ 0x54584e03, 0xffffffff, "TLV320AIC27",       NULL,           NULL },
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",       NULL,           NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",          NULL,           NULL }, // modified ICE1232 with S/PDIF
 { 0x56494170, 0xffffffff, "VIA1617A",          patch_vt1617a,  NULL }, // modified VT1616 with S/PDIF
index 5b6c4e3..748c6a9 100644 (file)
@@ -4864,8 +4864,8 @@ static void hda_power_work(struct work_struct *work)
        spin_unlock(&codec->power_lock);
 
        state = hda_call_codec_suspend(codec, true);
-       codec->pm_down_notified = 0;
-       if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) {
+       if (!codec->pm_down_notified &&
+           !bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) {
                codec->pm_down_notified = 1;
                hda_call_pm_notify(bus, false);
        }
index ac41e9c..b7c89df 100644 (file)
@@ -3531,7 +3531,7 @@ static int create_capture_mixers(struct hda_codec *codec)
                if (!multi)
                        err = create_single_cap_vol_ctl(codec, n, vol, sw,
                                                        inv_dmic);
-               else if (!multi_cap_vol)
+               else if (!multi_cap_vol && !inv_dmic)
                        err = create_bind_cap_vol_ctl(codec, n, vol, sw);
                else
                        err = create_multi_cap_vol_ctl(codec);
@@ -4475,9 +4475,11 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
                                            true, &spec->vmaster_mute.sw_kctl);
                if (err < 0)
                        return err;
-               if (spec->vmaster_mute.hook)
+               if (spec->vmaster_mute.hook) {
                        snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute,
                                                 spec->vmaster_mute_enum);
+                       snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
+               }
        }
 
        free_kctls(spec); /* no longer needed */
index 0cbdd87..2aa2f57 100644 (file)
@@ -968,6 +968,15 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
        }
 }
 
+static void ad1884_fixup_thinkpad(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       struct ad198x_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->gen.keep_eapd_on = 1;
+}
+
 /* set magic COEFs for dmic */
 static const struct hda_verb ad1884_dmic_init_verbs[] = {
        {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
@@ -979,6 +988,7 @@ enum {
        AD1884_FIXUP_AMP_OVERRIDE,
        AD1884_FIXUP_HP_EAPD,
        AD1884_FIXUP_DMIC_COEF,
+       AD1884_FIXUP_THINKPAD,
        AD1884_FIXUP_HP_TOUCHSMART,
 };
 
@@ -997,6 +1007,12 @@ static const struct hda_fixup ad1884_fixups[] = {
                .type = HDA_FIXUP_VERBS,
                .v.verbs = ad1884_dmic_init_verbs,
        },
+       [AD1884_FIXUP_THINKPAD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad1884_fixup_thinkpad,
+               .chained = true,
+               .chain_id = AD1884_FIXUP_DMIC_COEF,
+       },
        [AD1884_FIXUP_HP_TOUCHSMART] = {
                .type = HDA_FIXUP_VERBS,
                .v.verbs = ad1884_dmic_init_verbs,
@@ -1008,7 +1024,7 @@ static const struct hda_fixup ad1884_fixups[] = {
 static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
        SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_DMIC_COEF),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
        {}
 };
 
index 4edd2d0..ec68eae 100644 (file)
@@ -3231,6 +3231,7 @@ enum {
        CXT_FIXUP_INC_MIC_BOOST,
        CXT_FIXUP_HEADPHONE_MIC_PIN,
        CXT_FIXUP_HEADPHONE_MIC,
+       CXT_FIXUP_GPIO1,
 };
 
 static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
@@ -3375,6 +3376,15 @@ static const struct hda_fixup cxt_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cxt_fixup_headphone_mic,
        },
+       [CXT_FIXUP_GPIO1] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
+                       { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
+                       { 0x01, AC_VERB_SET_GPIO_DATA, 0x01 },
+                       { }
+               },
+       },
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -3384,6 +3394,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
 
 static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1),
        SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
index 7ea0245..50173d4 100644 (file)
@@ -936,6 +936,14 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
                return;
        }
 
+       /*
+        * always configure channel mapping, it may have been changed by the
+        * user in the meantime
+        */
+       hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
+                                  channels, per_pin->chmap,
+                                  per_pin->chmap_set);
+
        /*
         * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
         * sizeof(*dp_ai) to avoid partial match/update problems when
@@ -947,20 +955,10 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
                            "pin=%d channels=%d\n",
                            pin_nid,
                            channels);
-               hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
-                                          channels, per_pin->chmap,
-                                          per_pin->chmap_set);
                hdmi_stop_infoframe_trans(codec, pin_nid);
                hdmi_fill_audio_infoframe(codec, pin_nid,
                                            ai.bytes, sizeof(ai));
                hdmi_start_infoframe_trans(codec, pin_nid);
-       } else {
-               /* For non-pcm audio switch, setup new channel mapping
-                * accordingly */
-               if (per_pin->non_pcm != non_pcm)
-                       hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
-                                                  channels, per_pin->chmap,
-                                                  per_pin->chmap_set);
        }
 
        per_pin->non_pcm = non_pcm;
index 0e303b9..8ad5543 100644 (file)
@@ -2819,6 +2819,15 @@ static void alc269_fixup_hweq(struct hda_codec *codec,
        alc_write_coef_idx(codec, 0x1e, coef | 0x80);
 }
 
+static void alc269_fixup_headset_mic(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+}
+
 static void alc271_fixup_dmic(struct hda_codec *codec,
                              const struct hda_fixup *fix, int action)
 {
@@ -3496,6 +3505,15 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
        }
 }
 
+static void alc290_fixup_mono_speakers(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               /* Remove DAC node 0x03, as it seems to be
+                  giving mono output */
+               snd_hda_override_wcaps(codec, 0x03, 0);
+}
+
 enum {
        ALC269_FIXUP_SONY_VAIO,
        ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -3507,6 +3525,7 @@ enum {
        ALC271_FIXUP_DMIC,
        ALC269_FIXUP_PCM_44K,
        ALC269_FIXUP_STEREO_DMIC,
+       ALC269_FIXUP_HEADSET_MIC,
        ALC269_FIXUP_QUANTA_MUTE,
        ALC269_FIXUP_LIFEBOOK,
        ALC269_FIXUP_AMIC,
@@ -3519,9 +3538,11 @@ enum {
        ALC269_FIXUP_HP_GPIO_LED,
        ALC269_FIXUP_INV_DMIC,
        ALC269_FIXUP_LENOVO_DOCK,
+       ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
        ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
        ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
        ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+       ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
        ALC269_FIXUP_HEADSET_MODE,
        ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
        ALC269_FIXUP_ASUS_X101_FUNC,
@@ -3535,6 +3556,7 @@ enum {
        ALC283_FIXUP_CHROME_BOOK,
        ALC282_FIXUP_ASUS_TX300,
        ALC283_FIXUP_INT_MIC,
+       ALC290_FIXUP_MONO_SPEAKERS,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -3603,6 +3625,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_stereo_dmic,
        },
+       [ALC269_FIXUP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_headset_mic,
+       },
        [ALC269_FIXUP_QUANTA_MUTE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_quanta_mute,
@@ -3712,6 +3738,15 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
        },
+       [ALC269_FIXUP_DELL3_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
        [ALC269_FIXUP_HEADSET_MODE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode,
@@ -3720,6 +3755,15 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode_no_hp_mic,
        },
+       [ALC286_FIXUP_SONY_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
        [ALC269_FIXUP_ASUS_X101_FUNC] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_x101_headset_mic,
@@ -3804,6 +3848,12 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
        },
+       [ALC290_FIXUP_MONO_SPEAKERS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc290_fixup_mono_speakers,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -3845,6 +3895,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_MONO_SPEAKERS),
        SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -3867,6 +3918,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101),
+       SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
        SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
        SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
@@ -3952,6 +4004,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"},
        {.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"},
        {.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
+       {.id = ALC269_FIXUP_HEADSET_MIC, .name = "headset-mic"},
        {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
        {.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
        {.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
@@ -4569,6 +4622,8 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
+       SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_ASUS_MODE4),
+       SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_ASUS_MODE4),
        SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
        SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
index 4f255df..f59a321 100644 (file)
@@ -4845,6 +4845,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                        if ((err = hdsp_get_iobox_version(hdsp)) < 0)
                                return err;
                }
+               memset(&hdsp_version, 0, sizeof(hdsp_version));
                hdsp_version.io_type = hdsp->io_type;
                hdsp_version.firmware_rev = hdsp->firmware_rev;
                if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version))))
index c02405c..5810a06 100644 (file)
@@ -88,6 +88,7 @@ static int bfin_i2s_hw_params(struct snd_pcm_substream *substream,
        case SNDRV_PCM_FORMAT_S8:
                param.spctl |= 0x70;
                sport->wdsize = 1;
+               break;
        case SNDRV_PCM_FORMAT_S16_LE:
                param.spctl |= 0xf0;
                sport->wdsize = 2;
index 8af0434..259d1ac 100644 (file)
@@ -349,6 +349,9 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
        val = ucontrol->value.integer.value[0];
        val2 = ucontrol->value.integer.value[1];
 
+       if (val >= ARRAY_SIZE(st_table) || val2 >= ARRAY_SIZE(st_table))
+               return -EINVAL;
+
        err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
        if (err < 0)
                return err;
index b8ba0ad..80555d7 100644 (file)
@@ -1225,13 +1225,18 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
        struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
        struct device *dev = codec->dev;
        bool apply_fir, apply_iir;
-       int req, status;
+       unsigned int req;
+       int status;
 
        dev_dbg(dev, "%s: Enter.\n", __func__);
 
        mutex_lock(&drvdata->anc_lock);
 
        req = ucontrol->value.integer.value[0];
+       if (req >= ARRAY_SIZE(enum_anc_state)) {
+               status = -EINVAL;
+               goto cleanup;
+       }
        if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR &&
                req != ANC_APPLY_IIR) {
                dev_err(dev, "%s: ERROR: Unsupported status to set '%s'!\n",
index 41cdd16..8dbcacd 100644 (file)
@@ -1863,7 +1863,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
        struct max98095_pdata *pdata = max98095->pdata;
        int channel = max98095_get_eq_channel(kcontrol->id.name);
        struct max98095_cdata *cdata;
-       int sel = ucontrol->value.integer.value[0];
+       unsigned int sel = ucontrol->value.integer.value[0];
        struct max98095_eq_cfg *coef_set;
        int fs, best, best_val, i;
        int regmask, regsave;
@@ -2016,7 +2016,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
        struct max98095_pdata *pdata = max98095->pdata;
        int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
        struct max98095_cdata *cdata;
-       int sel = ucontrol->value.integer.value[0];
+       unsigned int sel = ucontrol->value.integer.value[0];
        struct max98095_biquad_cfg *coef_set;
        int fs, best, best_val, i;
        int regmask, regsave;
index 651ce09..c91eba5 100644 (file)
@@ -270,7 +270,7 @@ MODULE_DEVICE_TABLE(of, pcm1681_dt_ids);
 static const struct regmap_config pcm1681_regmap = {
        .reg_bits               = 8,
        .val_bits               = 8,
-       .max_register           = ARRAY_SIZE(pcm1681_reg_defaults) + 1,
+       .max_register           = 0x13,
        .reg_defaults           = pcm1681_reg_defaults,
        .num_reg_defaults       = ARRAY_SIZE(pcm1681_reg_defaults),
        .writeable_reg          = pcm1681_writeable_reg,
index 2a8eccf..7613181 100644 (file)
@@ -188,7 +188,7 @@ MODULE_DEVICE_TABLE(of, pcm1792a_of_match);
 static const struct regmap_config pcm1792a_regmap = {
        .reg_bits               = 8,
        .val_bits               = 8,
-       .max_register           = 24,
+       .max_register           = 23,
        .reg_defaults           = pcm1792a_reg_defaults,
        .num_reg_defaults       = ARRAY_SIZE(pcm1792a_reg_defaults),
        .writeable_reg          = pcm1792a_writeable_reg,
index 6e3f269..64ad84d 100644 (file)
@@ -674,6 +674,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        /* Left Input */
        {"Left Line1L Mux", "single-ended", "LINE1L"},
        {"Left Line1L Mux", "differential", "LINE1L"},
+       {"Left Line1R Mux", "single-ended", "LINE1R"},
+       {"Left Line1R Mux", "differential", "LINE1R"},
 
        {"Left Line2L Mux", "single-ended", "LINE2L"},
        {"Left Line2L Mux", "differential", "LINE2L"},
@@ -690,6 +692,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        /* Right Input */
        {"Right Line1R Mux", "single-ended", "LINE1R"},
        {"Right Line1R Mux", "differential", "LINE1R"},
+       {"Right Line1L Mux", "single-ended", "LINE1L"},
+       {"Right Line1L Mux", "differential", "LINE1L"},
 
        {"Right Line2R Mux", "single-ended", "LINE2R"},
        {"Right Line2R Mux", "differential", "LINE2R"},
index 8b50e59..01daf65 100644 (file)
@@ -530,6 +530,7 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
                                hubs->hp_startup_mode);
                        break;
                }
+               break;
 
        case SND_SOC_DAPM_PRE_PMD:
                snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
index c6b7439..6b81d0c 100644 (file)
@@ -936,7 +936,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        ssi_private->ssi_phys = res.start;
 
        ssi_private->irq = irq_of_parse_and_map(np, 0);
-       if (ssi_private->irq == NO_IRQ) {
+       if (ssi_private->irq == 0) {
                dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
                return -ENXIO;
        }
index a3d60d4..a2fd732 100644 (file)
@@ -112,7 +112,7 @@ static int imx_mc13783_probe(struct platform_device *pdev)
                return ret;
        }
 
-       if (machine_is_mx31_3ds()) {
+       if (machine_is_mx31_3ds() || machine_is_mx31moboard()) {
                imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
                        IMX_AUDMUX_V2_PTCR_SYN,
                        IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
index 46c5b4f..ca1be1d 100644 (file)
@@ -62,7 +62,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        struct device_node *ssi_np, *codec_np;
        struct platform_device *ssi_pdev;
        struct i2c_client *codec_dev;
-       struct imx_sgtl5000_data *data;
+       struct imx_sgtl5000_data *data = NULL;
        int int_port, ext_port;
        int ret;
 
@@ -128,7 +128,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
                goto fail;
        }
 
-       data->codec_clk = devm_clk_get(&codec_dev->dev, NULL);
+       data->codec_clk = clk_get(&codec_dev->dev, NULL);
        if (IS_ERR(data->codec_clk)) {
                ret = PTR_ERR(data->codec_clk);
                goto fail;
@@ -172,6 +172,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        return 0;
 
 fail:
+       if (data && !IS_ERR(data->codec_clk))
+               clk_put(data->codec_clk);
        if (ssi_np)
                of_node_put(ssi_np);
        if (codec_np)
@@ -185,6 +187,7 @@ static int imx_sgtl5000_remove(struct platform_device *pdev)
        struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
 
        snd_soc_unregister_card(&data->card);
+       clk_put(data->codec_clk);
 
        return 0;
 }
index f58bcd8..57d6941 100644 (file)
@@ -600,19 +600,17 @@ static int imx_ssi_probe(struct platform_device *pdev)
        ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx;
        ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
 
-       ret = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
-       if (ret)
-               goto failed_pcm_fiq;
+       ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
+       ssi->dma_init = imx_pcm_dma_init(pdev);
 
-       ret = imx_pcm_dma_init(pdev);
-       if (ret)
-               goto failed_pcm_dma;
+       if (ssi->fiq_init && ssi->dma_init) {
+               ret = ssi->fiq_init;
+               goto failed_pcm;
+       }
 
        return 0;
 
-failed_pcm_dma:
-       imx_pcm_fiq_exit(pdev);
-failed_pcm_fiq:
+failed_pcm:
        snd_soc_unregister_component(&pdev->dev);
 failed_register:
        release_mem_region(res->start, resource_size(res));
@@ -628,8 +626,11 @@ static int imx_ssi_remove(struct platform_device *pdev)
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct imx_ssi *ssi = platform_get_drvdata(pdev);
 
-       imx_pcm_dma_exit(pdev);
-       imx_pcm_fiq_exit(pdev);
+       if (!ssi->dma_init)
+               imx_pcm_dma_exit(pdev);
+
+       if (!ssi->fiq_init)
+               imx_pcm_fiq_exit(pdev);
 
        snd_soc_unregister_component(&pdev->dev);
 
index fb1616b..560c40f 100644 (file)
@@ -211,6 +211,8 @@ struct imx_ssi {
        struct imx_dma_data filter_data_rx;
        struct imx_pcm_fiq_params fiq_params;
 
+       int fiq_init;
+       int dma_init;
        int enabled;
 };
 
index daa78a0..4a07f71 100644 (file)
@@ -1,6 +1,6 @@
 config SND_OMAP_SOC
        tristate "SoC Audio for the Texas Instruments OMAP chips"
-       depends on (ARCH_OMAP && DMA_OMAP) || (ARCH_ARM && COMPILE_TEST)
+       depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST)
        select SND_DMAENGINE_PCM
 
 config SND_OMAP_SOC_DMIC
@@ -26,7 +26,7 @@ config SND_OMAP_SOC_N810
 
 config SND_OMAP_SOC_RX51
        tristate "SoC Audio support for Nokia RX-51"
-       depends on SND_OMAP_SOC && ARCH_ARM && (MACH_NOKIA_RX51 || COMPILE_TEST)
+       depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST)
        select SND_OMAP_SOC_MCBSP
        select SND_SOC_TLV320AIC3X
        select SND_SOC_TPA6130A2
index 9cc6986..5dd87f4 100644 (file)
@@ -220,8 +220,8 @@ int rsnd_gen_path_exit(struct rsnd_priv *priv,
 void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
                               struct rsnd_mod *mod,
                               enum rsnd_reg reg);
-#define rsnd_is_gen1(s)                ((s)->info->flags & RSND_GEN1)
-#define rsnd_is_gen2(s)                ((s)->info->flags & RSND_GEN2)
+#define rsnd_is_gen1(s)                (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1)
+#define rsnd_is_gen2(s)                (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2)
 
 /*
  *     R-Car ADG
index 4d05613..1a38be0 100644 (file)
@@ -1380,7 +1380,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
                                return -ENODEV;
 
                        list_add(&cpu_dai->dapm.list, &card->dapm_list);
-                       snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);
                }
 
                if (cpu_dai->driver->probe) {
index c17c14c..b2949ae 100644 (file)
@@ -1949,7 +1949,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
                                w->active ? "active" : "inactive");
 
        list_for_each_entry(p, &w->sources, list_sink) {
-               if (p->connected && !p->connected(w, p->sink))
+               if (p->connected && !p->connected(w, p->source))
                        continue;
 
                if (p->connect)
@@ -3495,6 +3495,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
                if (!w) {
                        dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
                                dai->driver->playback.stream_name);
+                       return -ENOMEM;
                }
 
                w->priv = dai;
@@ -3513,6 +3514,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
                if (!w) {
                        dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
                                dai->driver->capture.stream_name);
+                       return -ENOMEM;
                }
 
                w->priv = dai;
index d0323a6..999550b 100644 (file)
@@ -262,7 +262,9 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw,
        }
 
        area->vm_ops = &usb_stream_hwdep_vm_ops;
-       area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+       area->vm_flags |= VM_DONTDUMP;
+       if (!read)
+               area->vm_flags |= VM_DONTEXPAND;
        area->vm_private_data = us122l;
        atomic_inc(&us122l->mmap_count);
 out:
index 63fb521..6234a51 100644 (file)
@@ -299,19 +299,6 @@ static void usX2Y_error_urb_status(struct usX2Ydev *usX2Y,
        usX2Y_clients_stop(usX2Y);
 }
 
-static void usX2Y_error_sequence(struct usX2Ydev *usX2Y,
-                                struct snd_usX2Y_substream *subs, struct urb *urb)
-{
-       snd_printk(KERN_ERR
-"Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n"
-"Most probably some urb of usb-frame %i is still missing.\n"
-"Cause could be too long delays in usb-hcd interrupt handling.\n",
-                  usb_get_current_frame_number(usX2Y->dev),
-                  subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
-                  usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame);
-       usX2Y_clients_stop(usX2Y);
-}
-
 static void i_usX2Y_urb_complete(struct urb *urb)
 {
        struct snd_usX2Y_substream *subs = urb->context;
@@ -328,12 +315,9 @@ static void i_usX2Y_urb_complete(struct urb *urb)
                usX2Y_error_urb_status(usX2Y, subs, urb);
                return;
        }
-       if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
-               subs->completed_urb = urb;
-       else {
-               usX2Y_error_sequence(usX2Y, subs, urb);
-               return;
-       }
+
+       subs->completed_urb = urb;
+
        {
                struct snd_usX2Y_substream *capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE],
                        *playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
index f2a1acd..814d0e8 100644 (file)
@@ -244,13 +244,8 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
                usX2Y_error_urb_status(usX2Y, subs, urb);
                return;
        }
-       if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
-               subs->completed_urb = urb;
-       else {
-               usX2Y_error_sequence(usX2Y, subs, urb);
-               return;
-       }
 
+       subs->completed_urb = urb;
        capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
        capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
        playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
index e297b74..ca0d3d9 100644 (file)
@@ -90,8 +90,20 @@ OPTIONS
        Number of mmap data pages. Must be a power of two.
 
 -g::
+       Enables call-graph (stack chain/backtrace) recording.
+
 --call-graph::
-       Do call-graph (stack chain/backtrace) recording.
+       Setup and enable call-graph (stack chain/backtrace) recording,
+       implies -g.
+
+       Allows specifying "fp" (frame pointer) or "dwarf"
+       (DWARF's CFI - Call Frame Information) as the method to collect
+       the information used to show the call graphs.
+
+       In some systems, where binaries are build with gcc
+       --fomit-frame-pointer, using the "fp" method will produce bogus
+       call graphs, using "dwarf", if available (perf tools linked to
+       the libunwind library) should be used instead.
 
 -q::
 --quiet::
index 58d6598..6a118e7 100644 (file)
@@ -140,20 +140,12 @@ Default is to monitor all CPUS.
 --asm-raw::
        Show raw instruction encoding of assembly instructions.
 
--G [type,min,order]::
+-G::
+       Enables call-graph (stack chain/backtrace) recording.
+
 --call-graph::
-        Display call chains using type, min percent threshold and order.
-       type can be either:
-       - flat: single column, linear exposure of call chains.
-       - graph: use a graph tree, displaying absolute overhead rates.
-       - fractal: like graph, but displays relative rates. Each branch of
-                the tree is considered as a new profiled object.
-
-       order can be either:
-       - callee: callee based call graph.
-       - caller: inverted caller based call graph.
-
-       Default: fractal,0.5,callee.
+       Setup and enable call-graph (stack chain/backtrace) recording,
+       implies -G.
 
 --ignore-callees=<regex>::
         Ignore callees of the function(s) matching the given regex.
index 3a0ff7f..64c043b 100644 (file)
@@ -770,6 +770,7 @@ check: $(OUTPUT)common-cmds.h
 install-bin: all
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
        $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
+       $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
        $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 ifndef NO_LIBPERL
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
index 935d522..fbc2888 100644 (file)
@@ -888,11 +888,18 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
        while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) {
                err = perf_evlist__parse_sample(kvm->evlist, event, &sample);
                if (err) {
+                       perf_evlist__mmap_consume(kvm->evlist, idx);
                        pr_err("Failed to parse sample\n");
                        return -1;
                }
 
                err = perf_session_queue_event(kvm->session, event, &sample, 0);
+               /*
+                * FIXME: Here we can't consume the event, as perf_session_queue_event will
+                *        point to it, and it'll get possibly overwritten by the kernel.
+                */
+               perf_evlist__mmap_consume(kvm->evlist, idx);
+
                if (err) {
                        pr_err("Failed to enqueue sample: %d\n", err);
                        return -1;
index a41ac41..d046514 100644 (file)
@@ -712,21 +712,12 @@ static int get_stack_size(char *str, unsigned long *_size)
 }
 #endif /* LIBUNWIND_SUPPORT */
 
-int record_parse_callchain_opt(const struct option *opt,
-                              const char *arg, int unset)
+int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
 {
-       struct perf_record_opts *opts = opt->value;
        char *tok, *name, *saveptr = NULL;
        char *buf;
        int ret = -1;
 
-       /* --no-call-graph */
-       if (unset)
-               return 0;
-
-       /* We specified default option if none is provided. */
-       BUG_ON(!arg);
-
        /* We need buffer that we know we can write to. */
        buf = malloc(strlen(arg) + 1);
        if (!buf)
@@ -764,13 +755,9 @@ int record_parse_callchain_opt(const struct option *opt,
                                ret = get_stack_size(tok, &size);
                                opts->stack_dump_size = size;
                        }
-
-                       if (!ret)
-                               pr_debug("callchain: stack dump size %d\n",
-                                        opts->stack_dump_size);
 #endif /* LIBUNWIND_SUPPORT */
                } else {
-                       pr_err("callchain: Unknown -g option "
+                       pr_err("callchain: Unknown --call-graph option "
                               "value: %s\n", arg);
                        break;
                }
@@ -778,13 +765,52 @@ int record_parse_callchain_opt(const struct option *opt,
        } while (0);
 
        free(buf);
+       return ret;
+}
+
+static void callchain_debug(struct perf_record_opts *opts)
+{
+       pr_debug("callchain: type %d\n", opts->call_graph);
 
+       if (opts->call_graph == CALLCHAIN_DWARF)
+               pr_debug("callchain: stack dump size %d\n",
+                        opts->stack_dump_size);
+}
+
+int record_parse_callchain_opt(const struct option *opt,
+                              const char *arg,
+                              int unset)
+{
+       struct perf_record_opts *opts = opt->value;
+       int ret;
+
+       /* --no-call-graph */
+       if (unset) {
+               opts->call_graph = CALLCHAIN_NONE;
+               pr_debug("callchain: disabled\n");
+               return 0;
+       }
+
+       ret = record_parse_callchain(arg, opts);
        if (!ret)
-               pr_debug("callchain: type %d\n", opts->call_graph);
+               callchain_debug(opts);
 
        return ret;
 }
 
+int record_callchain_opt(const struct option *opt,
+                        const char *arg __maybe_unused,
+                        int unset __maybe_unused)
+{
+       struct perf_record_opts *opts = opt->value;
+
+       if (opts->call_graph == CALLCHAIN_NONE)
+               opts->call_graph = CALLCHAIN_FP;
+
+       callchain_debug(opts);
+       return 0;
+}
+
 static const char * const record_usage[] = {
        "perf record [<options>] [<command>]",
        "perf record [<options>] -- <command> [<options>]",
@@ -813,12 +839,12 @@ static struct perf_record record = {
        },
 };
 
-#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
+#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
 
 #ifdef LIBUNWIND_SUPPORT
-const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
+const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
 #else
-const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
+const char record_callchain_help[] = CALLCHAIN_HELP "fp";
 #endif
 
 /*
@@ -858,9 +884,12 @@ const struct option record_options[] = {
                     "number of mmap data pages"),
        OPT_BOOLEAN(0, "group", &record.opts.group,
                    "put the counters into a counter group"),
-       OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
-                            "mode[,dump_size]", record_callchain_help,
-                            &record_parse_callchain_opt, "fp"),
+       OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
+                          NULL, "enables call-graph recording" ,
+                          &record_callchain_opt),
+       OPT_CALLBACK(0, "call-graph", &record.opts,
+                    "mode[,dump_size]", record_callchain_help,
+                    &record_parse_callchain_opt),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
        OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
index f686d5f..5098f14 100644 (file)
@@ -457,6 +457,7 @@ static int __run_perf_stat(int argc, const char **argv)
                        perror("failed to prepare workload");
                        return -1;
                }
+               child_pid = evsel_list->workload.pid;
        }
 
        if (group)
index 2122141..5a11f13 100644 (file)
@@ -810,7 +810,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
                ret = perf_evlist__parse_sample(top->evlist, event, &sample);
                if (ret) {
                        pr_err("Can't parse sample, err = %d\n", ret);
-                       continue;
+                       goto next_event;
                }
 
                evsel = perf_evlist__id2evsel(session->evlist, sample.id);
@@ -825,13 +825,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
                case PERF_RECORD_MISC_USER:
                        ++top->us_samples;
                        if (top->hide_user_symbols)
-                               continue;
+                               goto next_event;
                        machine = &session->machines.host;
                        break;
                case PERF_RECORD_MISC_KERNEL:
                        ++top->kernel_samples;
                        if (top->hide_kernel_symbols)
-                               continue;
+                               goto next_event;
                        machine = &session->machines.host;
                        break;
                case PERF_RECORD_MISC_GUEST_KERNEL:
@@ -847,7 +847,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
                         */
                        /* Fall thru */
                default:
-                       continue;
+                       goto next_event;
                }
 
 
@@ -859,6 +859,8 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
                        machine__process_event(machine, event);
                } else
                        ++session->stats.nr_unknown_events;
+next_event:
+               perf_evlist__mmap_consume(top->evlist, idx);
        }
 }
 
@@ -1016,16 +1018,16 @@ out_delete:
 }
 
 static int
-parse_callchain_opt(const struct option *opt, const char *arg, int unset)
+callchain_opt(const struct option *opt, const char *arg, int unset)
 {
-       /*
-        * --no-call-graph
-        */
-       if (unset)
-               return 0;
-
        symbol_conf.use_callchain = true;
+       return record_callchain_opt(opt, arg, unset);
+}
 
+static int
+parse_callchain_opt(const struct option *opt, const char *arg, int unset)
+{
+       symbol_conf.use_callchain = true;
        return record_parse_callchain_opt(opt, arg, unset);
 }
 
@@ -1106,9 +1108,12 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                   "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"),
        OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
                    "Show a column with the number of samples"),
-       OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
-                            "mode[,dump_size]", record_callchain_help,
-                            &parse_callchain_opt, "fp"),
+       OPT_CALLBACK_NOOPT('G', NULL, &top.record_opts,
+                          NULL, "enables call-graph recording",
+                          &callchain_opt),
+       OPT_CALLBACK(0, "call-graph", &top.record_opts,
+                    "mode[,dump_size]", record_callchain_help,
+                    &parse_callchain_opt),
        OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
                   "ignore callees of these functions in call graphs",
                   report_parse_ignore_callees_opt),
index 71aa3e3..99c8d9a 100644 (file)
@@ -987,7 +987,7 @@ again:
                        err = perf_evlist__parse_sample(evlist, event, &sample);
                        if (err) {
                                fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
-                               continue;
+                               goto next_event;
                        }
 
                        if (trace->base_time == 0)
@@ -1001,18 +1001,20 @@ again:
                        evsel = perf_evlist__id2evsel(evlist, sample.id);
                        if (evsel == NULL) {
                                fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
-                               continue;
+                               goto next_event;
                        }
 
                        if (sample.raw_data == NULL) {
                                fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
                                       perf_evsel__name(evsel), sample.tid,
                                       sample.cpu, sample.raw_size);
-                               continue;
+                               goto next_event;
                        }
 
                        handler = evsel->handler.func;
                        handler(trace, evsel, &sample);
+next_event:
+                       perf_evlist__mmap_consume(evlist, i);
 
                        if (done)
                                goto out_unmap_evlist;
index d5a8dd4..f793057 100644 (file)
@@ -219,7 +219,7 @@ define SOURCE_LIBAUDIT
 
 int main(void)
 {
-       printf(\"error message: %s\n\", audit_errno_to_name(0));
+       printf(\"error message: %s\", audit_errno_to_name(0));
        return audit_open();
 }
 endef
index 6fb781d..e3fedfa 100644 (file)
@@ -290,6 +290,7 @@ static int process_events(struct machine *machine, struct perf_evlist *evlist,
        for (i = 0; i < evlist->nr_mmaps; i++) {
                while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
                        ret = process_event(machine, evlist, event, state);
+                       perf_evlist__mmap_consume(evlist, i);
                        if (ret < 0)
                                return ret;
                }
index d444ea2..376c356 100644 (file)
@@ -36,6 +36,7 @@ static int find_comm(struct perf_evlist *evlist, const char *comm)
                            (pid_t)event->comm.tid == getpid() &&
                            strcmp(event->comm.comm, comm) == 0)
                                found += 1;
+                       perf_evlist__mmap_consume(evlist, i);
                }
        }
        return found;
index c4185b9..a7232c2 100644 (file)
@@ -122,6 +122,7 @@ int test__basic_mmap(void)
                        goto out_munmap;
                }
                nr_events[evsel->idx]++;
+               perf_evlist__mmap_consume(evlist, 0);
        }
 
        err = 0;
index fc5b9fc..524b221 100644 (file)
@@ -77,8 +77,10 @@ int test__syscall_open_tp_fields(void)
 
                                ++nr_events;
 
-                               if (type != PERF_RECORD_SAMPLE)
+                               if (type != PERF_RECORD_SAMPLE) {
+                                       perf_evlist__mmap_consume(evlist, i);
                                        continue;
+                               }
 
                                err = perf_evsel__parse_sample(evsel, event, &sample);
                                if (err) {
index b8a7056..7923b06 100644 (file)
@@ -263,6 +263,8 @@ int test__PERF_RECORD(void)
                                                 type);
                                        ++errs;
                                }
+
+                               perf_evlist__mmap_consume(evlist, i);
                        }
                }
 
index 0ab61b1..4ca1b93 100644 (file)
@@ -122,7 +122,7 @@ int test__perf_time_to_tsc(void)
                        if (event->header.type != PERF_RECORD_COMM ||
                            (pid_t)event->comm.pid != getpid() ||
                            (pid_t)event->comm.tid != getpid())
-                               continue;
+                               goto next_event;
 
                        if (strcmp(event->comm.comm, comm1) == 0) {
                                CHECK__(perf_evsel__parse_sample(evsel, event,
@@ -134,6 +134,8 @@ int test__perf_time_to_tsc(void)
                                                                 &sample));
                                comm2_time = sample.time;
                        }
+next_event:
+                       perf_evlist__mmap_consume(evlist, i);
                }
        }
 
index 2e41e2d..6e2b44e 100644 (file)
@@ -78,7 +78,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
                struct perf_sample sample;
 
                if (event->header.type != PERF_RECORD_SAMPLE)
-                       continue;
+                       goto next_event;
 
                err = perf_evlist__parse_sample(evlist, event, &sample);
                if (err < 0) {
@@ -88,6 +88,8 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
 
                total_periods += sample.period;
                nr_samples++;
+next_event:
+               perf_evlist__mmap_consume(evlist, 0);
        }
 
        if ((u64) nr_samples == total_periods) {
index 28fe589..a3e6487 100644 (file)
@@ -96,10 +96,10 @@ int test__task_exit(void)
 
 retry:
        while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
-               if (event->header.type != PERF_RECORD_EXIT)
-                       continue;
+               if (event->header.type == PERF_RECORD_EXIT)
+                       nr_exit++;
 
-               nr_exit++;
+               perf_evlist__mmap_consume(evlist, 0);
        }
 
        if (!exited || !nr_exit) {
index 194e2f4..6c15268 100644 (file)
@@ -315,8 +315,7 @@ static inline void advance_hpp(struct perf_hpp *hpp, int inc)
 }
 
 static int hist_entry__period_snprintf(struct perf_hpp *hpp,
-                                      struct hist_entry *he,
-                                      bool color)
+                                      struct hist_entry *he)
 {
        const char *sep = symbol_conf.field_sep;
        struct perf_hpp_fmt *fmt;
@@ -338,7 +337,7 @@ static int hist_entry__period_snprintf(struct perf_hpp *hpp,
                } else
                        first = false;
 
-               if (color && fmt->color)
+               if (perf_hpp__use_color() && fmt->color)
                        ret = fmt->color(fmt, hpp, he);
                else
                        ret = fmt->entry(fmt, hpp, he);
@@ -358,12 +357,11 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
                .buf            = bf,
                .size           = size,
        };
-       bool color = !symbol_conf.field_sep;
 
        if (size == 0 || size > bfsz)
                size = hpp.size = bfsz;
 
-       ret = hist_entry__period_snprintf(&hpp, he, color);
+       ret = hist_entry__period_snprintf(&hpp, he);
        hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
 
        ret = fprintf(fp, "%s\n", bf);
@@ -482,6 +480,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
 
 print_entries:
        linesz = hists__sort_list_width(hists) + 3 + 1;
+       linesz += perf_hpp__color_overhead();
        line = malloc(linesz);
        if (line == NULL) {
                ret = -1;
index 2b585bc..9e99060 100644 (file)
@@ -147,6 +147,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
 
 struct option;
 
+int record_parse_callchain(const char *arg, struct perf_record_opts *opts);
 int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
+int record_callchain_opt(const struct option *opt, const char *arg, int unset);
+
 extern const char record_callchain_help[];
 #endif /* __PERF_CALLCHAIN_H */
index e23bde1..7defd77 100644 (file)
@@ -426,7 +426,7 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
  * @die_mem: a buffer for result DIE
  *
  * Search a non-inlined function DIE which includes @addr. Stores the
- * DIE to @die_mem and returns it if found. Returns NULl if failed.
+ * DIE to @die_mem and returns it if found. Returns NULL if failed.
  */
 Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
                                    Dwarf_Die *die_mem)
@@ -453,16 +453,33 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
        return DIE_FIND_CB_CONTINUE;
 }
 
+/**
+ * die_find_top_inlinefunc - Search the top inlined function at given address
+ * @sp_die: a subprogram DIE which including @addr
+ * @addr: target address
+ * @die_mem: a buffer for result DIE
+ *
+ * Search an inlined function DIE which includes @addr. Stores the
+ * DIE to @die_mem and returns it if found. Returns NULL if failed.
+ * Even if several inlined functions are expanded recursively, this
+ * doesn't trace it down, and returns the topmost one.
+ */
+Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
+                                  Dwarf_Die *die_mem)
+{
+       return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
+}
+
 /**
  * die_find_inlinefunc - Search an inlined function at given address
- * @cu_die: a CU DIE which including @addr
+ * @sp_die: a subprogram DIE which including @addr
  * @addr: target address
  * @die_mem: a buffer for result DIE
  *
  * Search an inlined function DIE which includes @addr. Stores the
- * DIE to @die_mem and returns it if found. Returns NULl if failed.
+ * DIE to @die_mem and returns it if found. Returns NULL if failed.
  * If several inlined functions are expanded recursively, this trace
- * it and returns deepest one.
+ * it down and returns deepest one.
  */
 Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
                               Dwarf_Die *die_mem)
index 8658d41..b4fe90c 100644 (file)
@@ -79,7 +79,11 @@ extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
 extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
                                    Dwarf_Die *die_mem);
 
-/* Search an inlined function including given address */
+/* Search the top inlined function including given address */
+extern Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
+                                         Dwarf_Die *die_mem);
+
+/* Search the deepest inlined function including given address */
 extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
                                      Dwarf_Die *die_mem);
 
index 9b393e7..49096ea 100644 (file)
@@ -187,7 +187,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                return -1;
        }
 
-       event->header.type = PERF_RECORD_MMAP2;
+       event->header.type = PERF_RECORD_MMAP;
        /*
         * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
         */
@@ -198,7 +198,6 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                char prot[5];
                char execname[PATH_MAX];
                char anonstr[] = "//anon";
-               unsigned int ino;
                size_t size;
                ssize_t n;
 
@@ -209,15 +208,12 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                strcpy(execname, "");
 
                /* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
-               n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
-                      &event->mmap2.start, &event->mmap2.len, prot,
-                      &event->mmap2.pgoff, &event->mmap2.maj,
-                      &event->mmap2.min,
-                      &ino, execname);
-
-               event->mmap2.ino = (u64)ino;
+               n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n",
+                      &event->mmap.start, &event->mmap.len, prot,
+                      &event->mmap.pgoff,
+                      execname);
 
-               if (n != 8)
+               if (n != 5)
                        continue;
 
                if (prot[2] != 'x')
@@ -227,15 +223,15 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                        strcpy(execname, anonstr);
 
                size = strlen(execname) + 1;
-               memcpy(event->mmap2.filename, execname, size);
+               memcpy(event->mmap.filename, execname, size);
                size = PERF_ALIGN(size, sizeof(u64));
-               event->mmap2.len -= event->mmap.start;
-               event->mmap2.header.size = (sizeof(event->mmap2) -
-                                       (sizeof(event->mmap2.filename) - size));
-               memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
-               event->mmap2.header.size += machine->id_hdr_size;
-               event->mmap2.pid = tgid;
-               event->mmap2.tid = pid;
+               event->mmap.len -= event->mmap.start;
+               event->mmap.header.size = (sizeof(event->mmap) -
+                                       (sizeof(event->mmap.filename) - size));
+               memset(event->mmap.filename + size, 0, machine->id_hdr_size);
+               event->mmap.header.size += machine->id_hdr_size;
+               event->mmap.pid = tgid;
+               event->mmap.tid = pid;
 
                if (process(tool, event, &synth_sample, machine) != 0) {
                        rc = -1;
index f9f77be..e584cd3 100644 (file)
@@ -545,12 +545,19 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
 
        md->prev = old;
 
-       if (!evlist->overwrite)
-               perf_mmap__write_tail(md, old);
-
        return event;
 }
 
+void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
+{
+       if (!evlist->overwrite) {
+               struct perf_mmap *md = &evlist->mmap[idx];
+               unsigned int old = md->prev;
+
+               perf_mmap__write_tail(md, old);
+       }
+}
+
 static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
 {
        if (evlist->mmap[idx].base != NULL) {
index 880d713..206d093 100644 (file)
@@ -89,6 +89,8 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id);
 
 union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
 
+void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx);
+
 int perf_evlist__open(struct perf_evlist *evlist);
 void perf_evlist__close(struct perf_evlist *evlist);
 
index 0ce9feb..9f1ef9b 100644 (file)
@@ -678,7 +678,6 @@ void perf_evsel__config(struct perf_evsel *evsel,
                attr->sample_type       |= PERF_SAMPLE_WEIGHT;
 
        attr->mmap  = track;
-       attr->mmap2 = track && !perf_missing_features.mmap2;
        attr->comm  = track;
 
        /*
index ce69901..c3e5a3b 100644 (file)
@@ -2768,6 +2768,18 @@ int perf_session__read_header(struct perf_session *session)
        if (perf_file_header__read(&f_header, header, fd) < 0)
                return -EINVAL;
 
+       /*
+        * Sanity check that perf.data was written cleanly; data size is
+        * initialized to 0 and updated only if the on_exit function is run.
+        * If data size is still 0 then the file contains only partial
+        * information.  Just warn user and process it as much as it can.
+        */
+       if (f_header.data.size == 0) {
+               pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n"
+                          "Was the 'perf record' command properly terminated?\n",
+                          session->filename);
+       }
+
        nr_attrs = f_header.attrs.size / f_header.attr_size;
        lseek(fd, f_header.attrs.offset, SEEK_SET);
 
index 1329b6b..ce8dc61 100644 (file)
@@ -5,6 +5,7 @@
 #include <pthread.h>
 #include "callchain.h"
 #include "header.h"
+#include "color.h"
 
 extern struct callchain_param callchain_param;
 
@@ -175,6 +176,18 @@ void perf_hpp__init(void);
 void perf_hpp__column_register(struct perf_hpp_fmt *format);
 void perf_hpp__column_enable(unsigned col);
 
+static inline size_t perf_hpp__use_color(void)
+{
+       return !symbol_conf.field_sep;
+}
+
+static inline size_t perf_hpp__color_overhead(void)
+{
+       return perf_hpp__use_color() ?
+              (COLOR_MAXLEN + sizeof(PERF_COLOR_RESET)) * PERF_HPP__MAX_INDEX
+              : 0;
+}
+
 struct perf_evlist;
 
 struct hist_browser_timer {
index 371476c..f069273 100644 (file)
@@ -1327,8 +1327,8 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
                                struct perf_probe_point *ppt)
 {
        Dwarf_Die cudie, spdie, indie;
-       Dwarf_Addr _addr, baseaddr;
-       const char *fname = NULL, *func = NULL, *tmp;
+       Dwarf_Addr _addr = 0, baseaddr = 0;
+       const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp;
        int baseline = 0, lineno = 0, ret = 0;
 
        /* Adjust address with bias */
@@ -1349,27 +1349,36 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
        /* Find a corresponding function (name, baseline and baseaddr) */
        if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) {
                /* Get function entry information */
-               tmp = dwarf_diename(&spdie);
-               if (!tmp ||
+               func = basefunc = dwarf_diename(&spdie);
+               if (!func ||
                    dwarf_entrypc(&spdie, &baseaddr) != 0 ||
-                   dwarf_decl_line(&spdie, &baseline) != 0)
+                   dwarf_decl_line(&spdie, &baseline) != 0) {
+                       lineno = 0;
                        goto post;
-               func = tmp;
+               }
 
-               if (addr == (unsigned long)baseaddr)
+               fname = dwarf_decl_file(&spdie);
+               if (addr == (unsigned long)baseaddr) {
                        /* Function entry - Relative line number is 0 */
                        lineno = baseline;
-               else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
-                                            &indie)) {
+                       goto post;
+               }
+
+               /* Track down the inline functions step by step */
+               while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr,
+                                               &indie)) {
+                       /* There is an inline function */
                        if (dwarf_entrypc(&indie, &_addr) == 0 &&
-                           _addr == addr)
+                           _addr == addr) {
                                /*
                                 * addr is at an inline function entry.
                                 * In this case, lineno should be the call-site
-                                * line number.
+                                * line number. (overwrite lineinfo)
                                 */
                                lineno = die_get_call_lineno(&indie);
-                       else {
+                               fname = die_get_call_file(&indie);
+                               break;
+                       } else {
                                /*
                                 * addr is in an inline function body.
                                 * Since lineno points one of the lines
@@ -1377,19 +1386,27 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
                                 * be the entry line of the inline function.
                                 */
                                tmp = dwarf_diename(&indie);
-                               if (tmp &&
-                                   dwarf_decl_line(&spdie, &baseline) == 0)
-                                       func = tmp;
+                               if (!tmp ||
+                                   dwarf_decl_line(&indie, &baseline) != 0)
+                                       break;
+                               func = tmp;
+                               spdie = indie;
                        }
                }
+               /* Verify the lineno and baseline are in a same file */
+               tmp = dwarf_decl_file(&spdie);
+               if (!tmp || strcmp(tmp, fname) != 0)
+                       lineno = 0;
        }
 
 post:
        /* Make a relative line number or an offset */
        if (lineno)
                ppt->line = lineno - baseline;
-       else if (func)
+       else if (basefunc) {
                ppt->offset = addr - (unsigned long)baseaddr;
+               func = basefunc;
+       }
 
        /* Duplicate strings */
        if (func) {
index 71b5412..2ac4bc9 100644 (file)
@@ -822,6 +822,8 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
                PyObject *pyevent = pyrf_event__new(event);
                struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
 
+               perf_evlist__mmap_consume(evlist, cpu);
+
                if (pyevent == NULL)
                        return PyErr_NoMemory();
 
index a85e4ae..c0c9795 100644 (file)
@@ -282,7 +282,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
 
        event = find_cache_event(evsel);
        if (!event)
-               die("ug! no event found for type %" PRIu64, evsel->attr.config);
+               die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config);
 
        pid = raw_field_value(event, "common_pid", data);
 
index cc75a3c..95d91a0 100644 (file)
@@ -56,6 +56,17 @@ static void handler_call_die(const char *handler_name)
        Py_FatalError("problem in Python trace event handler");
 }
 
+/*
+ * Insert val into into the dictionary and decrement the reference counter.
+ * This is necessary for dictionaries since PyDict_SetItemString() does not 
+ * steal a reference, as opposed to PyTuple_SetItem().
+ */
+static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObject *val)
+{
+       PyDict_SetItemString(dict, key, val);
+       Py_DECREF(val);
+}
+
 static void define_value(enum print_arg_type field_type,
                         const char *ev_name,
                         const char *field_name,
@@ -279,11 +290,11 @@ static void python_process_tracepoint(union perf_event *perf_event
                PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
                PyTuple_SetItem(t, n++, PyString_FromString(comm));
        } else {
-               PyDict_SetItemString(dict, "common_cpu", PyInt_FromLong(cpu));
-               PyDict_SetItemString(dict, "common_s", PyInt_FromLong(s));
-               PyDict_SetItemString(dict, "common_ns", PyInt_FromLong(ns));
-               PyDict_SetItemString(dict, "common_pid", PyInt_FromLong(pid));
-               PyDict_SetItemString(dict, "common_comm", PyString_FromString(comm));
+               pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu));
+               pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s));
+               pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns));
+               pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid));
+               pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm));
        }
        for (field = event->format.fields; field; field = field->next) {
                if (field->flags & FIELD_IS_STRING) {
@@ -313,7 +324,7 @@ static void python_process_tracepoint(union perf_event *perf_event
                if (handler)
                        PyTuple_SetItem(t, n++, obj);
                else
-                       PyDict_SetItemString(dict, field->name, obj);
+                       pydict_set_item_string_decref(dict, field->name, obj);
 
        }
        if (!handler)
@@ -370,21 +381,21 @@ static void python_process_general_event(union perf_event *perf_event
        if (!handler || !PyCallable_Check(handler))
                goto exit;
 
-       PyDict_SetItemString(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
-       PyDict_SetItemString(dict, "attr", PyString_FromStringAndSize(
+       pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
+       pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize(
                        (const char *)&evsel->attr, sizeof(evsel->attr)));
-       PyDict_SetItemString(dict, "sample", PyString_FromStringAndSize(
+       pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize(
                        (const char *)sample, sizeof(*sample)));
-       PyDict_SetItemString(dict, "raw_buf", PyString_FromStringAndSize(
+       pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize(
                        (const char *)sample->raw_data, sample->raw_size));
-       PyDict_SetItemString(dict, "comm",
+       pydict_set_item_string_decref(dict, "comm",
                        PyString_FromString(thread->comm));
        if (al->map) {
-               PyDict_SetItemString(dict, "dso",
+               pydict_set_item_string_decref(dict, "dso",
                        PyString_FromString(al->map->dso->name));
        }
        if (al->sym) {
-               PyDict_SetItemString(dict, "symbol",
+               pydict_set_item_string_decref(dict, "symbol",
                        PyString_FromString(al->sym->name));
        }
 
index 70ffa41..568b750 100644 (file)
@@ -256,6 +256,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
                tool->sample = process_event_sample_stub;
        if (tool->mmap == NULL)
                tool->mmap = process_event_stub;
+       if (tool->mmap2 == NULL)
+               tool->mmap2 = process_event_stub;
        if (tool->comm == NULL)
                tool->comm = process_event_stub;
        if (tool->fork == NULL)
@@ -1310,7 +1312,7 @@ int __perf_session__process_events(struct perf_session *session,
        file_offset = page_offset;
        head = data_offset - page_offset;
 
-       if (data_offset + data_size < file_size)
+       if (data_size && (data_offset + data_size < file_size))
                file_size = data_offset + data_size;
 
        progress_next = file_size / 16;
index 4fa655d..41bd855 100644 (file)
@@ -151,7 +151,7 @@ static int check_timer_create(int which)
        fflush(stdout);
 
        done = 0;
-       timer_create(which, NULL, &id);
+       err = timer_create(which, NULL, &id);
        if (err < 0) {
                perror("Can't create timer\n");
                return -1;
index 979bff4..1cf9ccb 100644 (file)
@@ -1064,10 +1064,12 @@ EXPORT_SYMBOL_GPL(gfn_to_hva);
 unsigned long gfn_to_hva_prot(struct kvm *kvm, gfn_t gfn, bool *writable)
 {
        struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
-       if (writable)
+       unsigned long hva = __gfn_to_hva_many(slot, gfn, NULL, false);
+
+       if (!kvm_is_error_hva(hva) && writable)
                *writable = !memslot_is_readonly(slot);
 
-       return __gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL, false);
+       return hva;
 }
 
 static int kvm_read_hva(void *data, void __user *hva, int len)
@@ -3089,7 +3091,7 @@ static const struct file_operations *stat_fops[] = {
 
 static int kvm_init_debug(void)
 {
-       int r = -EFAULT;
+       int r = -EEXIST;
        struct kvm_stats_debugfs_item *p;
 
        kvm_debugfs_dir = debugfs_create_dir("kvm", NULL);